defmodule ToweropsWeb.DashboardLiveTest do
  use ToweropsWeb.ConnCase

  import Phoenix.LiveViewTest

  alias Towerops.Preseem.Insights

  setup :register_and_log_in_user

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

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

    conn = Plug.Conn.put_session(conn, :current_organization_id, organization.id)

    %{conn: conn, organization: organization, site: site}
  end

  describe "empty state" do
    test "shows onboarding when no devices exist", %{conn: conn} do
      {:ok, _view, html} = live(conn, ~p"/dashboard")

      assert html =~ "Let&#39;s get started!"
      assert html =~ "Create Your First Site"
    end

    test "requires authentication" do
      conn = build_conn()
      {:error, redirect} = live(conn, ~p"/dashboard")

      assert {:redirect, %{to: path}} = redirect
      assert path == ~p"/users/log-in"
    end
  end

  describe "health overview" do
    test "displays health score", %{conn: conn, organization: organization, site: site} do
      {:ok, device} = create_device(organization, site)
      Towerops.Devices.update_device_status(device, :up)

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

      assert html =~ "Health Score"
      assert html =~ "100"
    end

    test "displays device counts with up/down/unknown", %{
      conn: conn,
      organization: organization,
      site: site
    } do
      {:ok, d1} = create_device(organization, site, "Router 1", "192.168.1.1")
      {:ok, d2} = create_device(organization, site, "Router 2", "192.168.1.2")
      Towerops.Devices.update_device_status(d1, :up)
      Towerops.Devices.update_device_status(d2, :down)

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

      assert html =~ "Devices"
      assert html =~ "1 Up"
      assert html =~ "1 Down"
    end

    test "displays active alert count", %{conn: conn, organization: organization, site: site} do
      {:ok, device} = create_device(organization, site)

      {:ok, _alert} =
        Towerops.Alerts.create_alert(%{
          device_id: device.id,
          alert_type: :device_down,
          triggered_at: DateTime.utc_now(),
          message: "Device is down"
        })

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

      assert html =~ "Active Alerts"
      assert html =~ "1"
    end

    test "displays insight counts by urgency", %{
      conn: conn,
      organization: organization,
      site: site
    } do
      {:ok, device} = create_device(organization, site)

      {:ok, _} =
        Insights.insert_insight_if_new(%{
          organization_id: organization.id,
          device_id: device.id,
          type: "device_poll_gap",
          source: "snmp",
          urgency: "warning",
          channel: "proactive",
          title: "Device not polled"
        })

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

      assert html =~ "Insights"
    end

    test "hides subscriber section when no Gaiia integration", %{
      conn: conn,
      organization: organization,
      site: site
    } do
      {:ok, _device} = create_device(organization, site)

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

      refute html =~ "Subscribers"
      refute html =~ "MRR"
    end

    test "shows subscriber section when Gaiia data exists", %{
      conn: conn,
      organization: organization,
      site: site
    } do
      {:ok, _device} = create_device(organization, site)

      {:ok, _} =
        Towerops.Gaiia.upsert_network_site(organization.id, %{
          gaiia_id: "ns-dash",
          name: "Tower",
          account_count: 100,
          total_mrr: Decimal.new("5000.00")
        })

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

      assert html =~ "Subscribers"
      assert html =~ "100"
      assert html =~ "5,000"
    end
  end

  describe "alert feed" do
    test "shows alerts with device links", %{conn: conn, organization: organization, site: site} do
      {:ok, device} = create_device(organization, site, "Main Router", "10.0.0.1")
      Towerops.Devices.update_device_status(device, :down)

      {:ok, _alert} =
        Towerops.Alerts.create_alert(%{
          device_id: device.id,
          alert_type: :device_down,
          triggered_at: DateTime.utc_now(),
          message: "Device is unreachable"
        })

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

      assert html =~ "Main Router"
      assert html =~ "Device is unreachable"
      assert html =~ ~p"/devices/#{device.id}"
    end

    test "shows View All link when alerts exist", %{
      conn: conn,
      organization: organization,
      site: site
    } do
      {:ok, device} = create_device(organization, site)

      {:ok, _alert} =
        Towerops.Alerts.create_alert(%{
          device_id: device.id,
          alert_type: :device_down,
          triggered_at: DateTime.utc_now(),
          message: "Device is down"
        })

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

      assert html =~ "View All"
    end

    test "shows acknowledge button for unacknowledged alerts", %{
      conn: conn,
      organization: organization,
      site: site
    } do
      {:ok, device} = create_device(organization, site)

      {:ok, _alert} =
        Towerops.Alerts.create_alert(%{
          device_id: device.id,
          alert_type: :device_down,
          triggered_at: DateTime.utc_now(),
          message: "Device is down"
        })

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

      assert html =~ "Acknowledge"
    end
  end

  describe "insight feed" do
    test "shows insights from multiple sources", %{
      conn: conn,
      organization: organization,
      site: site
    } do
      {:ok, device} = create_device(organization, site)

      {:ok, _} =
        Insights.insert_insight_if_new(%{
          organization_id: organization.id,
          device_id: device.id,
          type: "device_poll_gap",
          source: "snmp",
          urgency: "warning",
          channel: "proactive",
          title: "Device not polled in 24h"
        })

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

      assert html =~ "Device not polled in 24h"
      assert html =~ "snmp"
    end

    test "dismiss insight removes it from feed", %{
      conn: conn,
      organization: organization,
      site: site
    } do
      {:ok, device} = create_device(organization, site)

      {:ok, insight} =
        Insights.insert_insight_if_new(%{
          organization_id: organization.id,
          device_id: device.id,
          type: "device_poll_gap",
          source: "snmp",
          urgency: "warning",
          channel: "proactive",
          title: "Poll gap detected"
        })

      {:ok, view, html} = live(conn, ~p"/dashboard")
      assert html =~ "Poll gap detected"

      view |> element("#dismiss-insight-#{insight.id}") |> render_click()

      html = render(view)
      refute html =~ "Poll gap detected"
    end

    test "source filter filters insights via URL", %{
      conn: conn,
      organization: organization,
      site: site
    } do
      {:ok, device} = create_device(organization, site)

      {:ok, _} =
        Insights.insert_insight_if_new(%{
          organization_id: organization.id,
          device_id: device.id,
          type: "device_poll_gap",
          source: "snmp",
          urgency: "warning",
          channel: "proactive",
          title: "SNMP insight"
        })

      {:ok, _} =
        Insights.insert_insight_if_new(%{
          organization_id: organization.id,
          device_id: device.id,
          type: "reconciliation_finding",
          source: "gaiia",
          urgency: "info",
          channel: "proactive",
          title: "Gaiia insight",
          dedup_key: "test_dedup",
          metadata: %{"dedup_key" => "test_dedup"}
        })

      {:ok, view, _html} = live(conn, ~p"/dashboard?insight_source=snmp")

      html = render(view)
      assert html =~ "SNMP insight"
      refute html =~ "Gaiia insight"
    end
  end

  describe "site health grid" do
    test "shows site cards with device counts", %{
      conn: conn,
      organization: organization,
      site: site
    } do
      {:ok, device} = create_device(organization, site)
      Towerops.Devices.update_device_status(device, :up)

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

      assert html =~ "Test Site"
      assert html =~ ~p"/sites/#{site.id}"
    end

    test "shows subscriber data on site cards when Gaiia mapped", %{
      conn: conn,
      organization: organization,
      site: site
    } do
      {:ok, device} = create_device(organization, site)
      Towerops.Devices.update_device_status(device, :up)

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

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

      assert html =~ "42"
    end
  end

  describe "real-time updates" do
    test "PubSub new alert event updates dashboard", %{
      conn: conn,
      organization: organization,
      site: site
    } do
      {:ok, device} = create_device(organization, site)

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

      # Create alert and broadcast
      {:ok, _alert} =
        Towerops.Alerts.create_alert(%{
          device_id: device.id,
          alert_type: :device_down,
          triggered_at: DateTime.utc_now(),
          message: "Device went down"
        })

      Phoenix.PubSub.broadcast(
        Towerops.PubSub,
        "alerts:org:#{organization.id}:new",
        {:new_alert, device.id, :device_down}
      )

      html = render(view)
      assert html =~ "Device went down"
    end

    test "PubSub alert resolved event updates dashboard", %{
      conn: conn,
      organization: organization,
      site: site
    } do
      {:ok, device} = create_device(organization, site)

      {:ok, alert} =
        Towerops.Alerts.create_alert(%{
          device_id: device.id,
          alert_type: :device_down,
          triggered_at: DateTime.utc_now(),
          message: "Device went down"
        })

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

      # Resolve the alert
      Towerops.Alerts.resolve_alert(alert)

      Phoenix.PubSub.broadcast(
        Towerops.PubSub,
        "alerts:org:#{organization.id}:resolved",
        {:alert_resolved, device.id, :device_down}
      )

      html = render(view)
      refute html =~ "Device went down"
    end
  end

  defp create_device(organization, site, name \\ "Test Device", ip \\ "192.168.1.1") do
    Towerops.Devices.create_device(%{
      name: name,
      ip_address: ip,
      site_id: site.id,
      organization_id: organization.id
    })
  end
end
