-- Dealspace initial schema
-- All content fields (search_key, search_key2, summary, data) are encrypted blobs.
-- Plain fields (entry_id, project_id, parent_id, type, depth, stage, timestamps, IDs) are indexed.

PRAGMA journal_mode = WAL;
PRAGMA foreign_keys = ON;

-- Users
CREATE TABLE IF NOT EXISTS users (
    user_id    TEXT PRIMARY KEY,
    email      TEXT NOT NULL UNIQUE,
    name       TEXT NOT NULL,
    password   TEXT NOT NULL,           -- bcrypt hash
    org_id     TEXT NOT NULL DEFAULT '',
    org_name   TEXT NOT NULL DEFAULT '',
    mfa_secret TEXT NOT NULL DEFAULT '', -- TOTP secret, encrypted
    active     INTEGER NOT NULL DEFAULT 1,
    created_at INTEGER NOT NULL,
    updated_at INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_users_email ON users(email);
CREATE INDEX IF NOT EXISTS idx_users_org ON users(org_id);

-- Entries: the single tree
CREATE TABLE IF NOT EXISTS entries (
    entry_id     TEXT PRIMARY KEY,
    project_id   TEXT NOT NULL,
    parent_id    TEXT NOT NULL DEFAULT '',
    type         TEXT NOT NULL,
    depth        INTEGER NOT NULL DEFAULT 0,
    search_key   BLOB,                    -- blind index (HMAC-SHA256)
    search_key2  BLOB,                    -- blind index (HMAC-SHA256)
    summary      BLOB,                    -- packed: zstd + AES-256-GCM
    data         BLOB,                    -- packed: zstd + AES-256-GCM
    stage        TEXT NOT NULL DEFAULT 'pre_dataroom',
    assignee_id  TEXT NOT NULL DEFAULT '',
    return_to_id TEXT NOT NULL DEFAULT '',
    origin_id    TEXT NOT NULL DEFAULT '',
    version      INTEGER NOT NULL DEFAULT 1,
    deleted_at   INTEGER,
    deleted_by   TEXT,
    key_version  INTEGER NOT NULL DEFAULT 1,
    created_at   INTEGER NOT NULL,
    updated_at   INTEGER NOT NULL,
    created_by   TEXT NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_entries_project    ON entries(project_id);
CREATE INDEX IF NOT EXISTS idx_entries_parent     ON entries(parent_id);
CREATE INDEX IF NOT EXISTS idx_entries_type       ON entries(type);
CREATE INDEX IF NOT EXISTS idx_entries_stage      ON entries(stage);
CREATE INDEX IF NOT EXISTS idx_entries_assignee   ON entries(assignee_id);
CREATE INDEX IF NOT EXISTS idx_entries_return     ON entries(return_to_id);
CREATE INDEX IF NOT EXISTS idx_entries_origin     ON entries(origin_id);
CREATE INDEX IF NOT EXISTS idx_entries_search_key ON entries(search_key);
CREATE INDEX IF NOT EXISTS idx_entries_deleted    ON entries(deleted_at);

-- Answer ↔ Request links (many-to-many)
CREATE TABLE IF NOT EXISTS answer_links (
    answer_id     TEXT NOT NULL REFERENCES entries(entry_id),
    request_id    TEXT NOT NULL REFERENCES entries(entry_id),
    linked_by     TEXT NOT NULL,
    linked_at     INTEGER NOT NULL,
    confirmed     INTEGER NOT NULL DEFAULT 0,
    ai_score      REAL,
    status        TEXT NOT NULL DEFAULT 'pending',  -- pending | confirmed | rejected
    reviewed_by   TEXT,
    reviewed_at   INTEGER,
    reject_reason TEXT,
    PRIMARY KEY (answer_id, request_id)
);

-- Access / RBAC
CREATE TABLE IF NOT EXISTS access (
    id            TEXT PRIMARY KEY,
    project_id    TEXT NOT NULL,
    workstream_id TEXT,
    user_id       TEXT NOT NULL,
    role          TEXT NOT NULL,
    ops           TEXT NOT NULL,
    can_grant     INTEGER NOT NULL DEFAULT 0,
    granted_by    TEXT NOT NULL,
    granted_at    INTEGER NOT NULL,
    revoked_at    INTEGER,
    revoked_by    TEXT
);
CREATE INDEX IF NOT EXISTS idx_access_user    ON access(user_id);
CREATE INDEX IF NOT EXISTS idx_access_project ON access(project_id);

-- Entry events (workflow thread)
CREATE TABLE IF NOT EXISTS entry_events (
    id       TEXT PRIMARY KEY,
    entry_id TEXT NOT NULL REFERENCES entries(entry_id),
    actor_id TEXT NOT NULL,
    channel  TEXT NOT NULL,
    action   BLOB NOT NULL,  -- packed
    data     BLOB NOT NULL,  -- packed
    ts       INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_events_entry ON entry_events(entry_id);
CREATE INDEX IF NOT EXISTS idx_events_actor ON entry_events(actor_id);

-- Channel threads (email/Slack/Teams → entry mapping)
CREATE TABLE IF NOT EXISTS channel_threads (
    id         TEXT PRIMARY KEY,
    entry_id   TEXT NOT NULL REFERENCES entries(entry_id),
    channel    TEXT NOT NULL,
    thread_id  TEXT NOT NULL,
    project_id TEXT NOT NULL,
    UNIQUE(channel, thread_id)
);

-- Embeddings (AI matching)
CREATE TABLE IF NOT EXISTS embeddings (
    entry_id TEXT PRIMARY KEY REFERENCES entries(entry_id),
    vector   BLOB NOT NULL
);

-- Audit log
CREATE TABLE IF NOT EXISTS audit (
    id         TEXT PRIMARY KEY,
    project_id TEXT NOT NULL,
    actor_id   TEXT NOT NULL,
    action     BLOB NOT NULL,   -- packed
    target_id  TEXT,
    details    BLOB,            -- packed
    ip         TEXT,
    ts         INTEGER NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_audit_project ON audit(project_id);
CREATE INDEX IF NOT EXISTS idx_audit_actor   ON audit(actor_id);
CREATE INDEX IF NOT EXISTS idx_audit_ts      ON audit(ts);

-- Sessions
CREATE TABLE IF NOT EXISTS sessions (
    id           TEXT PRIMARY KEY,
    user_id      TEXT NOT NULL REFERENCES users(user_id),
    fingerprint  TEXT NOT NULL DEFAULT '',
    created_at   INTEGER NOT NULL,
    expires_at   INTEGER NOT NULL,
    revoked      INTEGER NOT NULL DEFAULT 0
);
CREATE INDEX IF NOT EXISTS idx_sessions_user ON sessions(user_id);

-- Auth challenges (email OTP)
CREATE TABLE IF NOT EXISTS challenges (
    challenge_id TEXT PRIMARY KEY,
    email        TEXT NOT NULL,
    code         TEXT NOT NULL,
    created_at   INTEGER NOT NULL,
    expires_at   INTEGER NOT NULL,
    used         INTEGER NOT NULL DEFAULT 0
);
CREATE INDEX IF NOT EXISTS idx_challenges_email ON challenges(email);

-- Broadcasts (idempotency)
CREATE TABLE IF NOT EXISTS broadcasts (
    id           TEXT PRIMARY KEY,
    answer_id    TEXT NOT NULL,
    request_id   TEXT NOT NULL,
    recipient_id TEXT NOT NULL,
    sent_at      INTEGER NOT NULL,
    UNIQUE(answer_id, request_id, recipient_id)
);
