defmodule TarakanWeb.InfestationLive.Index do
  @moduledoc "Cross-repo infestation list: patterns spanning multiple listed repositories."
  use TarakanWeb, :live_view

  alias Tarakan.Infestations

  @impl true
  def mount(_params, _session, socket) do
    {:ok,
     socket
     |> assign(:page_title, "Infestations")
     |> assign(
       :meta_description,
       "Cross-repo infestations: the same finding title in multiple listed repositories."
     )
     |> assign(:canonical_path, ~p"/infestations")
     |> assign(:days, 30)
     |> assign(:min_repos, 2)
     |> load_infestations()}
  end

  @impl true
  def handle_event("filter", params, socket) do
    days = parse_int(params["days"], socket.assigns.days, 1, 365)
    min_repos = parse_int(params["min_repos"], socket.assigns.min_repos, 2, 20)

    {:noreply,
     socket
     |> assign(:days, days)
     |> assign(:min_repos, min_repos)
     |> load_infestations()}
  end

  defp load_infestations(socket) do
    infestations =
      Infestations.list_infestations(
        days: socket.assigns.days,
        min_repos: socket.assigns.min_repos,
        limit: 50
      )

    assign(socket, :infestations, infestations)
  end

  defp parse_int(value, default, min, max) do
    case Integer.parse(to_string(value || "")) do
      {n, _} -> n |> max(min) |> min(max)
      :error -> default
    end
  end

  @impl true
  def render(assigns) do
    ~H"""
    <Layouts.app flash={@flash} current_scope={@current_scope} current_path={assigns[:current_path]}>
      <Layouts.page width={:wide}>
        <div class="flex flex-col gap-4 border-b-2 border-strong pb-6 sm:flex-row sm:items-end sm:justify-between">
          <div class="max-w-2xl">
            <h1 class="font-display text-3xl font-medium uppercase tracking-[0.02em] text-ink sm:text-5xl">
              Infestations
            </h1>
            <p class="mt-3 text-sm leading-6 text-ink-muted">
              Same finding title in {@min_repos}+ listed repos within the window.
              Ranked by affected repo count.
            </p>
          </div>

          <form
            id="infestations-filter"
            phx-change="filter"
            class="flex flex-wrap items-end gap-3 font-mono text-xs"
          >
            <label class="flex flex-col gap-1 text-ink-faint">
              Min repos
              <select
                name="min_repos"
                class="border border-strong bg-panel px-2 py-1.5 text-ink"
              >
                <option :for={n <- [2, 3, 5, 10]} value={n} selected={@min_repos == n}>{n}</option>
              </select>
            </label>
            <label class="flex flex-col gap-1 text-ink-faint">
              Window
              <select name="days" class="border border-strong bg-panel px-2 py-1.5 text-ink">
                <option :for={n <- [7, 30, 90, 365]} value={n} selected={@days == n}>
                  {n}d
                </option>
              </select>
            </label>
          </form>
        </div>

        <div
          :if={@infestations == []}
          id="infestations-empty"
          class="mt-10 bg-panel px-6 py-16 text-center"
        >
          <p class="text-sm font-medium text-ink">No infestations in this window</p>
          <p class="mt-2 text-xs text-ink-muted">
            Infestations appear when the same finding title hits {@min_repos}+ listed repos.
          </p>
        </div>

        <div :if={@infestations != []} class="mt-8">
          <.constellation id="infestations-constellation" infestations={@infestations} />

          <ul id="infestations-list" class="sr-only">
            <li :for={infestation <- @infestations} id={"infestation-#{infestation.pattern_key}"}>
              <.link navigate={~p"/infestations/#{infestation.pattern_key}"}>
                {infestation.title} · {infestation.repo_count} repos
              </.link>
            </li>
          </ul>
        </div>
      </Layouts.page>
    </Layouts.app>
    """
  end
end
