CREATE TABLE task_queue_outbox (
  task_id UUID PRIMARY KEY REFERENCES tasks(id) ON DELETE CASCADE,
  status VARCHAR(20) NOT NULL DEFAULT 'pending',
  attempts INTEGER NOT NULL DEFAULT 0,
  next_attempt_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  lease_owner UUID,
  lease_until TIMESTAMPTZ,
  last_error TEXT,
  delivered_at TIMESTAMPTZ,
  created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
  CONSTRAINT task_queue_outbox_status_check
    CHECK (status IN ('pending', 'delivering', 'delivered', 'dead')),
  CONSTRAINT task_queue_outbox_attempts_check
    CHECK (attempts >= 0),
  CONSTRAINT task_queue_outbox_lease_pair_check
    CHECK ((lease_owner IS NULL) = (lease_until IS NULL))
);

CREATE INDEX task_queue_outbox_ready
  ON task_queue_outbox(next_attempt_at, created_at)
  WHERE status IN ('pending', 'delivering');

INSERT INTO task_queue_outbox (task_id)
SELECT id
FROM tasks
WHERE status = 'pending'
ON CONFLICT (task_id) DO NOTHING;
