defmodule ToweropsWeb.Org.PreseemDevicesLive do
  @moduledoc false
  use ToweropsWeb, :live_view

  alias Towerops.Devices
  alias Towerops.Preseem
  alias Towerops.Repo

  @impl true
  def mount(_params, _session, socket) do
    org = socket.assigns.current_scope.organization

    {:ok,
     socket
     |> assign(:organization, org)
     |> assign(:filter, "all")
     |> assign(:linking_ap_id, nil)
     |> assign(:device_search, "")
     |> assign(:search_results, [])
     |> load_access_points()}
  end

  @impl true
  def handle_params(params, _url, socket) do
    filter =
      case params["filter"] do
        f when f in ~w(all unmatched matched) -> f
        _ -> "all"
      end

    {:noreply, socket |> assign(:filter, filter) |> load_access_points()}
  end

  @impl true
  def handle_event("filter", %{"filter" => filter}, socket) do
    org = socket.assigns.organization

    {:noreply,
     push_patch(socket,
       to: ~p"/orgs/#{org.slug}/settings/integrations/preseem/devices?filter=#{filter}"
     )}
  end

  @impl true
  def handle_event("start_link", %{"ap-id" => ap_id}, socket) do
    {:noreply,
     socket
     |> assign(:linking_ap_id, ap_id)
     |> assign(:device_search, "")
     |> assign(:search_results, [])}
  end

  @impl true
  def handle_event("cancel_link", _params, socket) do
    {:noreply,
     socket
     |> assign(:linking_ap_id, nil)
     |> assign(:device_search, "")
     |> assign(:search_results, [])}
  end

  @impl true
  def handle_event("search_devices", %{"query" => query}, socket) do
    org = socket.assigns.organization

    results =
      if String.length(query) >= 2 do
        Devices.search_devices(org.id, query)
      else
        []
      end

    {:noreply, socket |> assign(:device_search, query) |> assign(:search_results, results)}
  end

  @impl true
  def handle_event("link_device", %{"ap-id" => ap_id, "device-id" => device_id}, socket) do
    case Preseem.link_access_point(ap_id, device_id) do
      {:ok, _} ->
        {:noreply,
         socket
         |> assign(:linking_ap_id, nil)
         |> assign(:device_search, "")
         |> assign(:search_results, [])
         |> load_access_points()
         |> put_flash(:info, "Device linked successfully")}

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

  @impl true
  def handle_event("unlink_device", %{"ap-id" => ap_id}, socket) do
    case Preseem.unlink_access_point(ap_id) do
      {:ok, _} ->
        {:noreply,
         socket
         |> load_access_points()
         |> put_flash(:info, "Device unlinked")}

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

  defp match_confidence_classes(confidence) do
    case confidence do
      "unmatched" ->
        "bg-yellow-100 text-yellow-800 dark:bg-yellow-900/30 dark:text-yellow-400"

      "ambiguous" ->
        "bg-orange-100 text-orange-800 dark:bg-orange-900/30 dark:text-orange-400"

      "manual" ->
        "bg-blue-100 text-blue-800 dark:bg-blue-900/30 dark:text-blue-400"

      _ ->
        "bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-400"
    end
  end

  defp humanize_confidence(confidence) do
    case confidence do
      "auto_mac" -> "Auto (MAC)"
      "auto_ip" -> "Auto (IP)"
      "auto_hostname" -> "Auto (Hostname)"
      "manual" -> "Manual"
      "ambiguous" -> "Ambiguous"
      "unmatched" -> "Unmatched"
      other -> String.capitalize(other || "unknown")
    end
  end

  defp load_access_points(socket) do
    org_id = socket.assigns.organization.id
    filter = socket.assigns.filter

    access_points =
      case filter do
        "unmatched" -> Preseem.list_unmatched_access_points(org_id)
        "matched" -> Preseem.list_matched_access_points(org_id)
        _ -> Preseem.list_access_points(org_id)
      end

    access_points = Repo.preload(access_points, :device)

    assign(socket, :access_points, access_points)
  end
end
