defmodule Raxol.Extensions.VSCodeBackend do
  @moduledoc """
  Backend handler for the VS Code extension.

  This module provides the Elixir-side implementation for communicating
  with the VS Code extension, handling requests for AI features, performance
  analysis, and component management.
  """

  use Raxol.Core.Behaviours.BaseManager
  alias Raxol.Core.Runtime.Log

  # AI modules removed - AI features disabled
  @json_start_marker "RAXOL-JSON-BEGIN"
  @json_end_marker "RAXOL-JSON-END"

  defmodule State do
    @moduledoc false
    defstruct [:mode, :extension_pid, :active_requests, :capabilities]

    def new do
      %__MODULE__{
        mode: System.get_env("RAXOL_MODE") || "standalone",
        extension_pid: nil,
        active_requests: %{},
        capabilities:
          MapSet.new([
            # AI features disabled - removed:
            # :ai_content_generation,
            # :code_completion,
            # :optimization_suggestions
            :performance_analysis,
            :component_analysis
          ])
      }
    end
  end

  #  def start_link(opts \\ []) do
  #    GenServer.start_link(__MODULE__, opts, name: __MODULE__)
  #  end

  @impl true
  def init_manager(_opts) do
    state = State.new()
    initialize_mode(state.mode, state.capabilities)
    {:ok, state}
  end

  defp initialize_mode("vscode_ext", capabilities) do
    Log.info("Starting in VS Code extension mode")
    # Start listening for stdin messages from the extension
    _ = Task.start_link(&listen_for_messages/0)
    _ = send_capabilities(capabilities)
  end

  defp initialize_mode(_mode, _capabilities), do: :ok

  @impl true
  def handle_manager_cast({:handle_message, message}, state) do
    # handle_extension_message always returns {:ok, state}
    {:ok, new_state} = handle_extension_message(message, state)
    {:noreply, new_state}
  end

  @impl true
  def handle_manager_cast({:send_response, request_id, response}, state) do
    send_json_message(%{
      type: "response",
      request_id: request_id,
      payload: response
    })

    # Remove from active requests
    active_requests = Map.delete(state.active_requests, request_id)
    {:noreply, %{state | active_requests: active_requests}}
  end

  # Public API

  @doc """
  Handles a code completion request from the VS Code extension.
  """
  def handle_completion_request(_input, context) do
    # AI features disabled - ContentGeneration module removed
    {:ok,
     %{suggestions: [], context: context, message: "AI completion disabled"}}
  end

  @doc """
  Handles a performance analysis request from the VS Code extension.
  """
  def handle_performance_analysis(_code, component_name, _metrics \\ %{}) do
    # AI features disabled - PerformanceOptimization module removed
    {:ok,
     %{
       component: component_name,
       analysis: %{message: "AI performance analysis disabled"},
       suggestions: []
     }}
  end

  @doc """
  Handles a component analysis request from the VS Code extension.
  """
  def handle_component_analysis(file_path) do
    with {:ok, content} <- File.read(file_path),
         {:ok, ast} <- Code.string_to_quoted(content) do
      analysis = %{
        module_name: extract_module_name(ast),
        functions: extract_functions(ast),
        dependencies: extract_dependencies(ast),
        complexity_score: calculate_complexity(ast),
        suggestions: generate_component_suggestions(ast)
      }

      {:ok, analysis}
    else
      {:error, reason} ->
        {:error, "Failed to analyze component: #{inspect(reason)}"}
    end
  end

  @doc """
  Lists available components in the project.
  """
  def list_components do
    case Raxol.Core.ErrorHandling.safe_call(fn ->
           # Find all .ex files that look like components
           Path.wildcard("lib/**/*.ex")
           |> Enum.filter(&component_file?/1)
           |> Enum.map(&analyze_component_file/1)
           |> Enum.filter(& &1)
         end) do
      {:ok, components} ->
        {:ok, components}

      {:error, error} ->
        {:error, "Failed to list components: #{inspect(error)}"}
    end
  end

  # Private functions

  defp listen_for_messages do
    case IO.read(:stdio, :line) do
      :eof ->
        Log.info("EOF received, stopping message listener")
        :ok

      {:error, reason} ->
        Log.error(
          "[VSCodeBackend] Error reading from stdin: #{inspect(reason)}"
        )

        :error

      data ->
        case Jason.decode(String.trim(data)) do
          {:ok, message} ->
            GenServer.cast(__MODULE__, {:handle_message, message})

          {:error, _} ->
            Log.warning(
              "[VSCodeBackend] Invalid JSON received: #{inspect(data)}"
            )
        end

        listen_for_messages()
    end
  end

  defp handle_extension_message(
         %{"type" => "request", "id" => request_id} = message,
         state
       ) do
    # Store the request
    active_requests = Map.put(state.active_requests, request_id, message)
    new_state = %{state | active_requests: active_requests}

    # Process the request asynchronously
    _ =
      Task.start(fn ->
        response = process_request(message)
        GenServer.cast(__MODULE__, {:send_response, request_id, response})
      end)

    {:ok, new_state}
  end

  defp handle_extension_message(%{"type" => "shutdown"}, state) do
    Log.info("Shutdown requested by extension")
    System.stop()
    {:ok, state}
  end

  defp handle_extension_message(message, state) do
    Log.info("Received message: #{inspect(message)}")
    {:ok, state}
  end

  defp process_request(%{"action" => "complete", "payload" => payload}) do
    input = Map.get(payload, "input", "")
    context = Map.get(payload, "context", %{})

    case handle_completion_request(input, context) do
      {:ok, result} -> %{status: "success", data: result}
      {:error, reason} -> %{status: "error", error: inspect(reason)}
    end
  end

  defp process_request(%{
         "action" => "analyze_performance",
         "payload" => payload
       }) do
    code = Map.get(payload, "code", "")
    component_name = Map.get(payload, "component_name", "unknown")
    metrics = Map.get(payload, "metrics", %{})

    case handle_performance_analysis(code, component_name, metrics) do
      {:ok, result} -> %{status: "success", data: result}
      {:error, reason} -> %{status: "error", error: inspect(reason)}
    end
  end

  defp process_request(%{"action" => "analyze_component", "payload" => payload}) do
    file_path = Map.get(payload, "file_path", "")

    case handle_component_analysis(file_path) do
      {:ok, result} -> %{status: "success", data: result}
      {:error, reason} -> %{status: "error", error: inspect(reason)}
    end
  end

  defp process_request(%{"action" => "list_components"}) do
    case list_components() do
      {:ok, result} -> %{status: "success", data: result}
      {:error, reason} -> %{status: "error", error: inspect(reason)}
    end
  end

  defp process_request(%{"action" => action}) do
    %{status: "error", error: "Unknown action: #{action}"}
  end

  defp send_capabilities(capabilities) do
    send_json_message(%{
      type: "capabilities",
      payload: %{
        capabilities: MapSet.to_list(capabilities),
        ai_provider: Application.get_env(:raxol, :ai_provider, :mock),
        version: Application.spec(:raxol, :vsn)
      }
    })
  end

  defp send_json_message(message) do
    json = Jason.encode!(message)
    Log.info("#{@json_start_marker}#{json}#{@json_end_marker}")
  end

  defp component_file?(file_path) do
    content = File.read!(file_path)

    String.contains?(content, [
      "defmodule",
      "@behaviour",
      "use Raxol.Core.Behaviours.BaseManager"
    ]) and
      not String.contains?(file_path, ["test/", "_test.exs"])
  end

  defp analyze_component_file(file_path) do
    case Raxol.Core.ErrorHandling.safe_call(fn ->
           content = File.read!(file_path)
           {:ok, ast} = Code.string_to_quoted(content)

           %{
             file_path: file_path,
             module_name: extract_module_name(ast),
             type: determine_component_type(ast),
             functions: length(extract_functions(ast)),
             complexity: calculate_complexity(ast)
           }
         end) do
      {:ok, result} -> result
      {:error, _} -> nil
    end
  end

  defp extract_module_name(ast) do
    case ast do
      {:defmodule, _, [{:__aliases__, _, module_parts}, _]} ->
        Enum.join(module_parts, ".")

      _ ->
        "Unknown"
    end
  end

  defp extract_functions(ast) do
    {functions, _} =
      Macro.prewalk(ast, [], fn
        {:def, _, [{name, _, _} | _]}, acc -> {ast, [name | acc]}
        {:defp, _, [{name, _, _} | _]}, acc -> {ast, [name | acc]}
        node, acc -> {node, acc}
      end)

    Enum.uniq(functions)
  end

  defp extract_dependencies(ast) do
    {deps, _} =
      Macro.prewalk(ast, [], fn
        {:alias, _, [{:__aliases__, _, module_parts}]}, acc ->
          {ast, [Enum.join(module_parts, ".") | acc]}

        {:import, _, [{:__aliases__, _, module_parts}]}, acc ->
          {ast, [Enum.join(module_parts, ".") | acc]}

        node, acc ->
          {node, acc}
      end)

    Enum.uniq(deps)
  end

  defp calculate_complexity(ast) do
    {_, complexity} =
      Macro.prewalk(ast, 0, fn
        {:if, _, _}, acc -> {ast, acc + 1}
        {:case, _, _}, acc -> {ast, acc + 2}
        {:cond, _, _}, acc -> {ast, acc + 2}
        {:with, _, _}, acc -> {ast, acc + 1}
        {:try, _, _}, acc -> {ast, acc + 2}
        node, acc -> {node, acc}
      end)

    complexity
  end

  # Helper functions for pattern matching refactoring

  defp determine_component_type(ast) do
    content = Macro.to_string(ast)

    case {String.contains?(content, "GenServer"),
          String.contains?(content, "@behaviour"),
          String.contains?(content, "Supervisor"),
          String.contains?(content, "Application")} do
      {true, _, _, _} -> :genserver
      {false, true, _, _} -> :behaviour
      {false, false, true, _} -> :supervisor
      {false, false, false, true} -> :application
      {false, false, false, false} -> :module
    end
  end

  defp generate_component_suggestions(ast) do
    complexity = calculate_complexity(ast)
    functions = extract_functions(ast)

    suggestions =
      []
      |> add_complexity_suggestion(complexity)
      |> add_size_suggestion(functions)
      |> finalize_suggestions()

    suggestions
  end

  defp add_complexity_suggestion(suggestions, complexity)
       when complexity > 10 do
    ["Consider breaking down complex functions" | suggestions]
  end

  defp add_complexity_suggestion(suggestions, _complexity), do: suggestions

  defp add_size_suggestion(suggestions, functions)
       when length(functions) > 20 do
    ["Large module - consider splitting into smaller modules" | suggestions]
  end

  defp add_size_suggestion(suggestions, _functions), do: suggestions

  defp finalize_suggestions([]), do: ["Component looks well-structured"]
  defp finalize_suggestions(suggestions), do: suggestions
end
