defmodule Microwaveprop.Weather.HrdpsProfileTest do
  use Microwaveprop.DataCase, async: false

  alias Microwaveprop.Repo
  alias Microwaveprop.Weather.HrdpsProfile

  describe "changeset/2" do
    test "valid with required fields" do
      attrs = %{valid_time: ~U[2026-04-29 12:00:00Z], lat: 53.32, lon: -60.42}
      cs = HrdpsProfile.changeset(%HrdpsProfile{}, attrs)
      assert cs.valid?
    end

    test "rejects missing required fields" do
      cs = HrdpsProfile.changeset(%HrdpsProfile{}, %{})
      refute cs.valid?
      assert %{valid_time: ["can't be blank"]} = errors_on(cs)
      assert %{lat: ["can't be blank"]} = errors_on(cs)
      assert %{lon: ["can't be blank"]} = errors_on(cs)
    end

    test "casts the full set of derived fields" do
      attrs = %{
        valid_time: ~U[2026-04-29 12:00:00Z],
        lat: 53.32,
        lon: -60.42,
        run_time: ~U[2026-04-29 12:00:00Z],
        profile: [%{"pres" => 1000.0, "tmpc" => 12.0, "dwpc" => 7.0, "hght" => 100.0}],
        hpbl_m: 800.0,
        pwat_mm: nil,
        surface_temp_c: 12.0,
        surface_dewpoint_c: 7.0,
        surface_pressure_mb: 1000.0,
        surface_refractivity: 312.0,
        min_refractivity_gradient: -50.0,
        ducting_detected: false,
        duct_characteristics: [],
        is_grid_point: true
      }

      cs = HrdpsProfile.changeset(%HrdpsProfile{}, attrs)
      assert cs.valid?
      assert Ecto.Changeset.get_field(cs, :surface_refractivity) == 312.0
      assert Ecto.Changeset.get_field(cs, :is_grid_point) == true
    end
  end

  describe "persistence" do
    test "inserts and reads back via the partitioned hrdps_profiles table" do
      attrs = %{
        valid_time: ~U[2026-04-29 12:00:00Z],
        lat: 53.32,
        lon: -60.42,
        run_time: ~U[2026-04-29 12:00:00Z],
        surface_temp_c: 7.8
      }

      {:ok, %HrdpsProfile{id: id}} =
        %HrdpsProfile{} |> HrdpsProfile.changeset(attrs) |> Repo.insert()

      reloaded = Repo.get!(HrdpsProfile, id)
      assert reloaded.lat == 53.32
      assert reloaded.surface_temp_c == 7.8
    end

    test "enforces unique constraint on (lat, lon, valid_time) at the DB level" do
      # The partitioned table propagates the unique index per partition, so
      # Postgres rejects duplicate (lat, lon, valid_time) inserts. Schema-
      # level `unique_constraint/2` matching against changeset errors
      # doesn't apply because the partition's index name varies per
      # partition; callers that need upserts go through
      # `on_conflict: {:replace_all_except, ...}` in the worker.
      attrs = %{valid_time: ~U[2026-04-29 12:00:00Z], lat: 53.32, lon: -60.42}

      assert {:ok, _} =
               %HrdpsProfile{} |> HrdpsProfile.changeset(attrs) |> Repo.insert()

      assert_raise Ecto.ConstraintError, fn ->
        %HrdpsProfile{} |> HrdpsProfile.changeset(attrs) |> Repo.insert()
      end
    end
  end
end
