defmodule Microwaveprop.Weather.SoundingTest do
  use Microwaveprop.DataCase, async: true

  alias Microwaveprop.Weather.Sounding
  alias Microwaveprop.Weather.Station

  defp create_sounding_station do
    %Station{}
    |> Station.changeset(%{
      station_code: "FWD",
      station_type: "sounding",
      wmo_number: 72_249,
      name: "Fort Worth",
      lat: 32.83,
      lon: -97.30
    })
    |> Repo.insert!()
  end

  @sample_profile [
    %{"pres" => 1013.0, "hght" => 171, "tmpc" => 25.0, "dwpc" => 15.0, "drct" => 180, "sknt" => 10},
    %{"pres" => 925.0, "hght" => 800, "tmpc" => 20.0, "dwpc" => 12.0, "drct" => 200, "sknt" => 15},
    %{"pres" => 850.0, "hght" => 1500, "tmpc" => 15.0, "dwpc" => 8.0, "drct" => 220, "sknt" => 20}
  ]

  @valid_sounding_attrs %{
    observed_at: ~U[2026-03-28 12:00:00Z],
    profile: @sample_profile,
    level_count: 3,
    surface_pressure_mb: 1013.0,
    surface_temp_c: 25.0,
    surface_dewpoint_c: 15.0,
    surface_refractivity: 320.5,
    min_refractivity_gradient: -45.0,
    boundary_layer_depth_m: 1200.0,
    precipitable_water_mm: 25.0,
    k_index: 28.0,
    lifted_index: -2.0,
    ducting_detected: false,
    duct_characteristics: nil
  }

  describe "changeset/2" do
    test "valid attributes with station_id" do
      station = create_sounding_station()
      attrs = Map.put(@valid_sounding_attrs, :station_id, station.id)
      changeset = Sounding.changeset(%Sounding{}, attrs)
      assert changeset.valid?
    end

    test "requires station_id, observed_at, profile, level_count" do
      changeset = Sounding.changeset(%Sounding{}, %{})

      assert %{
               station_id: ["can't be blank"],
               observed_at: ["can't be blank"],
               profile: ["can't be blank"],
               level_count: ["can't be blank"]
             } = errors_on(changeset)
    end

    test "derived params are optional" do
      station = create_sounding_station()

      attrs = %{
        station_id: station.id,
        observed_at: ~U[2026-03-28 12:00:00Z],
        profile: @sample_profile,
        level_count: 3
      }

      changeset = Sounding.changeset(%Sounding{}, attrs)
      assert changeset.valid?
    end

    test "persists to the database with JSONB profile" do
      station = create_sounding_station()
      attrs = Map.put(@valid_sounding_attrs, :station_id, station.id)
      changeset = Sounding.changeset(%Sounding{}, attrs)
      assert {:ok, sounding} = Repo.insert(changeset)
      assert length(sounding.profile) == 3
      assert hd(sounding.profile)["pres"] == 1013.0
      assert sounding.ducting_detected == false
      assert sounding.k_index == 28.0
    end

    test "persists duct_characteristics as JSONB" do
      station = create_sounding_station()

      duct_chars = [
        %{"base" => 200, "top" => 500, "strength" => "5.2"}
      ]

      attrs =
        @valid_sounding_attrs
        |> Map.put(:station_id, station.id)
        |> Map.put(:ducting_detected, true)
        |> Map.put(:duct_characteristics, duct_chars)

      changeset = Sounding.changeset(%Sounding{}, attrs)
      assert {:ok, sounding} = Repo.insert(changeset)
      assert sounding.ducting_detected == true
      assert [%{"base" => 200, "top" => 500}] = sounding.duct_characteristics
    end

    test "enforces unique station_id + observed_at" do
      station = create_sounding_station()
      attrs = Map.put(@valid_sounding_attrs, :station_id, station.id)

      assert {:ok, _} = %Sounding{} |> Sounding.changeset(attrs) |> Repo.insert()
      assert {:error, changeset} = %Sounding{} |> Sounding.changeset(attrs) |> Repo.insert()
      assert %{station_id: ["has already been taken"]} = errors_on(changeset)
    end
  end
end
