SET LOCAL lock_timeout = '10s';
SET LOCAL statement_timeout = '60s';

-- 0071 was briefly released with only the singleton reservation lease fields.
-- Add the durable lifecycle columns without rewriting that already-applied
-- migration, then reconcile the singleton with the canonical outstanding
-- pairing (when one exists).
ALTER TABLE gateway_identity_pairing_start_reservation
  ADD COLUMN IF NOT EXISTS state text,
  ADD COLUMN IF NOT EXISTS revision_id uuid,
  ADD COLUMN IF NOT EXISTS updated_at timestamptz;

UPDATE gateway_identity_pairing_start_reservation
SET state=CASE WHEN revision_id IS NULL THEN 'starting' ELSE 'paired' END,
    updated_at=COALESCE(updated_at,created_at,now())
WHERE state IS NULL
   OR state NOT IN ('starting','paired')
   OR (state='starting' AND revision_id IS NOT NULL)
   OR (state='paired' AND revision_id IS NULL)
   OR updated_at IS NULL;

WITH canonical_pairing AS (
  SELECT exchange.id AS attempt_id,
         revision.id AS revision_id,
         exchange.expires_at
  FROM gateway_identity_configuration_revisions revision
  JOIN gateway_identity_onboarding_exchanges exchange
    ON exchange.revision_id=revision.id
  WHERE revision.state IN ('draft','validated','failed')
    AND NOT (exchange.status='cancelled' AND exchange.cleanup_status='completed')
  ORDER BY revision.created_at DESC,exchange.created_at DESC
  LIMIT 1
)
INSERT INTO gateway_identity_pairing_start_reservation(
  singleton,attempt_id,state,revision_id,expires_at,updated_at
)
SELECT true,attempt_id,'paired',revision_id,expires_at,now()
FROM canonical_pairing
ON CONFLICT (singleton) DO UPDATE
SET attempt_id=EXCLUDED.attempt_id,
    state=EXCLUDED.state,
    revision_id=EXCLUDED.revision_id,
    expires_at=EXCLUDED.expires_at,
    updated_at=now();

ALTER TABLE gateway_identity_pairing_start_reservation
  ALTER COLUMN state SET DEFAULT 'starting',
  ALTER COLUMN state SET NOT NULL,
  ALTER COLUMN updated_at SET DEFAULT now(),
  ALTER COLUMN updated_at SET NOT NULL;

ALTER TABLE gateway_identity_pairing_start_reservation
  DROP CONSTRAINT IF EXISTS gateway_identity_pairing_start_state_value_check,
  DROP CONSTRAINT IF EXISTS gateway_identity_pairing_start_state_check;

ALTER TABLE gateway_identity_pairing_start_reservation
  ADD CONSTRAINT gateway_identity_pairing_start_state_value_check
    CHECK (state IN ('starting','paired')),
  ADD CONSTRAINT gateway_identity_pairing_start_state_check CHECK (
    (state='starting' AND revision_id IS NULL) OR
    (state='paired' AND revision_id IS NOT NULL)
  );

DO $migration$
BEGIN
  IF NOT EXISTS (
    SELECT 1
    FROM pg_constraint
    WHERE conrelid='gateway_identity_pairing_start_reservation'::regclass
      AND contype='f'
      AND pg_get_constraintdef(oid) LIKE 'FOREIGN KEY (revision_id)%'
  ) THEN
    ALTER TABLE gateway_identity_pairing_start_reservation
      ADD CONSTRAINT gateway_identity_pairing_start_revision_fk
      FOREIGN KEY (revision_id)
      REFERENCES gateway_identity_configuration_revisions(id)
      ON DELETE RESTRICT;
  END IF;
END
$migration$;

CREATE UNIQUE INDEX IF NOT EXISTS idx_gateway_identity_pairing_start_revision_unique
  ON gateway_identity_pairing_start_reservation(revision_id)
  WHERE revision_id IS NOT NULL;

DROP INDEX IF EXISTS idx_gateway_identity_pairing_start_expiry;

CREATE INDEX idx_gateway_identity_pairing_start_expiry
  ON gateway_identity_pairing_start_reservation(state,expires_at);
