defmodule Microwaveprop.RoverPlanning.Path do
  @moduledoc """
  A computed (or pending) path-profile result for one rover-location
  → station pairing inside a mission. `result` holds the same shape
  produced by `MicrowavepropWeb.PathLive`'s synchronous compute, so
  the show page can render it identically.
  """
  use Ecto.Schema

  import Ecto.Changeset

  alias Microwaveprop.Rover.Location
  alias Microwaveprop.RoverPlanning.Mission
  alias Microwaveprop.RoverPlanning.Station

  @statuses [:pending, :computing, :complete, :failed]

  @primary_key {:id, :binary_id, autogenerate: true}
  @foreign_key_type :binary_id
  schema "rover_mission_paths" do
    field :band_mhz, :integer
    field :status, Ecto.Enum, values: @statuses, default: :pending
    field :result, :map
    field :error, :string
    field :computed_at, :utc_datetime

    belongs_to :mission, Mission
    belongs_to :rover_location, Location
    belongs_to :station, Station

    timestamps(type: :utc_datetime)
  end

  @type t :: %__MODULE__{}

  @spec statuses() :: [atom()]
  def statuses, do: @statuses

  @spec changeset(t() | Ecto.Changeset.t(), map()) :: Ecto.Changeset.t()
  def changeset(path, attrs) do
    path
    |> cast(attrs, [
      :band_mhz,
      :status,
      :result,
      :error,
      :computed_at,
      :mission_id,
      :rover_location_id,
      :station_id
    ])
    |> validate_required([:mission_id, :rover_location_id, :station_id, :band_mhz, :status])
    |> validate_inclusion(:status, @statuses)
    |> validate_number(:band_mhz, greater_than: 0)
    |> unique_constraint([:mission_id, :rover_location_id, :station_id, :band_mhz],
      name: :rover_mission_paths_unique
    )
  end
end
