-- 015_job_queue.sql
-- Persistent job queue for portal automation with retry and deferral.
--
-- Replaces the fire-and-forget in-memory job dispatch.
-- A scheduler thread in job_server.py polls this table every 60s.
--
-- Portal hours awareness:
--   BC Corporate Online: Mon-Sat 06:00-22:00 PT, Sun 13:00-22:00 PT
--   IRS EIN Assistant:   Mon-Fri 07:00-22:00 ET
--   All others:          24/7 (no deferral needed)
--
-- Retry policy: exponential backoff, 5 attempts max, then escalate to admin.

BEGIN;

CREATE TABLE IF NOT EXISTS job_queue (
    id              SERIAL PRIMARY KEY,
    job_type        TEXT NOT NULL,              -- 'file_entity' | 'obtain_ein' | 'name_search' | 'process_crtc' | 'deliver'
    payload         JSONB NOT NULL,             -- order details, state_code, order_name, etc.
    status          TEXT NOT NULL DEFAULT 'pending'
                    CHECK (status IN ('pending', 'running', 'completed', 'failed', 'deferred', 'cancelled')),
    attempts        INTEGER NOT NULL DEFAULT 0,
    max_attempts    INTEGER NOT NULL DEFAULT 5,
    run_at          TIMESTAMPTZ NOT NULL DEFAULT NOW(),  -- next eligible run time
    started_at      TIMESTAMPTZ,
    completed_at    TIMESTAMPTZ,
    last_error      TEXT,
    -- Portal context
    portal_tz       TEXT,                       -- e.g. 'America/Vancouver' for BC jobs
    portal_hours    JSONB,                      -- {mon:[6,22], tue:[6,22], ..., sun:[13,22]}
    -- Linkage
    order_id        TEXT,                       -- denormalized for easy lookup
    order_type      TEXT,                       -- 'canada_crtc' | 'formation'
    created_at      TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- Scheduler polls this index every 60s for due, runnable jobs
CREATE INDEX IF NOT EXISTS idx_job_queue_runnable
    ON job_queue (run_at, created_at)
    WHERE status IN ('pending', 'deferred');

CREATE INDEX IF NOT EXISTS idx_job_queue_order
    ON job_queue (order_id)
    WHERE status NOT IN ('completed', 'cancelled');

COMMIT;
