defmodule Microwaveprop.CommercialTest do
  use Microwaveprop.DataCase, async: true

  alias Microwaveprop.Commercial
  alias Microwaveprop.Commercial.Link

  setup do
    Repo.delete_all(Link)
    :ok
  end

  @link_attrs %{
    label: "test-link",
    host: "10.0.0.1",
    community: "public",
    radio_type: "af11x",
    weather_station: "KTKI",
    enabled: true
  }

  describe "enabled_links/0" do
    test "returns only enabled links" do
      {:ok, _enabled} = Commercial.create_link(@link_attrs)

      {:ok, _disabled} =
        Commercial.create_link(%{@link_attrs | label: "disabled-link", enabled: false})

      links = Commercial.enabled_links()
      assert length(links) == 1
      assert hd(links).label == "test-link"
    end

    test "returns empty list when no enabled links" do
      assert Commercial.enabled_links() == []
    end
  end

  describe "create_link/1" do
    test "creates a link with valid attrs" do
      assert {:ok, link} = Commercial.create_link(@link_attrs)
      assert link.label == "test-link"
      assert link.enabled == true
    end

    test "returns error for invalid attrs" do
      assert {:error, _changeset} = Commercial.create_link(%{})
    end
  end

  describe "create_sample/1" do
    test "creates a sample for a link" do
      {:ok, link} = Commercial.create_link(@link_attrs)

      attrs = %{
        link_id: link.id,
        sampled_at: DateTime.utc_now(),
        rx_power_0: -55.0,
        tx_power: 20.0,
        link_state: 1
      }

      assert {:ok, sample} = Commercial.create_sample(attrs)
      assert sample.rx_power_0 == -55.0
      assert sample.link_id == link.id
    end
  end

  describe "link_degradation_at/3" do
    @endpoint_dfw %{"lat" => 33.2, "lon" => -96.5}
    @far_point {0.0, 0.0}
    @near_point {33.2, -96.5}

    test "returns nil when no links are within the radius" do
      {:ok, _} =
        Commercial.create_link(
          Map.merge(@link_attrs, %{
            endpoint_a: @endpoint_dfw,
            endpoint_b: @endpoint_dfw
          })
        )

      valid_time = ~U[2026-04-13 18:00:00Z]
      assert Commercial.link_degradation_at(@far_point, valid_time, radius_km: 50) == nil
    end

    test "returns nil when the link has no recent baseline samples" do
      {:ok, _link} =
        Commercial.create_link(Map.merge(@link_attrs, %{endpoint_a: @endpoint_dfw, endpoint_b: @endpoint_dfw}))

      valid_time = ~U[2026-04-13 18:00:00Z]
      assert Commercial.link_degradation_at(@near_point, valid_time) == nil
    end

    test "returns positive degradation when current rx_power is below baseline" do
      {:ok, link} =
        Commercial.create_link(Map.merge(@link_attrs, %{endpoint_a: @endpoint_dfw, endpoint_b: @endpoint_dfw}))

      valid_time = ~U[2026-04-13 18:00:00Z]

      # 7-day baseline: -52 dBm average
      for day_offset <- 1..6 do
        {:ok, _} =
          Commercial.create_sample(%{
            link_id: link.id,
            sampled_at: DateTime.add(valid_time, -day_offset * 3600 * 24, :second),
            rx_power_0: -52.0,
            rx_power_1: -52.0,
            link_state: 1
          })
      end

      # Current (within 15 min) drops to -62 — 10 dB deep fade.
      {:ok, _} =
        Commercial.create_sample(%{
          link_id: link.id,
          sampled_at: DateTime.add(valid_time, -300, :second),
          rx_power_0: -62.0,
          rx_power_1: -62.0,
          link_state: 1
        })

      result = Commercial.link_degradation_at(@near_point, valid_time)
      assert result
      assert_in_delta result.degradation_db, 10.0, 0.5
      assert result.n_links == 1
    end

    test "returns 0 degradation when rx_power matches baseline" do
      {:ok, link} =
        Commercial.create_link(Map.merge(@link_attrs, %{endpoint_a: @endpoint_dfw, endpoint_b: @endpoint_dfw}))

      valid_time = ~U[2026-04-13 18:00:00Z]

      for day_offset <- 1..6 do
        {:ok, _} =
          Commercial.create_sample(%{
            link_id: link.id,
            sampled_at: DateTime.add(valid_time, -day_offset * 3600 * 24, :second),
            rx_power_0: -55.0,
            link_state: 1
          })
      end

      {:ok, _} =
        Commercial.create_sample(%{
          link_id: link.id,
          sampled_at: DateTime.add(valid_time, -60, :second),
          rx_power_0: -55.0,
          link_state: 1
        })

      result = Commercial.link_degradation_at(@near_point, valid_time)
      assert result
      assert_in_delta result.degradation_db, 0.0, 0.5
    end

    test "ignores links with link_state != 1 (down link isn't tropo)" do
      {:ok, link} =
        Commercial.create_link(Map.merge(@link_attrs, %{endpoint_a: @endpoint_dfw, endpoint_b: @endpoint_dfw}))

      valid_time = ~U[2026-04-13 18:00:00Z]

      for day_offset <- 1..6 do
        {:ok, _} =
          Commercial.create_sample(%{
            link_id: link.id,
            sampled_at: DateTime.add(valid_time, -day_offset * 3600 * 24, :second),
            rx_power_0: -52.0,
            link_state: 1
          })
      end

      {:ok, _} =
        Commercial.create_sample(%{
          link_id: link.id,
          sampled_at: DateTime.add(valid_time, -120, :second),
          rx_power_0: -90.0,
          link_state: 0
        })

      assert Commercial.link_degradation_at(@near_point, valid_time) == nil
    end
  end

  describe "weather_stations/0" do
    test "returns unique weather stations from enabled links" do
      {:ok, _} = Commercial.create_link(@link_attrs)

      {:ok, _} =
        Commercial.create_link(%{@link_attrs | label: "link-2", host: "10.0.0.2"})

      {:ok, _} =
        Commercial.create_link(%{
          @link_attrs
          | label: "link-3",
            host: "10.0.0.3",
            weather_station: "KDFW"
        })

      stations = Commercial.weather_stations()
      assert Enum.sort(stations) == ["KDFW", "KTKI"]
    end

    test "excludes disabled links" do
      {:ok, _} = Commercial.create_link(%{@link_attrs | enabled: false})

      assert Commercial.weather_stations() == []
    end

    test "excludes nil weather stations" do
      {:ok, _} = Commercial.create_link(%{@link_attrs | weather_station: nil})

      assert Commercial.weather_stations() == []
    end
  end
end
