defmodule Microwaveprop.Repo.Migrations.CreatePskrCalibrationSamples do
  use Ecto.Migration

  # Calibration corpus joining PSKR spot density (truth signal) with
  # HRRR atmospheric state and SWPC space weather (predictors). One
  # row per (hour, band, midpoint cell). The recalibrator reads from
  # this table and computes predicted scores on demand from the
  # stored features — never store the prediction itself, since it
  # depends on the algorithm version under evaluation.

  def change do
    create table(:pskr_calibration_samples, primary_key: false) do
      add :id, :binary_id, primary_key: true
      add :hour_utc, :utc_datetime, null: false
      add :band, :string, null: false
      add :midpoint_lat, :float, null: false
      add :midpoint_lon, :float, null: false

      # Aggregate PSKR signal at this cell.
      add :spot_count, :integer, null: false, default: 0
      add :distinct_paths, :integer, null: false, default: 0
      add :median_distance_km, :float
      add :modes, {:array, :string}, null: false, default: []

      # HRRR atmospheric snapshot at midpoint at the hour boundary.
      # Nullable because the join may miss for pre-2014 cells or
      # cells outside the HRRR domain.
      add :surface_temp_c, :float
      add :surface_dewpoint_c, :float
      add :pwat_mm, :float
      add :surface_pressure_mb, :float
      add :min_refractivity_gradient, :float
      add :hpbl_m, :float
      add :hrrr_ducting_detected, :boolean

      # SWPC geomagnetic state at the hour boundary. Same Kp value
      # applies to every cell in the same hour, but stored per-row so
      # the recalibrator doesn't have to re-join SpaceWeather for
      # every batch of samples.
      add :kp_index, :integer

      timestamps(type: :utc_datetime)
    end

    # Same uniqueness shape as `pskr_spots_hourly` so the upsert
    # pattern translates 1:1. Cell granularity is set by the sampler
    # (currently 0.125° to match the propagation grid).
    create unique_index(:pskr_calibration_samples, [
             :hour_utc,
             :band,
             :midpoint_lat,
             :midpoint_lon
           ])

    create index(:pskr_calibration_samples, [:hour_utc])

    # Make the spot-side spatial filter the sampler runs cheap.
    # `pskr_spots_hourly` already has unique-index coverage on
    # (hour_utc, band, sender_grid, receiver_grid) but no index that
    # supports a midpoint range scan, which is the hot path for both
    # the sampler join and any future map-side density queries.
    create index(:pskr_spots_hourly, [:midpoint_lat, :midpoint_lon])
  end
end
