defmodule Microwaveprop.Backtest.FeaturesTest do
  use Microwaveprop.DataCase, async: true

  alias Microwaveprop.Backtest.Features
  alias Microwaveprop.Weather
  alias Microwaveprop.Weather.HrrrNativeProfile

  @point_lat 32.9
  @point_lon -97.0
  @valid_time ~U[2026-03-28 18:00:00Z]

  defp create_profile(attrs) do
    base = %{
      valid_time: @valid_time,
      lat: @point_lat,
      lon: @point_lon
    }

    {:ok, _} = Weather.upsert_hrrr_profile(Map.merge(base, attrs))
  end

  describe "naive_gradient/3" do
    test "returns the nearest profile's min_refractivity_gradient" do
      create_profile(%{min_refractivity_gradient: -250.0})
      assert Features.naive_gradient(@point_lat, @point_lon, @valid_time) == -250.0
    end

    test "returns nil when no profile is within match window" do
      assert Features.naive_gradient(@point_lat, @point_lon, @valid_time) == nil
    end
  end

  describe "td_depression/3" do
    test "returns surface_temp_c minus surface_dewpoint_c" do
      create_profile(%{surface_temp_c: 20.0, surface_dewpoint_c: 14.0})
      assert Features.td_depression(@point_lat, @point_lon, @valid_time) == 6.0
    end

    test "returns nil when profile has no surface data" do
      create_profile(%{surface_temp_c: nil, surface_dewpoint_c: nil})
      assert Features.td_depression(@point_lat, @point_lon, @valid_time) == nil
    end
  end

  describe "time_of_day/3" do
    test "returns UTC hour + minute fraction and never calls the database" do
      assert Features.time_of_day(0.0, 0.0, ~U[2026-01-01 06:30:00Z]) == 6.5
      assert Features.time_of_day(0.0, 0.0, ~U[2026-01-01 00:00:00Z]) == 0.0
      assert Features.time_of_day(0.0, 0.0, ~U[2026-01-01 23:45:00Z]) == 23.75
    end
  end

  describe "pressure/3" do
    test "returns surface_pressure_mb from the nearest profile" do
      create_profile(%{surface_pressure_mb: 1013.2})
      assert Features.pressure(@point_lat, @point_lon, @valid_time) == 1013.2
    end

    test "returns nil when no profile exists" do
      assert Features.pressure(@point_lat, @point_lon, @valid_time) == nil
    end
  end

  describe "native_surface_refractivity/3" do
    test "computes N-units from native profile surface scalars" do
      {:ok, _} =
        %HrrrNativeProfile{}
        |> HrrrNativeProfile.changeset(%{
          valid_time: @valid_time,
          lat: @point_lat,
          lon: @point_lon,
          level_count: 1,
          heights_m: [10.0],
          temp_k: [295.0],
          spfh: [0.010],
          pressure_pa: [101_325.0],
          u_wind_ms: [2.0],
          v_wind_ms: [1.0],
          tke_m2s2: [0.5],
          surface_temp_k: 295.0,
          surface_spfh: 0.010,
          surface_pressure_pa: 101_325.0
        })
        |> Repo.insert()

      result = Features.native_surface_refractivity(@point_lat, @point_lon, @valid_time)
      assert is_float(result)
      # Typical surface N is 250-400 in temperate latitudes
      assert result > 200.0 and result < 500.0
    end

    test "returns nil when no native profile exists" do
      assert Features.native_surface_refractivity(@point_lat, @point_lon, @valid_time) == nil
    end
  end
end
