defmodule ToweropsWeb.Admin.SecurityLive.Index do
  @moduledoc """
  Admin page for managing IP-based brute force protection.

  Provides two main functions:
  1. Allowlist management - Add/remove IPs and CIDR ranges that bypass protection
  2. Denylist management - View and manually unblock banned IPs
  """
  use ToweropsWeb, :live_view

  alias Towerops.Security.BruteForce

  @impl true
  def mount(_params, _session, socket) do
    if connected?(socket) do
      Phoenix.PubSub.subscribe(Towerops.PubSub, "security:whitelist")
      Phoenix.PubSub.subscribe(Towerops.PubSub, "security:blocks")
    end

    {:ok,
     socket
     |> assign(:page_title, "Security - IP Access Control")
     |> assign(:current_tab, "whitelist")}
  end

  @impl true
  def handle_params(params, _url, socket) do
    tab = Map.get(params, "tab", "whitelist")
    filter = Map.get(params, "filter", "all")

    {:noreply,
     socket
     |> assign(:current_tab, tab)
     |> assign(:filter, filter)
     |> load_data()}
  end

  @impl true
  def handle_event("change_tab", %{"tab" => tab}, socket) do
    {:noreply, push_patch(socket, to: ~p"/admin/security?tab=#{tab}")}
  end

  def handle_event("change_filter", %{"filter" => filter}, socket) do
    {:noreply, push_patch(socket, to: ~p"/admin/security?tab=#{socket.assigns.current_tab}&filter=#{filter}")}
  end

  def handle_event("show_whitelist_form", _params, socket) do
    {:noreply,
     socket
     |> assign(:show_whitelist_form, true)
     |> assign(:whitelist_form, to_form(%{}))}
  end

  def handle_event("hide_whitelist_form", _params, socket) do
    {:noreply, assign(socket, :show_whitelist_form, false)}
  end

  def handle_event("add_whitelist", %{"whitelist" => params}, socket) do
    case BruteForce.add_to_whitelist(
           params["ip_or_cidr"],
           params["description"],
           socket.assigns.current_user
         ) do
      {:ok, _entry} ->
        {:noreply,
         socket
         |> put_flash(:info, "IP/CIDR added to allowlist")
         |> assign(:show_whitelist_form, false)
         |> load_data()}

      {:error, changeset} ->
        {:noreply,
         socket
         |> assign(:whitelist_form, to_form(Map.put(changeset, :action, :validate)))
         |> put_flash(:error, "Failed to add to allowlist")}
    end
  end

  def handle_event("remove_whitelist", %{"id" => id}, socket) do
    case BruteForce.remove_from_whitelist(id) do
      :ok ->
        {:noreply,
         socket
         |> put_flash(:info, "Removed from allowlist")
         |> load_data()}

      {:error, _} ->
        {:noreply, put_flash(socket, :error, "Failed to remove from allowlist")}
    end
  end

  def handle_event("unblock_ip", %{"ip" => ip_address}, socket) do
    case BruteForce.manually_unblock(ip_address) do
      {:ok, _} ->
        {:noreply,
         socket
         |> put_flash(:info, "IP #{ip_address} unblocked")
         |> load_data()}

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

  @impl true
  def handle_info(:whitelist_updated, socket) do
    {:noreply, load_data(socket)}
  end

  def handle_info(:blocks_updated, socket) do
    {:noreply, load_data(socket)}
  end

  defp load_data(socket) do
    whitelist = BruteForce.list_whitelist()

    blocked_ips =
      case socket.assigns[:filter] || "all" do
        "permanent" -> BruteForce.list_blocked_ips(:permanent)
        "temporary" -> BruteForce.list_blocked_ips(:temporary)
        _ -> BruteForce.list_blocked_ips(:all)
      end

    socket
    |> assign(:whitelist, whitelist)
    |> assign(:blocked_ips, blocked_ips)
    |> assign(:show_whitelist_form, Map.get(socket.assigns, :show_whitelist_form, false))
  end
end
