defmodule ToweropsWeb.Org.PreseemDevicesLiveTest do
  use ToweropsWeb.ConnCase, async: true

  import Phoenix.LiveViewTest
  import Towerops.AccountsFixtures
  import Towerops.DevicesFixtures
  import Towerops.OrganizationsFixtures

  alias Towerops.Preseem.AccessPoint
  alias Towerops.Repo

  setup do
    user = user_fixture()
    org = organization_fixture(user.id)
    %{user: user, organization: org}
  end

  defp insert_access_point!(org, attrs) do
    default = %{
      organization_id: org.id,
      preseem_id: "ap-#{System.unique_integer([:positive])}",
      name: "Test AP"
    }

    {:ok, ap} =
      %AccessPoint{}
      |> AccessPoint.changeset(Map.merge(default, attrs))
      |> Repo.insert()

    ap
  end

  describe "index" do
    test "renders page with no access points", %{conn: conn, user: user, organization: org} do
      {:ok, _view, html} =
        conn
        |> log_in_user(user)
        |> live(~p"/orgs/#{org.slug}/settings/integrations/preseem/devices")

      assert html =~ "Preseem Devices"
    end

    test "shows empty state message when no APs exist", %{conn: conn, user: user, organization: org} do
      {:ok, view, _html} =
        conn
        |> log_in_user(user)
        |> live(~p"/orgs/#{org.slug}/settings/integrations/preseem/devices")

      assert has_element?(view, "#empty-state")
    end

    test "shows access points in table", %{conn: conn, user: user, organization: org} do
      insert_access_point!(org, %{
        name: "Tower 1 AP",
        preseem_id: "preseem-123",
        ip_address: "10.0.0.1",
        mac_address: "AA:BB:CC:DD:EE:FF"
      })

      {:ok, _view, html} =
        conn
        |> log_in_user(user)
        |> live(~p"/orgs/#{org.slug}/settings/integrations/preseem/devices")

      assert html =~ "Tower 1 AP"
      assert html =~ "preseem-123"
      assert html =~ "10.0.0.1"
    end

    test "shows match confidence for each AP", %{conn: conn, user: user, organization: org} do
      insert_access_point!(org, %{name: "Unmatched AP", match_confidence: "unmatched"})

      {:ok, _view, html} =
        conn
        |> log_in_user(user)
        |> live(~p"/orgs/#{org.slug}/settings/integrations/preseem/devices")

      assert html =~ "Unmatched"
    end

    test "shows linked device name for matched APs", %{conn: conn, user: user, organization: org} do
      device = device_fixture(%{organization_id: org.id, name: "My Router"})

      insert_access_point!(org, %{
        name: "Matched AP",
        device_id: device.id,
        match_confidence: "manual"
      })

      {:ok, _view, html} =
        conn
        |> log_in_user(user)
        |> live(~p"/orgs/#{org.slug}/settings/integrations/preseem/devices")

      assert html =~ "My Router"
    end
  end

  describe "filtering" do
    setup %{organization: org} do
      unmatched = insert_access_point!(org, %{name: "Unmatched AP", match_confidence: "unmatched"})
      device = device_fixture(%{organization_id: org.id, name: "Linked Device"})

      matched =
        insert_access_point!(org, %{
          name: "Matched AP",
          device_id: device.id,
          match_confidence: "auto_mac"
        })

      %{unmatched: unmatched, matched: matched, device: device}
    end

    test "shows all APs by default", %{conn: conn, user: user, organization: org} do
      {:ok, _view, html} =
        conn
        |> log_in_user(user)
        |> live(~p"/orgs/#{org.slug}/settings/integrations/preseem/devices")

      assert html =~ "Unmatched AP"
      assert html =~ "Matched AP"
    end

    test "filters to unmatched only", %{conn: conn, user: user, organization: org} do
      {:ok, _view, html} =
        conn
        |> log_in_user(user)
        |> live(~p"/orgs/#{org.slug}/settings/integrations/preseem/devices?filter=unmatched")

      assert html =~ "Unmatched AP"
      refute html =~ "Matched AP"
    end

    test "filters to matched only", %{conn: conn, user: user, organization: org} do
      {:ok, _view, html} =
        conn
        |> log_in_user(user)
        |> live(~p"/orgs/#{org.slug}/settings/integrations/preseem/devices?filter=matched")

      refute html =~ "Unmatched AP"
      assert html =~ "Matched AP"
    end

    test "clicking filter tab patches URL", %{conn: conn, user: user, organization: org} do
      {:ok, view, _html} =
        conn
        |> log_in_user(user)
        |> live(~p"/orgs/#{org.slug}/settings/integrations/preseem/devices")

      view |> element("#filter-unmatched") |> render_click()

      assert_patch(view, ~p"/orgs/#{org.slug}/settings/integrations/preseem/devices?filter=unmatched")
    end
  end

  describe "linking" do
    test "shows link button for unmatched APs", %{conn: conn, user: user, organization: org} do
      ap = insert_access_point!(org, %{name: "Unlinked AP", match_confidence: "unmatched"})

      {:ok, view, _html} =
        conn
        |> log_in_user(user)
        |> live(~p"/orgs/#{org.slug}/settings/integrations/preseem/devices")

      assert has_element?(view, "#link-ap-#{ap.id}")
    end

    test "clicking link opens search UI", %{conn: conn, user: user, organization: org} do
      ap = insert_access_point!(org, %{name: "Unlinked AP", match_confidence: "unmatched"})

      {:ok, view, _html} =
        conn
        |> log_in_user(user)
        |> live(~p"/orgs/#{org.slug}/settings/integrations/preseem/devices")

      view |> element("#link-ap-#{ap.id}") |> render_click()

      assert has_element?(view, "#device-search-input")
    end

    test "searching devices returns results", %{conn: conn, user: user, organization: org} do
      device = device_fixture(%{organization_id: org.id, name: "My Tower Router"})
      ap = insert_access_point!(org, %{name: "Unlinked AP", match_confidence: "unmatched"})

      {:ok, view, _html} =
        conn
        |> log_in_user(user)
        |> live(~p"/orgs/#{org.slug}/settings/integrations/preseem/devices")

      view |> element("#link-ap-#{ap.id}") |> render_click()

      html =
        view
        |> element("#device-search-form")
        |> render_change(%{query: "Tower"})

      assert html =~ "My Tower Router"

      # Verify the device fixture was created correctly
      assert device.name == "My Tower Router"
    end

    test "can link a device to an AP", %{conn: conn, user: user, organization: org} do
      device = device_fixture(%{organization_id: org.id, name: "Link Target"})
      ap = insert_access_point!(org, %{name: "Unlinked AP", match_confidence: "unmatched"})

      {:ok, view, _html} =
        conn
        |> log_in_user(user)
        |> live(~p"/orgs/#{org.slug}/settings/integrations/preseem/devices")

      # Open linking UI
      view |> element("#link-ap-#{ap.id}") |> render_click()

      # Search for device
      view
      |> element("#device-search-form")
      |> render_change(%{query: "Link Target"})

      # Click to link
      html =
        view
        |> element("#select-device-#{device.id}")
        |> render_click()

      assert html =~ "Device linked successfully"

      # Verify the AP is now linked in the database
      updated_ap = Repo.get!(AccessPoint, ap.id)
      assert updated_ap.device_id == device.id
      assert updated_ap.match_confidence == "manual"
    end

    test "cancel closes linking UI", %{conn: conn, user: user, organization: org} do
      ap = insert_access_point!(org, %{name: "AP to Cancel", match_confidence: "unmatched"})

      {:ok, view, _html} =
        conn
        |> log_in_user(user)
        |> live(~p"/orgs/#{org.slug}/settings/integrations/preseem/devices")

      # Open linking UI
      view |> element("#link-ap-#{ap.id}") |> render_click()
      assert has_element?(view, "#device-search-input")

      # Cancel
      view |> element("#cancel-link") |> render_click()
      refute has_element?(view, "#device-search-input")
    end
  end

  describe "unlinking" do
    test "shows unlink button for matched APs", %{conn: conn, user: user, organization: org} do
      device = device_fixture(%{organization_id: org.id})

      ap =
        insert_access_point!(org, %{
          name: "Linked AP",
          device_id: device.id,
          match_confidence: "manual"
        })

      {:ok, view, _html} =
        conn
        |> log_in_user(user)
        |> live(~p"/orgs/#{org.slug}/settings/integrations/preseem/devices")

      assert has_element?(view, "#unlink-ap-#{ap.id}")
    end

    test "can unlink a device from an AP", %{conn: conn, user: user, organization: org} do
      device = device_fixture(%{organization_id: org.id})

      ap =
        insert_access_point!(org, %{
          name: "Linked AP",
          device_id: device.id,
          match_confidence: "manual"
        })

      {:ok, view, _html} =
        conn
        |> log_in_user(user)
        |> live(~p"/orgs/#{org.slug}/settings/integrations/preseem/devices")

      html = view |> element("#unlink-ap-#{ap.id}") |> render_click()
      assert html =~ "Device unlinked"

      # Verify the AP is now unlinked in the database
      updated_ap = Repo.get!(AccessPoint, ap.id)
      assert is_nil(updated_ap.device_id)
      assert updated_ap.match_confidence == "unmatched"
    end
  end
end
