defmodule ToweropsWeb.GraphLive.ShowTest do
  use ToweropsWeb.ConnCase

  import Phoenix.LiveViewTest

  alias Towerops.Monitoring
  alias Towerops.Organizations
  alias Towerops.Sites
  alias Towerops.Snmp

  setup :register_and_log_in_user

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

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

    {:ok, device} =
      Towerops.Devices.create_device(%{
        name: "Test Router",
        ip_address: "192.168.1.1",
        site_id: site.id,
        snmp_enabled: true
      })

    # Create SNMP device for sensor tests
    {:ok, snmp_device} =
      Snmp.create_snmp_device(%{
        device_id: device.id,
        sys_name: "test-router",
        sys_descr: "Test Router",
        sys_object_id: "1.3.6.1.4.1.9"
      })

    %{organization: organization, site: site, device: device, snmp_device: snmp_device}
  end

  describe "Latency graph" do
    test "renders latency graph page with correct assigns", %{
      conn: conn,
      device: device,
      organization: org
    } do
      # Create monitoring checks
      Monitoring.create_check(%{
        device_id: device.id,
        status: :success,
        response_time_ms: 10.5,
        checked_at: DateTime.utc_now()
      })

      {:ok, view, html} = live(conn, ~p"/orgs/#{org.slug}/devices/#{device.id}/graph/latency")

      # Verify page renders
      assert html =~ "ICMP Latency"
      assert html =~ device.name

      # Verify correct assigns are set
      assert view.assigns.current_organization.id == org.id
      assert view.assigns.device_id == device.id
      assert view.assigns.sensor_type == "latency"
      assert view.assigns.range == "24h"
    end

    test "uses current_organization in back link", %{
      conn: conn,
      device: device,
      organization: org
    } do
      {:ok, _view, html} = live(conn, ~p"/orgs/#{org.slug}/devices/#{device.id}/graph/latency")

      # Verify back link uses organization slug (this was the bug)
      assert html =~ ~s[/orgs/#{org.slug}/devices/#{device.id}]
    end

    test "displays empty state when no latency data", %{
      conn: conn,
      device: device,
      organization: org
    } do
      {:ok, _view, html} = live(conn, ~p"/orgs/#{org.slug}/devices/#{device.id}/graph/latency")

      assert html =~ "No sensor data available"
    end
  end

  describe "Processor graph" do
    test "renders processor graph page", %{
      conn: conn,
      device: device,
      organization: org,
      snmp_device: snmp_device
    } do
      # Create a CPU sensor
      {:ok, sensor} =
        Snmp.create_sensor(%{
          snmp_device_id: snmp_device.id,
          sensor_type: "cpu_load",
          sensor_index: 1,
          sensor_descr: "CPU 1",
          sensor_unit: "%"
        })

      # Create sensor reading
      Snmp.create_sensor_reading(%{
        sensor_id: sensor.id,
        value: 45.2,
        checked_at: DateTime.utc_now()
      })

      {:ok, view, html} =
        live(conn, ~p"/orgs/#{org.slug}/devices/#{device.id}/graph/processors")

      assert html =~ "Processor Usage"
      assert html =~ device.name

      # Verify correct assigns
      assert view.assigns.current_organization.id == org.id
      assert view.assigns.sensor_type == "processors"
      assert view.assigns.unit == "%"
    end
  end

  describe "Memory graph" do
    test "renders memory graph page", %{
      conn: conn,
      device: device,
      organization: org,
      snmp_device: snmp_device
    } do
      # Create a memory sensor
      {:ok, sensor} =
        Snmp.create_sensor(%{
          snmp_device_id: snmp_device.id,
          sensor_type: "memory_usage",
          sensor_index: 1,
          sensor_descr: "Memory",
          sensor_unit: "%"
        })

      # Create sensor reading
      Snmp.create_sensor_reading(%{
        sensor_id: sensor.id,
        value: 75.5,
        checked_at: DateTime.utc_now()
      })

      {:ok, view, html} = live(conn, ~p"/orgs/#{org.slug}/devices/#{device.id}/graph/memory")

      assert html =~ "Memory Usage"
      assert html =~ device.name

      # Verify correct assigns
      assert view.assigns.current_organization.id == org.id
      assert view.assigns.sensor_type == "memory"
      assert view.assigns.unit == "%"
    end
  end

  describe "Traffic graph" do
    test "renders overall traffic graph page", %{
      conn: conn,
      device: device,
      organization: org,
      snmp_device: snmp_device
    } do
      # Create an interface
      {:ok, interface} =
        Snmp.create_interface(%{
          snmp_device_id: snmp_device.id,
          if_index: 1,
          if_descr: "eth0",
          if_name: "eth0",
          if_oper_status: "up",
          if_speed: 1_000_000_000
        })

      # Create interface stats
      Snmp.create_interface_stat(%{
        interface_id: interface.id,
        if_in_octets: 1000,
        if_out_octets: 2000,
        checked_at: DateTime.utc_now()
      })

      {:ok, view, html} = live(conn, ~p"/orgs/#{org.slug}/devices/#{device.id}/graph/traffic")

      assert html =~ "Overall Traffic"
      assert html =~ device.name

      # Verify correct assigns
      assert view.assigns.current_organization.id == org.id
      assert view.assigns.sensor_type == "traffic"
      assert view.assigns.unit == "bps"
      assert view.assigns.show_zero_line == true
    end

    test "renders specific interface traffic graph", %{
      conn: conn,
      device: device,
      organization: org,
      snmp_device: snmp_device
    } do
      # Create an interface
      {:ok, interface} =
        Snmp.create_interface(%{
          snmp_device_id: snmp_device.id,
          if_index: 1,
          if_descr: "eth0",
          if_name: "eth0",
          if_oper_status: "up",
          if_speed: 1_000_000_000
        })

      # Create interface stats
      Snmp.create_interface_stat(%{
        interface_id: interface.id,
        if_in_octets: 1000,
        if_out_octets: 2000,
        checked_at: DateTime.utc_now()
      })

      {:ok, view, html} =
        live(
          conn,
          ~p"/orgs/#{org.slug}/devices/#{device.id}/graph/traffic?interface_id=#{interface.id}"
        )

      assert html =~ "Overall Traffic"
      assert html =~ device.name

      # Verify correct assigns including interface_id
      assert view.assigns.current_organization.id == org.id
      assert view.assigns.interface_id == interface.id
    end
  end

  describe "Time range selection" do
    test "defaults to 24h range", %{conn: conn, device: device, organization: org} do
      {:ok, view, _html} = live(conn, ~p"/orgs/#{org.slug}/devices/#{device.id}/graph/latency")

      assert view.assigns.range == "24h"
    end

    test "accepts custom range parameter", %{conn: conn, device: device, organization: org} do
      {:ok, view, _html} =
        live(conn, ~p"/orgs/#{org.slug}/devices/#{device.id}/graph/latency?range=1h")

      assert view.assigns.range == "1h"
    end

    test "changes range when user clicks range button", %{
      conn: conn,
      device: device,
      organization: org
    } do
      {:ok, view, _html} = live(conn, ~p"/orgs/#{org.slug}/devices/#{device.id}/graph/latency")

      # Initially 24h
      assert view.assigns.range == "24h"

      # Change to 1h
      view
      |> element("button", "1 Hour")
      |> render_click()

      assert view.assigns.range == "1h"
    end

    test "preserves interface_id when changing range", %{
      conn: conn,
      device: device,
      organization: org,
      snmp_device: snmp_device
    } do
      # Create an interface
      {:ok, interface} =
        Snmp.create_interface(%{
          snmp_device_id: snmp_device.id,
          if_index: 1,
          if_descr: "eth0",
          if_name: "eth0",
          if_oper_status: "up",
          if_speed: 1_000_000_000
        })

      {:ok, view, _html} =
        live(
          conn,
          ~p"/orgs/#{org.slug}/devices/#{device.id}/graph/traffic?interface_id=#{interface.id}"
        )

      # Change range
      view
      |> element("button", "1 Hour")
      |> render_click()

      # Interface ID should be preserved
      assert view.assigns.interface_id == interface.id
      assert view.assigns.range == "1h"
    end
  end

  describe "Assign validation" do
    test "ensures current_organization assign exists, not organization", %{
      conn: conn,
      device: device,
      organization: org
    } do
      {:ok, view, _html} = live(conn, ~p"/orgs/#{org.slug}/devices/#{device.id}/graph/latency")

      # current_organization should exist
      assert Map.has_key?(view.assigns, :current_organization)
      assert view.assigns.current_organization.id == org.id

      # organization should NOT exist (this was the bug)
      refute Map.has_key?(view.assigns, :organization)
    end

    test "has all required assigns for rendering", %{
      conn: conn,
      device: device,
      organization: org
    } do
      {:ok, view, _html} = live(conn, ~p"/orgs/#{org.slug}/devices/#{device.id}/graph/latency")

      # All required assigns should be present
      assert Map.has_key?(view.assigns, :current_organization)
      assert Map.has_key?(view.assigns, :device)
      assert Map.has_key?(view.assigns, :device_id)
      assert Map.has_key?(view.assigns, :sensor_type)
      assert Map.has_key?(view.assigns, :range)
      assert Map.has_key?(view.assigns, :chart_title)
      assert Map.has_key?(view.assigns, :unit)
      assert Map.has_key?(view.assigns, :auto_scale)
      assert Map.has_key?(view.assigns, :show_zero_line)
    end
  end
end
