-- 017_identity_verifications.sql
-- Stripe Identity verification sessions for director KYC.
--
-- Every CRTC order director is verified via Stripe Identity BEFORE the order is
-- saved and before any payment is collected. The verification session extracts
-- name and date of birth from the ID document, which are compared against what
-- the customer entered on the order form.
--
-- Applies to ALL payment methods (card, ACH, Klarna, crypto).
--
-- Match result tiers:
--   name_match:  exact | fuzzy_pass | fuzzy_warn | mismatch
--   dob_match:   exact | no_dob_on_id | mismatch
--   overall:     verified | pending | needs_review | failed
--
-- 'needs_review' orders are held in a manual queue — payment is NOT collected
-- until an admin clears them. This is a hard gate.

BEGIN;

CREATE TABLE IF NOT EXISTS identity_verifications (
    id                      SERIAL PRIMARY KEY,

    -- Stripe Identity
    stripe_session_id       TEXT NOT NULL UNIQUE,
    stripe_report_id        TEXT,                     -- verification_report id once complete
    stripe_status           TEXT,                     -- 'requires_input' | 'processing' | 'verified' | 'canceled'

    -- What customer typed on the form
    form_director_name      TEXT NOT NULL,
    form_director_dob       DATE,                     -- null if customer didn't enter DOB

    -- What Stripe extracted from the ID document
    id_first_name           TEXT,
    id_last_name            TEXT,
    id_full_name_extracted  TEXT,                     -- first + last concatenated
    id_dob_year             INTEGER,
    id_dob_month            INTEGER,
    id_dob_day              INTEGER,
    id_doc_type             TEXT,                     -- 'driving_license' | 'passport' | 'id_card'
    id_issuing_country      TEXT,
    id_expiry_year          INTEGER,
    id_expiry_month         INTEGER,
    id_expiry_day           INTEGER,
    id_number               TEXT,                     -- redacted after comparison

    -- Comparison results
    name_match_score        NUMERIC(5,2),             -- 0-100 fuzzy score
    name_match              TEXT                      -- 'exact' | 'fuzzy_pass' | 'fuzzy_warn' | 'mismatch' | 'pending'
                            CHECK (name_match IN ('exact','fuzzy_pass','fuzzy_warn','mismatch','pending')),
    dob_match               TEXT                      -- 'exact' | 'no_dob_on_id' | 'mismatch' | 'pending'
                            CHECK (dob_match IN ('exact','no_dob_on_id','mismatch','pending')),
    doc_expired             BOOLEAN DEFAULT FALSE,

    -- Overall gate result
    overall_result          TEXT NOT NULL DEFAULT 'pending'
                            CHECK (overall_result IN ('pending','verified','needs_review','failed')),

    -- Admin review
    reviewed_by             TEXT,
    review_notes            TEXT,
    reviewed_at             TIMESTAMPTZ,
    admin_override          BOOLEAN DEFAULT FALSE,    -- admin manually cleared needs_review

    -- Linkage
    order_number            TEXT,                     -- set once order is created
    order_type              TEXT DEFAULT 'canada_crtc',
    customer_email          TEXT,

    -- Audit
    created_at              TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    verified_at             TIMESTAMPTZ,
    ip_address              TEXT,
    user_agent              TEXT
);

CREATE INDEX IF NOT EXISTS idx_iv_session       ON identity_verifications (stripe_session_id);
CREATE INDEX IF NOT EXISTS idx_iv_order         ON identity_verifications (order_number);
CREATE INDEX IF NOT EXISTS idx_iv_result        ON identity_verifications (overall_result, created_at);
CREATE INDEX IF NOT EXISTS idx_iv_needs_review  ON identity_verifications (overall_result)
    WHERE overall_result = 'needs_review' AND admin_override = FALSE;

-- Add identity_session_id to CRTC orders so the order route can gate on it
ALTER TABLE canada_crtc_orders
    ADD COLUMN IF NOT EXISTS identity_session_id TEXT
        REFERENCES identity_verifications(stripe_session_id) ON DELETE SET NULL;

ALTER TABLE canada_crtc_orders
    ADD COLUMN IF NOT EXISTS identity_result TEXT
        CHECK (identity_result IN ('verified','needs_review','failed','pending'));

-- Admin view: sessions awaiting review
CREATE OR REPLACE VIEW identity_pending_review AS
SELECT
    iv.*,
    o.order_number  AS linked_order,
    o.customer_email AS order_email
FROM identity_verifications iv
LEFT JOIN canada_crtc_orders o ON o.identity_session_id = iv.stripe_session_id
WHERE iv.overall_result = 'needs_review'
  AND iv.admin_override = FALSE
ORDER BY iv.created_at DESC;

COMMIT;
