defmodule ToweropsWeb.DeviceLive.ShowTest do
  use ToweropsWeb.ConnCase, async: true

  import Phoenix.LiveViewTest

  setup do
    user = Towerops.AccountsFixtures.user_fixture()
    {:ok, organization} = Towerops.Organizations.create_organization(%{name: "Test Org"}, user.id)

    device =
      Towerops.DevicesFixtures.device_fixture(%{
        organization_id: organization.id,
        name: "Test Router",
        ip_address: "192.168.1.1"
      })

    %{user: user, organization: organization, device: device}
  end

  describe "authenticated access" do
    test "redirects to login when not authenticated", %{conn: conn, device: device} do
      assert {:error, redirect} = live(conn, ~p"/devices/#{device.id}?tab=overview")
      assert {:redirect, %{to: to}} = redirect
      assert to =~ "/users/log-in"
    end
  end

  describe "mount and display" do
    test "displays device name and IP address", %{conn: conn, user: user, device: device} do
      conn = log_in_user(conn, user)
      {:ok, _view, html} = live(conn, ~p"/devices/#{device.id}?tab=overview")

      assert html =~ "Test Router"
      assert html =~ "192.168.1.1"
    end

    test "redirects to add tab=overview when no tab param", %{conn: conn, user: user, device: device} do
      conn = log_in_user(conn, user)

      # Without a tab param, the LiveView does push_patch to add ?tab=overview
      assert {:error, {:live_redirect, %{to: to}}} = live(conn, ~p"/devices/#{device.id}")
      assert to =~ "tab=overview"
    end

    test "sets page title to device name", %{conn: conn, user: user, device: device} do
      conn = log_in_user(conn, user)
      {:ok, view, _html} = live(conn, ~p"/devices/#{device.id}?tab=overview")

      assert page_title(view) =~ "Test Router"
    end
  end

  describe "checks tab" do
    test "displays checks tab link", %{conn: conn, user: user, device: device} do
      conn = log_in_user(conn, user)
      {:ok, _view, html} = live(conn, ~p"/devices/#{device.id}?tab=overview")

      assert html =~ "Checks"
    end

    test "loads checks tab with empty state", %{conn: conn, user: user, device: device} do
      conn = log_in_user(conn, user)
      {:ok, _view, html} = live(conn, ~p"/devices/#{device.id}?tab=checks")

      assert html =~ "No checks configured"
      assert html =~ "Add Check"
    end
  end

  describe "tab navigation" do
    test "renders overview tab with device information", %{conn: conn, user: user, device: device} do
      conn = log_in_user(conn, user)
      {:ok, _view, html} = live(conn, ~p"/devices/#{device.id}?tab=overview")

      assert html =~ "Device Information"
    end

    test "switches to neighbors tab via patch", %{conn: conn, user: user, device: device} do
      conn = log_in_user(conn, user)
      {:ok, view, _html} = live(conn, ~p"/devices/#{device.id}?tab=overview")

      # Clicking the Neighbors tab link triggers a patch (not a redirect)
      html = view |> element("a", "Neighbors") |> render_click()

      assert html =~ "Neighbors"
    end

    test "renders logs tab directly", %{conn: conn, user: user, device: device} do
      conn = log_in_user(conn, user)
      {:ok, _view, html} = live(conn, ~p"/devices/#{device.id}?tab=logs")

      assert html =~ "Test Router"
    end
  end

  describe "organization access control" do
    test "denies access to device from another organization", %{conn: conn, device: device} do
      other_user = Towerops.AccountsFixtures.user_fixture()

      {:ok, _other_org} =
        Towerops.Organizations.create_organization(%{name: "Other Org"}, other_user.id)

      conn = log_in_user(conn, other_user)

      assert {:error, {:live_redirect, %{to: "/devices", flash: flash}}} =
               live(conn, ~p"/devices/#{device.id}?tab=overview")

      assert flash["error"] =~ "You don't have access to this device"
    end

    test "redirects with not found for nonexistent device", %{conn: conn, user: user} do
      conn = log_in_user(conn, user)
      fake_id = Ecto.UUID.generate()

      assert {:error, {:live_redirect, %{to: "/devices", flash: flash}}} =
               live(conn, ~p"/devices/#{fake_id}?tab=overview")

      assert flash["error"] =~ "Device not found"
    end
  end

  describe "tab rendering" do
    test "renders interfaces tab", %{conn: conn, user: user, device: device} do
      conn = log_in_user(conn, user)
      {:ok, _view, html} = live(conn, ~p"/devices/#{device.id}?tab=interfaces")

      assert html =~ "Test Router"
    end

    test "renders sensors tab", %{conn: conn, user: user, device: device} do
      conn = log_in_user(conn, user)
      {:ok, _view, html} = live(conn, ~p"/devices/#{device.id}?tab=sensors")

      assert html =~ "Test Router"
    end

    test "renders events tab", %{conn: conn, user: user, device: device} do
      conn = log_in_user(conn, user)
      {:ok, _view, html} = live(conn, ~p"/devices/#{device.id}?tab=events")

      assert html =~ "Test Router"
    end
  end

  describe "handle_info events" do
    test "handles device_status_changed", %{conn: conn, user: user, device: device} do
      conn = log_in_user(conn, user)
      {:ok, view, _html} = live(conn, ~p"/devices/#{device.id}?tab=overview")

      send(view.pid, {:device_status_changed, device.id, :up, 10})
      assert render(view)
    end

    test "handles discovery_completed", %{conn: conn, user: user, device: device} do
      conn = log_in_user(conn, user)
      {:ok, view, _html} = live(conn, ~p"/devices/#{device.id}?tab=overview")

      send(view.pid, {:discovery_completed, device.id})
      html = render(view)
      assert html =~ "Discovery completed"
    end

    test "handles sensors_updated", %{conn: conn, user: user, device: device} do
      conn = log_in_user(conn, user)
      {:ok, view, _html} = live(conn, ~p"/devices/#{device.id}?tab=overview")

      send(view.pid, {:sensors_updated, device.id})
      assert render(view)
    end

    test "handles interfaces_updated", %{conn: conn, user: user, device: device} do
      conn = log_in_user(conn, user)
      {:ok, view, _html} = live(conn, ~p"/devices/#{device.id}?tab=overview")

      send(view.pid, {:interfaces_updated, device.id})
      assert render(view)
    end

    test "handles neighbors_updated", %{conn: conn, user: user, device: device} do
      conn = log_in_user(conn, user)
      {:ok, view, _html} = live(conn, ~p"/devices/#{device.id}?tab=overview")

      send(view.pid, {:neighbors_updated, device.id})
      assert render(view)
    end

    test "handles arp_updated", %{conn: conn, user: user, device: device} do
      conn = log_in_user(conn, user)
      {:ok, view, _html} = live(conn, ~p"/devices/#{device.id}?tab=overview")

      send(view.pid, {:arp_updated, device.id})
      assert render(view)
    end

    test "handles mac_updated", %{conn: conn, user: user, device: device} do
      conn = log_in_user(conn, user)
      {:ok, view, _html} = live(conn, ~p"/devices/#{device.id}?tab=overview")

      send(view.pid, {:mac_updated, device.id})
      assert render(view)
    end

    test "handles state_sensors_updated", %{conn: conn, user: user, device: device} do
      conn = log_in_user(conn, user)
      {:ok, view, _html} = live(conn, ~p"/devices/#{device.id}?tab=overview")

      send(view.pid, {:state_sensors_updated, device.id})
      assert render(view)
    end

    test "handles processors_updated", %{conn: conn, user: user, device: device} do
      conn = log_in_user(conn, user)
      {:ok, view, _html} = live(conn, ~p"/devices/#{device.id}?tab=overview")

      send(view.pid, {:processors_updated, device.id})
      assert render(view)
    end

    test "handles storage_updated", %{conn: conn, user: user, device: device} do
      conn = log_in_user(conn, user)
      {:ok, view, _html} = live(conn, ~p"/devices/#{device.id}?tab=overview")

      send(view.pid, {:storage_updated, device.id})
      assert render(view)
    end

    test "handles monitoring_check_updated", %{conn: conn, user: user, device: device} do
      conn = log_in_user(conn, user)
      {:ok, view, _html} = live(conn, ~p"/devices/#{device.id}?tab=overview")

      send(view.pid, {:monitoring_check_updated, device.id})
      assert render(view)
    end

    test "handles device_event", %{conn: conn, user: user, device: device} do
      conn = log_in_user(conn, user)
      {:ok, view, _html} = live(conn, ~p"/devices/#{device.id}?tab=overview")

      send(view.pid, {:device_event, %{device_id: device.id, type: "test"}})
      assert render(view)
    end

    test "handles refresh_data", %{conn: conn, user: user, device: device} do
      conn = log_in_user(conn, user)
      {:ok, view, _html} = live(conn, ~p"/devices/#{device.id}?tab=overview")

      send(view.pid, :refresh_data)
      assert render(view)
    end

    test "handles agents_stale with unrelated agent", %{conn: conn, user: user, device: device} do
      conn = log_in_user(conn, user)
      {:ok, view, _html} = live(conn, ~p"/devices/#{device.id}?tab=overview")

      send(view.pid, {:agents_stale, []})
      assert render(view)
    end

    test "handles agent_connected with unrelated agent", %{conn: conn, user: user, device: device} do
      conn = log_in_user(conn, user)
      {:ok, view, _html} = live(conn, ~p"/devices/#{device.id}?tab=overview")

      send(view.pid, {:agent_connected, Ecto.UUID.generate(), Ecto.UUID.generate()})
      assert render(view)
    end

    test "handles agent_disconnected with unrelated agent", %{conn: conn, user: user, device: device} do
      conn = log_in_user(conn, user)
      {:ok, view, _html} = live(conn, ~p"/devices/#{device.id}?tab=overview")

      send(view.pid, {:agent_disconnected, Ecto.UUID.generate(), Ecto.UUID.generate()})
      assert render(view)
    end

    test "handles agent_heartbeat with unrelated agent", %{conn: conn, user: user, device: device} do
      conn = log_in_user(conn, user)
      {:ok, view, _html} = live(conn, ~p"/devices/#{device.id}?tab=overview")

      send(view.pid, {:agent_heartbeat, Ecto.UUID.generate(), Ecto.UUID.generate()})
      assert render(view)
    end
  end
end
