defmodule ToweropsWeb.AgentLive.Index do
  @moduledoc false
  use ToweropsWeb, :live_view

  import ToweropsWeb.AgentLive.Helpers

  alias Towerops.Agents
  alias Towerops.Agents.Stats

  @impl true
  def mount(_params, _session, socket) do
    organization = socket.assigns.current_organization
    agent_tokens = Agents.list_organization_agent_tokens(organization.id)

    # device counts for each agent (both direct and total with inheritance)
    equipment_counts =
      Map.new(agent_tokens, fn token ->
        direct = Agents.count_assigned_devices(token.id)
        total = length(Agents.list_agent_polling_targets(token.id))
        {token.id, %{direct: direct, total: total}}
      end)

    # Get organization-wide agent health statistics
    agent_health_stats = Stats.get_organization_agent_health(organization.id)
    assignment_breakdown = Stats.get_device_assignment_breakdown(organization.id)
    offline_agents = Stats.get_offline_agents(organization.id)

    # Get agent image URL from config or use default
    agent_image = Application.get_env(:towerops, :agent_docker_image, "towerops/agent:latest")

    {:ok,
     socket
     |> assign(:page_title, "Remote Agents")
     |> assign(:agent_tokens, agent_tokens)
     |> assign(:device_counts, equipment_counts)
     |> assign(:agent_health_stats, agent_health_stats)
     |> assign(:assignment_breakdown, assignment_breakdown)
     |> assign(:offline_agents, offline_agents)
     |> assign(:agent_image, agent_image)
     |> assign(:new_token, nil)
     |> assign(:show_token_modal, false)
     |> assign(:agent_form, to_form(%{"name" => ""}))}
  end

  @impl true
  def handle_params(params, _url, socket) do
    {:noreply, apply_action(socket, socket.assigns.live_action, params)}
  end

  @impl true
  def handle_event("create_agent", params, socket) do
    name =
      case params do
        %{"agent_form" => %{"name" => n}} -> n
        %{"name" => n} -> n
      end

    organization = socket.assigns.current_organization

    case Agents.create_agent_token(organization.id, name) do
      {:ok, agent_token, token} ->
        agent_tokens = Agents.list_organization_agent_tokens(organization.id)

        # device counts
        equipment_counts =
          Map.new(agent_tokens, fn t ->
            direct = Agents.count_assigned_devices(t.id)
            total = length(Agents.list_agent_polling_targets(t.id))
            {t.id, %{direct: direct, total: total}}
          end)

        # Refresh health statistics
        agent_health_stats = Stats.get_organization_agent_health(organization.id)
        assignment_breakdown = Stats.get_device_assignment_breakdown(organization.id)
        offline_agents = Stats.get_offline_agents(organization.id)

        {:noreply,
         socket
         |> assign(:agent_tokens, agent_tokens)
         |> assign(:device_counts, equipment_counts)
         |> assign(:agent_health_stats, agent_health_stats)
         |> assign(:assignment_breakdown, assignment_breakdown)
         |> assign(:offline_agents, offline_agents)
         |> assign(:new_token, %{agent_token: agent_token, token: token})
         |> assign(:show_token_modal, true)
         |> assign(:agent_form, to_form(%{"name" => ""}))
         |> put_flash(:info, "Agent created successfully")}

      {:error, _changeset} ->
        {:noreply, put_flash(socket, :error, "Failed to create agent")}
    end
  end

  @impl true
  def handle_event("close_token_modal", _params, socket) do
    {:noreply,
     socket
     |> assign(:show_token_modal, false)
     |> assign(:new_token, nil)}
  end

  @impl true
  def handle_event("show_setup", %{"id" => id}, socket) do
    agent_token = Agents.get_agent_token!(id)

    {:noreply,
     socket
     |> assign(:new_token, %{agent_token: agent_token, token: agent_token.token})
     |> assign(:show_token_modal, true)}
  end

  @impl true
  def handle_event("regenerate_token", %{"id" => id}, socket) do
    agent_token = Agents.get_agent_token!(id)
    organization = socket.assigns.current_organization

    # Revoke the old token and create a new one
    case Agents.revoke_agent_token(id) do
      {:ok, _} ->
        case Agents.create_agent_token(organization.id, agent_token.name) do
          {:ok, new_agent_token, token} ->
            agent_tokens = Agents.list_organization_agent_tokens(organization.id)

            {:noreply,
             socket
             |> assign(:agent_tokens, agent_tokens)
             |> assign(:new_token, %{agent_token: new_agent_token, token: token})
             |> assign(:show_token_modal, true)
             |> put_flash(:info, "New token generated successfully")}

          {:error, _changeset} ->
            {:noreply, put_flash(socket, :error, "Failed to generate new token")}
        end

      {:error, _} ->
        {:noreply, put_flash(socket, :error, "Failed to revoke old token")}
    end
  end

  @impl true
  def handle_event("delete_agent", %{"id" => id}, socket) do
    case Agents.delete_agent_token(id) do
      {:ok, _} ->
        organization = socket.assigns.current_organization
        agent_tokens = Agents.list_organization_agent_tokens(organization.id)

        # Recalculate device counts after deletion
        equipment_counts =
          Map.new(agent_tokens, fn token ->
            direct = Agents.count_assigned_devices(token.id)
            total = length(Agents.list_agent_polling_targets(token.id))
            {token.id, %{direct: direct, total: total}}
          end)

        # Refresh health statistics
        agent_health_stats = Stats.get_organization_agent_health(organization.id)
        assignment_breakdown = Stats.get_device_assignment_breakdown(organization.id)
        offline_agents = Stats.get_offline_agents(organization.id)

        {:noreply,
         socket
         |> assign(:agent_tokens, agent_tokens)
         |> assign(:device_counts, equipment_counts)
         |> assign(:agent_health_stats, agent_health_stats)
         |> assign(:assignment_breakdown, assignment_breakdown)
         |> assign(:offline_agents, offline_agents)
         |> put_flash(:info, "Agent deleted successfully. Devices now fall back to site/org defaults or cloud polling.")}

      {:error, _} ->
        {:noreply, put_flash(socket, :error, "Failed to delete agent")}
    end
  end

  defp apply_action(socket, :index, _params) do
    socket
  end
end
