-- ============================================================
-- ALGORITHM_REGISTRY — The Multi-Root Algorithm Layer
-- ============================================================
-- Level 2.5 in the computational fabric.
-- An ALGORITHM is a named root-set that fires together across
-- one or more ayat to execute a single operational pattern.
--
-- Q28:4 is ONE algorithm (Pharaoh extraction).
-- Q63:1-11 is ONE algorithm (munafiq deception).
-- Q12:57-66 is ONE algorithm (Yusuf kayl distribution).
-- The Radhanite operation runs MULTIPLE algorithms simultaneously.
--
-- This replaces the root-at-a-time fabric scan with a
-- multi-root fabric scan keyed on named algorithms.
-- ============================================================

-- ============================================================
-- 1. algorithm_registry — master metadata
-- ============================================================
CREATE TABLE IF NOT EXISTS algorithm_registry (
    algo_id           TEXT PRIMARY KEY,       -- ALG-PHARAOH-EXTRACTION
    algo_name         TEXT NOT NULL,          -- human-readable name
    algo_class        TEXT NOT NULL,          -- OPERATOR | NARRATIVE | BINARY_PAIR | REFRAIN | DESCRIPTION | ECONOMIC | ESCHATOLOGICAL
    description       TEXT,                   -- structural description (no etymologies)
    primary_ayah      TEXT,                   -- canonical source (Q28:4)
    root_count        INTEGER DEFAULT 0,      -- auto-populated from algorithm_root_map
    ayah_count        INTEGER DEFAULT 0,      -- auto-populated from algorithm_ayah_map
    surah_count       INTEGER DEFAULT 0,      -- auto-populated from algorithm_ayah_map
    cross_refs        TEXT,                   -- JSON array of related algo_ids and table refs
    status            TEXT DEFAULT 'DRAFT',   -- DRAFT | VERIFIED | SEALED
    created_date      TEXT DEFAULT (datetime('now')),
    notes             TEXT,
    quf_q             TEXT,
    quf_u             TEXT,
    quf_f             TEXT,
    quf_pass          TEXT,
    quf_date          TEXT,
    quf_token         TEXT,
    CHECK (algo_id LIKE 'ALG-%'),
    CHECK (algo_class IN ('OPERATOR','NARRATIVE','BINARY_PAIR','REFRAIN','DESCRIPTION','ECONOMIC','ESCHATOLOGICAL','MORPHOLOGICAL'))
);

CREATE INDEX IF NOT EXISTS idx_algo_class ON algorithm_registry(algo_class);
CREATE INDEX IF NOT EXISTS idx_algo_status ON algorithm_registry(status);

-- ============================================================
-- 2. algorithm_root_map — N:M link (algo ↔ roots)
-- ============================================================
CREATE TABLE IF NOT EXISTS algorithm_root_map (
    map_id            INTEGER PRIMARY KEY AUTOINCREMENT,
    algo_id           TEXT NOT NULL,
    root_letters      TEXT NOT NULL,          -- must exist in roots table
    role              TEXT DEFAULT 'PRIMARY', -- PRIMARY | SUPPORT | BINARY_A | BINARY_B | INVERSION
    token_count       INTEGER,                -- auto-filled from quran_word_roots at insert time
    notes             TEXT,
    created_date      TEXT DEFAULT (datetime('now')),
    UNIQUE (algo_id, root_letters),
    FOREIGN KEY (algo_id) REFERENCES algorithm_registry(algo_id) ON DELETE CASCADE,
    CHECK (role IN ('PRIMARY','SUPPORT','BINARY_A','BINARY_B','INVERSION','OBJECT','INSTRUMENT'))
);

CREATE INDEX IF NOT EXISTS idx_arm_algo ON algorithm_root_map(algo_id);
CREATE INDEX IF NOT EXISTS idx_arm_root ON algorithm_root_map(root_letters);

-- ============================================================
-- 3. algorithm_ayah_map — N:M link (algo ↔ ayat)
-- ============================================================
CREATE TABLE IF NOT EXISTS algorithm_ayah_map (
    map_id            INTEGER PRIMARY KEY AUTOINCREMENT,
    algo_id           TEXT NOT NULL,
    surah             INTEGER NOT NULL,
    ayah_start        INTEGER NOT NULL,
    ayah_end          INTEGER,                -- NULL = single ayah
    is_primary        INTEGER DEFAULT 0,      -- 1 = canonical source
    instance_note     TEXT,                   -- e.g. "Pharaoh instance" vs "Rome instance"
    created_date      TEXT DEFAULT (datetime('now')),
    FOREIGN KEY (algo_id) REFERENCES algorithm_registry(algo_id) ON DELETE CASCADE,
    CHECK (surah BETWEEN 1 AND 114),
    CHECK (ayah_start > 0),
    CHECK (ayah_end IS NULL OR ayah_end >= ayah_start)
);

CREATE INDEX IF NOT EXISTS idx_aam_algo ON algorithm_ayah_map(algo_id);
CREATE INDEX IF NOT EXISTS idx_aam_surah ON algorithm_ayah_map(surah);
CREATE INDEX IF NOT EXISTS idx_aam_primary ON algorithm_ayah_map(is_primary) WHERE is_primary = 1;

-- ============================================================
-- TRIGGERS — auto-populate counts + contamination shield
-- ============================================================

-- Update root_count on algorithm_registry when algorithm_root_map changes
CREATE TRIGGER IF NOT EXISTS trg_arm_insert_count
AFTER INSERT ON algorithm_root_map
BEGIN
    UPDATE algorithm_registry
    SET root_count = (SELECT COUNT(*) FROM algorithm_root_map WHERE algo_id = NEW.algo_id)
    WHERE algo_id = NEW.algo_id;
END;

CREATE TRIGGER IF NOT EXISTS trg_arm_delete_count
AFTER DELETE ON algorithm_root_map
BEGIN
    UPDATE algorithm_registry
    SET root_count = (SELECT COUNT(*) FROM algorithm_root_map WHERE algo_id = OLD.algo_id)
    WHERE algo_id = OLD.algo_id;
END;

-- Update ayah_count + surah_count on algorithm_registry when algorithm_ayah_map changes
CREATE TRIGGER IF NOT EXISTS trg_aam_insert_count
AFTER INSERT ON algorithm_ayah_map
BEGIN
    UPDATE algorithm_registry
    SET
        ayah_count = (
            SELECT COALESCE(SUM(COALESCE(ayah_end, ayah_start) - ayah_start + 1), 0)
            FROM algorithm_ayah_map WHERE algo_id = NEW.algo_id
        ),
        surah_count = (
            SELECT COUNT(DISTINCT surah) FROM algorithm_ayah_map WHERE algo_id = NEW.algo_id
        )
    WHERE algo_id = NEW.algo_id;
END;

CREATE TRIGGER IF NOT EXISTS trg_aam_delete_count
AFTER DELETE ON algorithm_ayah_map
BEGIN
    UPDATE algorithm_registry
    SET
        ayah_count = (
            SELECT COALESCE(SUM(COALESCE(ayah_end, ayah_start) - ayah_start + 1), 0)
            FROM algorithm_ayah_map WHERE algo_id = OLD.algo_id
        ),
        surah_count = (
            SELECT COUNT(DISTINCT surah) FROM algorithm_ayah_map WHERE algo_id = OLD.algo_id
        )
    WHERE algo_id = OLD.algo_id;
END;

-- Auto-fill token_count on algorithm_root_map insert (from quran_word_roots)
CREATE TRIGGER IF NOT EXISTS trg_arm_fill_tokens
AFTER INSERT ON algorithm_root_map
FOR EACH ROW
WHEN NEW.token_count IS NULL
BEGIN
    UPDATE algorithm_root_map
    SET token_count = (SELECT COUNT(*) FROM quran_word_roots WHERE root = NEW.root_letters)
    WHERE map_id = NEW.map_id;
END;

-- Contamination shield — block banned terms in description/notes
CREATE TRIGGER IF NOT EXISTS trg_algo_contamination_desc
BEFORE INSERT ON algorithm_registry
FOR EACH ROW
WHEN NEW.description IS NOT NULL AND (
    LOWER(NEW.description) LIKE '%borrowed from%' OR
    LOWER(NEW.description) LIKE '%loan from%' OR
    LOWER(NEW.description) LIKE '%loanword%' OR
    LOWER(NEW.description) LIKE '%cognate with%' OR
    LOWER(NEW.description) LIKE '%semitic%' OR
    LOWER(NEW.description) LIKE '%proto-indo-european%' OR
    LOWER(NEW.description) LIKE '%from greek%' OR
    LOWER(NEW.description) LIKE '%from latin%' OR
    LOWER(NEW.description) LIKE '%from sanskrit%' OR
    LOWER(NEW.description) LIKE '%from persian%' OR
    LOWER(NEW.description) LIKE '%farsi%'
)
BEGIN
    SELECT RAISE(ABORT, 'CONTAMINATION: banned term in algorithm description');
END;

CREATE TRIGGER IF NOT EXISTS trg_algo_contamination_notes
BEFORE INSERT ON algorithm_registry
FOR EACH ROW
WHEN NEW.notes IS NOT NULL AND (
    LOWER(NEW.notes) LIKE '%borrowed from%' OR
    LOWER(NEW.notes) LIKE '%loan from%' OR
    LOWER(NEW.notes) LIKE '%loanword%' OR
    LOWER(NEW.notes) LIKE '%cognate with%' OR
    LOWER(NEW.notes) LIKE '%semitic%' OR
    LOWER(NEW.notes) LIKE '%proto-indo-european%' OR
    LOWER(NEW.notes) LIKE '%from greek%' OR
    LOWER(NEW.notes) LIKE '%from latin%' OR
    LOWER(NEW.notes) LIKE '%from sanskrit%' OR
    LOWER(NEW.notes) LIKE '%from persian%' OR
    LOWER(NEW.notes) LIKE '%farsi%'
)
BEGIN
    SELECT RAISE(ABORT, 'CONTAMINATION: banned term in algorithm notes');
END;
