defmodule Microwaveprop.Rover.FixedStationTest do
  use Microwaveprop.DataCase, async: true

  import Microwaveprop.AccountsFixtures

  alias Microwaveprop.Rover.FixedStation

  describe "changeset/2" do
    test "with grid only derives lat/lon from Maidenhead" do
      cs = FixedStation.changeset(%FixedStation{}, %{callsign: "W5LUA", grid: "EM13qc"})
      assert cs.valid?
      lat = Ecto.Changeset.get_field(cs, :lat)
      lon = Ecto.Changeset.get_field(cs, :lon)
      assert_in_delta lat, 33.10, 0.05
      assert_in_delta lon, -96.625, 0.05
    end

    test "with explicit lat/lon only is valid without grid derivation" do
      cs = FixedStation.changeset(%FixedStation{}, %{callsign: "W5HN", lat: 33.27, lon: -96.875})
      assert cs.valid?
      assert Ecto.Changeset.get_field(cs, :lat) == 33.27
      assert Ecto.Changeset.get_field(cs, :lon) == -96.875
      assert Ecto.Changeset.get_field(cs, :grid) == nil
    end

    test "with neither grid nor lat/lon is invalid" do
      cs = FixedStation.changeset(%FixedStation{}, %{callsign: "N5XU"})
      refute cs.valid?
      assert %{lat: _} = errors_on(cs)
    end

    test "callsign normalised to uppercase + trimmed" do
      cs = FixedStation.changeset(%FixedStation{}, %{callsign: "  w5lua  ", lat: 33.1, lon: -96.6})
      assert cs.valid?
      assert Ecto.Changeset.get_field(cs, :callsign) == "W5LUA"
    end

    test "grid em13QC normalised to EM13qc" do
      cs = FixedStation.changeset(%FixedStation{}, %{callsign: "W5LUA", grid: "em13QC"})
      assert cs.valid?
      assert Ecto.Changeset.get_field(cs, :grid) == "EM13qc"
    end

    test "invalid grid ZZ99zz is rejected" do
      cs = FixedStation.changeset(%FixedStation{}, %{callsign: "W5LUA", grid: "ZZ99zz"})
      refute cs.valid?
      assert %{grid: _} = errors_on(cs)
    end

    test "lat out of range is invalid" do
      cs = FixedStation.changeset(%FixedStation{}, %{callsign: "W5LUA", lat: 100.0, lon: -96.6})
      refute cs.valid?
      assert %{lat: _} = errors_on(cs)
    end

    test "unique constraint on (user_id, callsign)" do
      user = user_fixture()

      attrs = %{callsign: "W5LUA", lat: 33.1, lon: -96.6}

      {:ok, _} =
        %FixedStation{user_id: user.id}
        |> FixedStation.changeset(attrs)
        |> Repo.insert()

      {:error, cs} =
        %FixedStation{user_id: user.id}
        |> FixedStation.changeset(attrs)
        |> Repo.insert()

      refute cs.valid?
      assert %{callsign: _} = errors_on(cs)
    end
  end
end
