defmodule Mix.Tasks.Raxol do
  @moduledoc """
  Main entry point for Raxol development tasks.

  This task provides a consolidated interface to all Raxol development tools.

  ## Usage

      mix raxol COMMAND [OPTIONS]

  ## Available Commands

    * `check` - Run all quality checks (compile, format, credo, dialyzer, tests)
    * `test` - Run test suite with various options
    * `dev` - Development tools (debug, profile, analyze)
    * `docs` - Generate and manage documentation
    * `setup` - Initial project setup
    * `clean` - Clean build artifacts

  ## Examples

      # Run all checks
      mix raxol check

      # Run tests
      mix raxol test

      # Run specific check
      mix raxol check.format

      # Get help
      mix raxol help
  """

  use Mix.Task

  @shortdoc "Main Raxol task runner"

  @impl Mix.Task
  def run([]), do: show_help()
  def run(["help" | _]), do: show_help()
  def run(["check" | rest]), do: run_check_tasks(rest)
  def run(["test" | rest]), do: run_test_tasks(rest)
  def run(["dev" | rest]), do: run_dev_tasks(rest)
  def run(["docs" | rest]), do: run_docs_tasks(rest)
  def run(["setup" | rest]), do: run_setup_tasks(rest)
  def run(["clean" | rest]), do: run_clean_tasks(rest)
  def run([unknown | _]), do: handle_unknown_command(unknown)

  @commands ~w(check test dev docs setup clean help)
  @check_subcommands ~w(format compile credo)
  @dev_subcommands ~w(analyze profile debug)

  defp handle_unknown_command(unknown) do
    case find_similar_command(unknown) do
      {similar, score} when score > 0.7 ->
        Mix.shell().error("Unknown command: '#{unknown}'")
        Mix.shell().info("\nDid you mean: mix raxol #{similar}?")
        Mix.shell().info("\nRun 'mix raxol help' for available commands.")

      _ ->
        Mix.shell().error("Unknown command: '#{unknown}'")
        Mix.shell().info("\nAvailable commands: #{Enum.join(@commands, ", ")}")
        Mix.shell().info("\nRun 'mix raxol help' for details.")
    end
  end

  defp find_similar_command(input) do
    @commands
    |> Enum.map(fn cmd -> {cmd, String.jaro_distance(input, cmd)} end)
    |> Enum.max_by(fn {_cmd, score} -> score end)
  end

  defp handle_unknown_subcommand(parent, unknown, valid_subcommands) do
    case find_similar(unknown, valid_subcommands) do
      {similar, score} when score > 0.6 ->
        Mix.shell().error("Unknown #{parent} command: '#{unknown}'")
        Mix.shell().info("\nDid you mean: mix raxol #{parent} #{similar}?")

      _ ->
        Mix.shell().error("Unknown #{parent} command: '#{unknown}'")
        Mix.shell().info("\nAvailable: #{Enum.join(valid_subcommands, ", ")}")
    end
  end

  defp find_similar(input, candidates) do
    candidates
    |> Enum.map(fn cmd -> {cmd, String.jaro_distance(input, cmd)} end)
    |> Enum.max_by(fn {_cmd, score} -> score end)
  end

  defp show_help do
    Mix.shell().info(@moduledoc)
  end

  defp run_check_tasks([]) do
    Mix.shell().info("Running all quality checks...")

    tasks = [
      "compile --warnings-as-errors",
      "format --check-formatted",
      "credo --strict",
      "test"
    ]

    Enum.each(tasks, fn task ->
      Mix.shell().info("Running: mix #{task}")

      try do
        Mix.Task.run(task, [])
        Mix.Task.reenable(task)
      rescue
        e ->
          Mix.shell().error("Task failed: #{task}")
          Mix.shell().error(Exception.message(e))
      end
    end)
  end

  defp run_check_tasks(["format" | _]) do
    Mix.shell().info("Checking code formatting...")
    Mix.Task.run("format", ["--check-formatted"])
  end

  defp run_check_tasks(["compile" | _]) do
    Mix.shell().info("Checking compilation...")
    Mix.Task.run("compile", ["--warnings-as-errors"])
  end

  defp run_check_tasks(["credo" | _]) do
    Mix.shell().info("Running Credo analysis...")
    Mix.Task.run("credo", ["--strict"])
  end

  defp run_check_tasks([unknown | _]) do
    handle_unknown_subcommand("check", unknown, @check_subcommands)
  end

  defp run_test_tasks([]) do
    Mix.shell().info("Running test suite...")
    Mix.Task.run("test", [])
  end

  defp run_test_tasks(args) do
    Mix.shell().info("Running tests with args: #{Enum.join(args, " ")}")
    Mix.Task.run("test", args)
  end

  defp run_dev_tasks([]) do
    Mix.shell().info("""
    Available dev commands:
      mix raxol dev.analyze  - Run code analysis
      mix raxol dev.profile  - Profile application
      mix raxol dev.debug    - Debug helpers
    """)
  end

  defp run_dev_tasks([cmd | _args]) do
    case cmd do
      "analyze" ->
        Mix.shell().info("Running code analysis...")
        # Would call the analyze task when enabled
        Mix.shell().info("(analyze task not yet enabled)")

      "profile" ->
        Mix.shell().info("Running profiler...")
        # Would call the profile task when enabled
        Mix.shell().info("(profile task not yet enabled)")

      "debug" ->
        Mix.shell().info("Running debug tools...")
        # Would call the debug task when enabled
        Mix.shell().info("(debug task not yet enabled)")

      _ ->
        handle_unknown_subcommand("dev", cmd, @dev_subcommands)
    end
  end

  defp run_docs_tasks([]) do
    Mix.shell().info("Generating documentation...")
    Mix.Task.run("docs", [])
  end

  defp run_docs_tasks(args) do
    Mix.Task.run("docs", args)
  end

  defp run_setup_tasks([]) do
    Mix.shell().info("Setting up Raxol project...")

    tasks = [
      {"deps.get", "Fetching dependencies"},
      {"compile", "Compiling project"},
      {"test", "Running initial tests"}
    ]

    Enum.each(tasks, fn {task, desc} ->
      Mix.shell().info("#{desc}...")
      Mix.Task.run(task, [])
      Mix.Task.reenable(task)
    end)

    Mix.shell().info("Setup complete!")
  end

  defp run_setup_tasks(_args) do
    run_setup_tasks([])
  end

  defp run_clean_tasks([]) do
    Mix.shell().info("Cleaning build artifacts...")

    Mix.Task.run("clean", [])

    # Clean additional artifacts
    _ = File.rm_rf("_build")
    _ = File.rm_rf("deps")
    _ = File.rm_rf("doc")
    _ = File.rm_rf("cover")

    Mix.shell().info("Clean complete!")
  end

  defp run_clean_tasks(_args) do
    run_clean_tasks([])
  end
end
