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

  import Phoenix.LiveViewTest

  alias Towerops.Devices

  setup :register_and_log_in_user

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

    {:ok, site} =
      Towerops.Sites.create_site(%{
        name: "Test Site",
        organization_id: organization.id
      })

    %{organization: organization, site: site}
  end

  describe "index page rendering" do
    test "renders empty state when no devices", %{conn: conn} do
      {:ok, _view, html} = live(conn, ~p"/devices")

      assert html =~ "No devices"
      assert html =~ "New Device"
    end

    test "renders device list with devices", %{conn: conn, site: site, organization: organization} do
      {:ok, _device} =
        Devices.create_device(%{
          name: "Test Router",
          ip_address: "192.168.1.1",
          site_id: site.id,
          organization_id: organization.id
        })

      {:ok, _view, html} = live(conn, ~p"/devices")

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

    test "renders site headers with device stats", %{conn: conn, site: site, organization: organization} do
      {:ok, _device} =
        Devices.create_device(%{
          name: "Router 1",
          ip_address: "192.168.1.1",
          site_id: site.id,
          organization_id: organization.id
        })

      {:ok, _view, html} = live(conn, ~p"/devices")

      assert html =~ "Test Site"
      assert html =~ "1 device"
    end
  end

  describe "real-time updates via PubSub" do
    test "updates when a new device is created", %{conn: conn, site: site, organization: organization} do
      {:ok, view, html} = live(conn, ~p"/devices")

      assert html =~ "No devices"

      # Create a device (triggers PubSub broadcast)
      {:ok, _device} =
        Devices.create_device(%{
          name: "New Router",
          ip_address: "192.168.1.1",
          site_id: site.id,
          organization_id: organization.id
        })

      # LiveView should receive PubSub event and re-render
      html = render(view)
      assert html =~ "New Router"
      assert html =~ "192.168.1.1"
    end

    test "updates when a device is modified", %{conn: conn, site: site, organization: organization} do
      {:ok, device} =
        Devices.create_device(%{
          name: "Old Name",
          ip_address: "192.168.1.1",
          site_id: site.id,
          organization_id: organization.id
        })

      {:ok, view, html} = live(conn, ~p"/devices")

      assert html =~ "Old Name"

      {:ok, _updated} = Devices.update_device(device, %{name: "New Name"})

      html = render(view)
      assert html =~ "New Name"
    end

    test "updates when a device status changes", %{conn: conn, site: site, organization: organization} do
      {:ok, device} =
        Devices.create_device(%{
          name: "Status Router",
          ip_address: "192.168.1.1",
          site_id: site.id,
          organization_id: organization.id
        })

      {:ok, view, _html} = live(conn, ~p"/devices")

      {:ok, _updated} = Devices.update_device_status(device, :up)

      html = render(view)
      assert html =~ "UP"
    end

    test "updates when a device is deleted", %{conn: conn, site: site, organization: organization} do
      {:ok, device} =
        Devices.create_device(%{
          name: "Delete Me",
          ip_address: "192.168.1.1",
          site_id: site.id,
          organization_id: organization.id
        })

      {:ok, view, html} = live(conn, ~p"/devices")

      assert html =~ "Delete Me"

      {:ok, _deleted} = Devices.delete_device(device)

      html = render(view)
      refute html =~ "Delete Me"
      assert html =~ "No devices"
    end

    test "updates device quota after changes", %{conn: conn, site: site, organization: organization} do
      {:ok, view, _html} = live(conn, ~p"/devices")

      {:ok, _device} =
        Devices.create_device(%{
          name: "Quota Router",
          ip_address: "192.168.1.1",
          site_id: site.id,
          organization_id: organization.id
        })

      html = render(view)
      assert html =~ "1/10 devices"
    end
  end

  describe "tick timer" do
    test "tick refreshes device stream on existing tab", %{conn: conn, site: site, organization: organization} do
      {:ok, device} =
        Devices.create_device(%{
          name: "Tick Router",
          ip_address: "192.168.1.1",
          site_id: site.id,
          organization_id: organization.id
        })

      {:ok, view, _html} = live(conn, ~p"/devices")

      # Update device status directly in DB (no broadcast)
      {:ok, _} =
        device
        |> Ecto.Changeset.change(%{status: :up})
        |> Towerops.Repo.update()

      # Send tick to trigger reload
      send(view.pid, :tick)

      html = render(view)
      assert html =~ "UP"
    end

    test "tick does not reload on discovered tab", %{conn: conn} do
      {:ok, view, _html} = live(conn, ~p"/devices?tab=discovered")

      # Send tick - should not crash or error
      send(view.pid, :tick)

      html = render(view)
      assert html =~ "Discovered"
    end
  end

  describe "site header enrichment" do
    test "shows subscriber count on site header when Gaiia mapped", %{
      conn: conn,
      site: site,
      organization: organization
    } do
      {:ok, _device} =
        Devices.create_device(%{
          name: "Router",
          ip_address: "192.168.1.1",
          site_id: site.id,
          organization_id: organization.id
        })

      {:ok, _} =
        Towerops.Gaiia.upsert_network_site(organization.id, %{
          gaiia_id: "ns-dev-list",
          name: "Tower",
          account_count: 55,
          total_mrr: Decimal.new("2750.00"),
          site_id: site.id
        })

      {:ok, _view, html} = live(conn, ~p"/devices")

      assert html =~ "55 subscribers"
    end

    test "hides subscriber count when no Gaiia mapping", %{
      conn: conn,
      site: site,
      organization: organization
    } do
      {:ok, _device} =
        Devices.create_device(%{
          name: "Router",
          ip_address: "192.168.1.1",
          site_id: site.id,
          organization_id: organization.id
        })

      {:ok, _view, html} = live(conn, ~p"/devices")

      refute html =~ "subscribers"
    end
  end

  describe "discovered tab" do
    test "renders discovered devices tab", %{conn: conn} do
      {:ok, _view, html} = live(conn, ~p"/devices?tab=discovered")

      assert html =~ "Discovered"
    end

    test "renders discovered tab with pagination", %{conn: conn} do
      {:ok, _view, html} = live(conn, ~p"/devices?tab=discovered&page=1")

      assert html =~ "Discovered"
    end
  end

  describe "device management events" do
    test "toggles reorder mode", %{conn: conn, site: site, organization: organization} do
      {:ok, _device} =
        Devices.create_device(%{
          name: "Router",
          ip_address: "192.168.1.1",
          site_id: site.id,
          organization_id: organization.id
        })

      {:ok, view, _html} = live(conn, ~p"/devices")

      html = render_click(view, "toggle_reorder_mode")
      assert html =~ "Reset Order"
    end

    test "resets device order", %{conn: conn, site: site, organization: organization} do
      {:ok, _device} =
        Devices.create_device(%{
          name: "Router",
          ip_address: "192.168.1.1",
          site_id: site.id,
          organization_id: organization.id
        })

      {:ok, view, _html} = live(conn, ~p"/devices")

      html = render_click(view, "reset_order")
      assert html =~ "Order reset to alphabetical"
    end

    test "force_rediscover_all with no SNMP devices shows error", %{conn: conn, site: site, organization: organization} do
      {:ok, _device} =
        Devices.create_device(%{
          name: "Router",
          ip_address: "192.168.1.1",
          site_id: site.id,
          organization_id: organization.id,
          snmp_enabled: false
        })

      {:ok, view, _html} = live(conn, ~p"/devices")

      html = render_click(view, "force_rediscover_all")
      assert html =~ "No SNMP-enabled devices found"
    end

    test "reorder_device with invalid device_id shows error", %{conn: conn} do
      {:ok, view, _html} = live(conn, ~p"/devices")

      html =
        render_click(view, "reorder_device", %{
          "device_id" => Ecto.UUID.generate(),
          "new_position" => "1"
        })

      assert html =~ "not found"
    end

    test "reorder_site with invalid site_id shows error", %{conn: conn} do
      {:ok, view, _html} = live(conn, ~p"/devices")

      html =
        render_click(view, "reorder_site", %{
          "site_id" => Ecto.UUID.generate(),
          "new_position" => "1"
        })

      assert html =~ "not found"
    end
  end
end
