#!/usr/bin/env ruby
require "souls"
begin
  require("./config/souls") unless ARGV[0] == "new" || ARGV[0] == "i" || ARGV[0] == "-v" || ARGV[0] == "deploy"
rescue StandardError
  puts("Make sure you are at SOULs APP directory!")
end
begin
  souls_command = ARGV[0]
  case souls_command
  when "new"
    STRAINS = %w[api worker console admin media].freeze
    app_name = ARGV[1]
    if app_name.nil?
      puts(Paint["you need to specify your app name", :red])
      puts(Paint["`souls new app_name`", :yellow])
      exit
    end
    first_message = Paint % [
      "Select Strain: %{red_text} %{yellow_text} %{green_text} %{blue_text} %{cyan_text}",
      :white,
      {
        red_text: ["\n1. SOULs GraphQL API", :red],
        yellow_text: ["\n2. SOULs Worker", :yellow],
        green_text: ["\n3. SOULs Console Web", :green],
        blue_text: ["\n4. SOULs Admin Web", :blue],
        cyan_text: ["\n5. SOULs Media Web", :cyan]
      }
    ]
    puts(first_message)
    strain = $stdin.gets.chomp.to_i
    case strain
    when 1, 2
      Souls::Init.download_souls(app_name: app_name, repository_name: "souls_#{STRAINS[strain.to_i - 1]}")
      Souls::Init.initial_config_init(app_name: app_name, strain: STRAINS[strain.to_i - 1])
    else
      puts(Paint["Coming Soon...", :blue])
    end
  when "s", "server"
    strain = Souls.configuration.strain
    case strain
    when "media", "admin", "console"
      system("yarn dev")
    when "worker"
      system("bundle exec puma -p 3000 -e development")
    else
      system("foreman start -f Procfile.dev")
    end
  when "c", "console"
    strain = Souls.configuration.strain
    case strain
    when "media", "admin"
      system("yarn dev")
    else
      rack_env = ARGV[1]
      case rack_env
      when "RACK_ENV=production"
        system("RACK_ENV=production bundle exec irb")
      else
        system("bundle exec irb")
      end
    end
  when "i", "infra"
    send_method = ARGV[1]
    Souls.public_send(send_method)
  when "gcloud"
    status = Paint["Running Gcloud Commands...", :yellow]
    Whirly.start(spinner: "clock", interval: 420, stop: "🎉") do
      Whirly.status = status
      send_method = ARGV[1]
      Souls::Gcloud.public_send(send_method)
      Whirly.status = "Done!"
    end
  when "-v", "--version"
    puts(Paint[Souls::VERSION, :white])
  when "gem:update", "gemfile:update"
    status = Paint["Checking for updates...", :yellow]
    Whirly.start(spinner: "clock", interval: 420, stop: "🎉") do
      Whirly.status = status
      Souls.update_gemfile
      Whirly.status = "Done!"
    end
  when "add"
    graphql_class = ARGV[1]
    case graphql_class
    when "mutation"
      Souls::Init.add_mutation(class_name: "user", file_name: "hoi")
    when "type"
      Souls::Init.add_type(class_name: "user", file_name: "hoi")
    when "connection"
      Souls::Init.add_connection(class_name: "user", file_name: "hoi")
    when "edge"
      Souls::Init.add_edge(class_name: "user", file_name: "hoi")
    when "rspec_mutation"
      Souls::Init.add_rspec_mutation(class_name: "user", file_name: "hoi")
    else
      puts(Paint["Wrong Argument!", :red])
    end
  when "g", "generate"
    graphql_class = ARGV[1]
    class_name = ARGV[2]
    case graphql_class
    when "test_dir"
      Souls::Generate.test_dir
    when "model"
      Souls::Generate.model(class_name: class_name)
    when "mutation"
      Souls::Generate.mutation(class_name: class_name)
    when "query"
      Souls::Generate.query(class_name: class_name)
    when "type"
      Souls::Generate.type(class_name: class_name)
    when "edge"
      Souls::Generate.edge(class_name: class_name)
    when "connection"
      Souls::Generate.connection(class_name: class_name)
    when "resolver"
      Souls::Generate.resolver(class_name: class_name)
    when "policy"
      Souls::Generate.policy(class_name: class_name)
    when "rspec_factory"
      Souls::Generate.rspec_factory(class_name: class_name)
    when "rspec_model"
      Souls::Generate.rspec_model(class_name: class_name)
    when "rspec_mutation"
      Souls::Generate.rspec_mutation(class_name: class_name)
    when "rspec_query"
      Souls::Generate.rspec_query(class_name: class_name)
    when "rspec_resolver"
      Souls::Generate.rspec_resolver(class_name: class_name)
    when "rspec_policy"
      Souls::Generate.rspec_policy(class_name: class_name)
    when "node_type"
      Souls::Generate.node_type(class_name: class_name)
    when "job"
      Souls::Generate.job(class_name: class_name)
    when "migrate"
      Souls::Generate.single_migrate(class_name: class_name)
    when "migrate_all"
      Souls::Generate.migrate_all
    when "migration"
      pluralized_class_name = class_name.underscore.pluralize
      system("rake db:create_migration NAME=create_#{pluralized_class_name}")
    when "update"
      Souls::Generate.update_delete(class_name: class_name)
      Souls::Generate.single_migrate(class_name: class_name)
    else
      "SOULs!"
    end
  when "d"
    class_name = ARGV[1]
    Souls::Generate.delete_all(class_name: class_name)
  when "db:create"
    rack_env = ARGV[1]
    case rack_env
    when "RACK_ENV=production"
      system("rake db:create RACK_ENV=production")
    else
      system("rake db:create && rake db:create RACK_ENV=test")
    end
  when "db:migrate"
    rack_env = ARGV[1]
    case rack_env
    when "RACK_ENV=production"
      system("rake db:migrate RACK_ENV=production")
    else
      system("rake db:migrate && rake db:migrate RACK_ENV=test")
    end
  when "db:seed"
    rack_env = ARGV[1]
    case rack_env
    when "RACK_ENV=production"
      system("rake db:seed RACK_ENV=production")
    else
      system("rake db:seed")
    end
  when "db:migrate:reset"
    rack_env = ARGV[1]
    case rack_env
    when "RACK_ENV=production"
      system("rake db:migrate:reset RACK_ENV=production DISABLE_DATABASE_ENVIRONMENT_CHECK=1")
    else
      system("rake db:migrate:reset && rake db:migrate:reset RACK_ENV=test")
    end
  when "db:update"
    strain = Souls.configuration.strain
    case strain
    when "api"
      other_app = Souls.configuration.worker_name
    when "worker"
      other_app = Souls.configuration.api_name
    else
      raise(StandardError, "Unknown app name!")
    end
    system("rm -rf ../#{other_app}/db/*")
    system("cp -r ./db/* ../#{other_app}/db/*")
  when "t", "test"
    system("rubocop -a")
    system("bundle exec rspec")
  when "run"
    system("docker build . -t souls -f Dockerfile.dev")
    system("docker run --rm --env-file .env -p 3000:3000 souls:latest")
  when "deploy"
    project_id = Souls.configuration.project_id
    system("gcloud builds submit --config=cloudbuild.yml --project #{project_id}")
  else
    puts(Paint["Welcome to SOULs!", :green])
  end
rescue StandardError => e
  puts(Paint[e, :red])
end