-- Fractafrag Database Bootstrap
-- Runs on first container start via docker-entrypoint-initdb.d

-- Enable required extensions
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE EXTENSION IF NOT EXISTS "vector";
CREATE EXTENSION IF NOT EXISTS "pg_trgm";  -- for text search

-- ════════════════════════════════════════════════════════════
-- USERS
-- ════════════════════════════════════════════════════════════
CREATE TABLE users (
    id                      UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    username                TEXT UNIQUE NOT NULL,
    email                   TEXT UNIQUE NOT NULL,
    password_hash           TEXT NOT NULL,
    role                    TEXT NOT NULL DEFAULT 'user',        -- user, moderator, admin
    trust_tier              TEXT NOT NULL DEFAULT 'standard',    -- standard, creator, trusted_api
    stripe_customer_id      TEXT,
    subscription_tier       TEXT DEFAULT 'free',                 -- free, pro, studio
    ai_credits_remaining    INTEGER DEFAULT 0,
    taste_vector            vector(512),                         -- pgvector: learned taste embedding
    -- Creator economy stubs (Section 11f — deferred, schema only)
    is_verified_creator     BOOLEAN DEFAULT FALSE,
    verified_creator_at     TIMESTAMPTZ,
    stripe_connect_account_id TEXT,
    -- Timestamps
    created_at              TIMESTAMPTZ DEFAULT NOW(),
    last_active_at          TIMESTAMPTZ
);

-- ════════════════════════════════════════════════════════════
-- SHADERS
-- ════════════════════════════════════════════════════════════
CREATE TABLE shaders (
    id                  UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    author_id           UUID REFERENCES users(id) ON DELETE SET NULL,
    title               TEXT NOT NULL,
    description         TEXT,
    glsl_code           TEXT NOT NULL,
    is_public           BOOLEAN DEFAULT TRUE,
    is_ai_generated     BOOLEAN DEFAULT FALSE,
    ai_provider         TEXT,                   -- anthropic, openai, ollama, null
    thumbnail_url       TEXT,
    preview_url         TEXT,
    render_status       TEXT DEFAULT 'pending',  -- pending, rendering, ready, failed
    style_vector        vector(512),             -- pgvector: visual style embedding
    style_metadata      JSONB,                   -- { chaos_level, color_temp, motion_type, ... }
    tags                TEXT[],
    shader_type         TEXT DEFAULT '2d',        -- 2d, 3d, audio-reactive
    forked_from         UUID REFERENCES shaders(id) ON DELETE SET NULL,
    view_count          INTEGER DEFAULT 0,
    score               FLOAT DEFAULT 0,          -- cached hot score for feed ranking
    -- Creator economy stubs (Section 11f)
    access_tier                     TEXT DEFAULT 'open',  -- open, source_locked, commercial
    source_unlock_price_cents       INTEGER,
    commercial_license_price_cents  INTEGER,
    verified_creator_shader         BOOLEAN DEFAULT FALSE,
    -- Timestamps
    created_at          TIMESTAMPTZ DEFAULT NOW(),
    updated_at          TIMESTAMPTZ DEFAULT NOW()
);

-- ════════════════════════════════════════════════════════════
-- VOTES
-- ════════════════════════════════════════════════════════════
CREATE TABLE votes (
    id          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id     UUID REFERENCES users(id) ON DELETE CASCADE,
    shader_id   UUID REFERENCES shaders(id) ON DELETE CASCADE,
    value       SMALLINT NOT NULL CHECK (value IN (-1, 1)),
    created_at  TIMESTAMPTZ DEFAULT NOW(),
    UNIQUE (user_id, shader_id)
);

-- ════════════════════════════════════════════════════════════
-- ENGAGEMENT EVENTS (dwell time, replays, shares)
-- ════════════════════════════════════════════════════════════
CREATE TABLE engagement_events (
    id          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id     UUID REFERENCES users(id) ON DELETE SET NULL,  -- null for anonymous
    session_id  TEXT,                                           -- anonymous session token
    shader_id   UUID REFERENCES shaders(id) ON DELETE CASCADE,
    event_type  TEXT NOT NULL,       -- dwell, replay, share, generate_similar
    dwell_secs  FLOAT,
    metadata    JSONB,
    created_at  TIMESTAMPTZ DEFAULT NOW()
);

-- ════════════════════════════════════════════════════════════
-- DESIRES / BOUNTIES
-- ════════════════════════════════════════════════════════════
CREATE TABLE desires (
    id                      UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    author_id               UUID REFERENCES users(id) ON DELETE SET NULL,
    prompt_text             TEXT NOT NULL,
    prompt_embedding        vector(512),        -- embedded for similarity grouping
    style_hints             JSONB,              -- { chaos_level, color_temp, etc }
    tip_amount_cents        INTEGER DEFAULT 0,
    status                  TEXT DEFAULT 'open', -- open, in_progress, fulfilled, expired
    heat_score              FLOAT DEFAULT 1,     -- updated as similar desires accumulate
    fulfilled_by_shader     UUID REFERENCES shaders(id) ON DELETE SET NULL,
    fulfilled_at            TIMESTAMPTZ,
    expires_at              TIMESTAMPTZ,
    created_at              TIMESTAMPTZ DEFAULT NOW()
);

-- Similar desire grouping (many-to-many)
CREATE TABLE desire_clusters (
    cluster_id  UUID,
    desire_id   UUID REFERENCES desires(id) ON DELETE CASCADE,
    similarity  FLOAT,
    PRIMARY KEY (cluster_id, desire_id)
);

-- ════════════════════════════════════════════════════════════
-- BOUNTY TIPS
-- ════════════════════════════════════════════════════════════
CREATE TABLE bounty_tips (
    id                          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    desire_id                   UUID REFERENCES desires(id) ON DELETE CASCADE,
    tipper_id                   UUID REFERENCES users(id) ON DELETE SET NULL,
    amount_cents                INTEGER NOT NULL,
    stripe_payment_intent_id    TEXT,
    status                      TEXT DEFAULT 'held',  -- held, released, refunded
    created_at                  TIMESTAMPTZ DEFAULT NOW()
);

-- ════════════════════════════════════════════════════════════
-- CREATOR PAYOUTS
-- ════════════════════════════════════════════════════════════
CREATE TABLE creator_payouts (
    id                  UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    creator_id          UUID REFERENCES users(id) ON DELETE SET NULL,
    desire_id           UUID REFERENCES desires(id) ON DELETE SET NULL,
    gross_amount_cents  INTEGER,
    platform_fee_cents  INTEGER,     -- 10%
    net_amount_cents    INTEGER,     -- 90%
    stripe_transfer_id  TEXT,
    status              TEXT DEFAULT 'pending',  -- pending, processing, completed, failed
    created_at          TIMESTAMPTZ DEFAULT NOW()
);

-- ════════════════════════════════════════════════════════════
-- API KEYS (for MCP clients)
-- ════════════════════════════════════════════════════════════
CREATE TABLE api_keys (
    id                      UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id                 UUID REFERENCES users(id) ON DELETE CASCADE,
    key_hash                TEXT UNIQUE NOT NULL,     -- bcrypt hash of the actual key
    key_prefix              TEXT NOT NULL,            -- first 8 chars for display (ff_key_XXXXXXXX)
    name                    TEXT,                     -- user-given label
    trust_tier              TEXT DEFAULT 'probation', -- probation, trusted, premium
    submissions_approved    INTEGER DEFAULT 0,
    rate_limit_per_hour     INTEGER DEFAULT 10,
    last_used_at            TIMESTAMPTZ,
    created_at              TIMESTAMPTZ DEFAULT NOW(),
    revoked_at              TIMESTAMPTZ
);

-- ════════════════════════════════════════════════════════════
-- AI GENERATION LOG
-- ════════════════════════════════════════════════════════════
CREATE TABLE generation_log (
    id          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id     UUID REFERENCES users(id) ON DELETE SET NULL,
    shader_id   UUID REFERENCES shaders(id) ON DELETE SET NULL,
    provider    TEXT NOT NULL,
    prompt_text TEXT,
    tokens_used INTEGER,
    cost_cents  INTEGER,       -- platform cost for credit-based generations
    success     BOOLEAN,
    created_at  TIMESTAMPTZ DEFAULT NOW()
);

-- ════════════════════════════════════════════════════════════
-- COMMENTS (schema in place, feature deferred to post-M5)
-- ════════════════════════════════════════════════════════════
CREATE TABLE comments (
    id          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    shader_id   UUID REFERENCES shaders(id) ON DELETE CASCADE,
    author_id   UUID REFERENCES users(id) ON DELETE SET NULL,
    body        TEXT NOT NULL,
    parent_id   UUID REFERENCES comments(id) ON DELETE CASCADE,
    created_at  TIMESTAMPTZ DEFAULT NOW()
);

-- ════════════════════════════════════════════════════════════
-- CREATOR ECONOMY STUBS (Section 11f — dormant until activated)
-- ════════════════════════════════════════════════════════════
CREATE TABLE source_unlocks (
    id                          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    shader_id                   UUID REFERENCES shaders(id) ON DELETE CASCADE,
    buyer_id                    UUID REFERENCES users(id) ON DELETE SET NULL,
    license_type                TEXT NOT NULL,    -- personal, commercial
    amount_cents                INTEGER NOT NULL,
    platform_fee_cents          INTEGER NOT NULL,
    stripe_payment_intent_id    TEXT,
    created_at                  TIMESTAMPTZ DEFAULT NOW()
);

CREATE TABLE creator_engagement_snapshots (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    creator_id      UUID REFERENCES users(id) ON DELETE CASCADE,
    month           DATE NOT NULL,
    total_score     FLOAT NOT NULL,
    pool_share      FLOAT,
    payout_cents    INTEGER,
    paid_at         TIMESTAMPTZ,
    created_at      TIMESTAMPTZ DEFAULT NOW()
);

-- ════════════════════════════════════════════════════════════
-- INDEXES
-- ════════════════════════════════════════════════════════════

-- Feed performance
CREATE INDEX idx_shaders_score ON shaders(score DESC) WHERE is_public = TRUE;
CREATE INDEX idx_shaders_created ON shaders(created_at DESC) WHERE is_public = TRUE;
CREATE INDEX idx_shaders_tags ON shaders USING GIN(tags);
CREATE INDEX idx_shaders_render_status ON shaders(render_status) WHERE render_status != 'ready';

-- Recommendation (pgvector ANN — ivfflat, will rebuild after data exists)
-- NOTE: ivfflat indexes require data in the table to build properly.
-- Run these AFTER seeding initial data:
--   CREATE INDEX idx_shaders_style_vector ON shaders
--     USING ivfflat (style_vector vector_cosine_ops) WITH (lists = 100);
--   CREATE INDEX idx_users_taste_vector ON users
--     USING ivfflat (taste_vector vector_cosine_ops) WITH (lists = 50);
--   CREATE INDEX idx_desires_embedding ON desires
--     USING ivfflat (prompt_embedding vector_cosine_ops) WITH (lists = 50);

-- For now, use HNSW (works on empty tables, better perf at small scale)
CREATE INDEX idx_shaders_style_vector ON shaders
    USING hnsw (style_vector vector_cosine_ops) WITH (m = 16, ef_construction = 64);
CREATE INDEX idx_users_taste_vector ON users
    USING hnsw (taste_vector vector_cosine_ops) WITH (m = 16, ef_construction = 64);
CREATE INDEX idx_desires_embedding ON desires
    USING hnsw (prompt_embedding vector_cosine_ops) WITH (m = 16, ef_construction = 64);

-- Engagement
CREATE INDEX idx_engagement_user ON engagement_events(user_id, created_at DESC);
CREATE INDEX idx_engagement_shader ON engagement_events(shader_id, event_type);
CREATE INDEX idx_engagement_session ON engagement_events(session_id, created_at DESC)
    WHERE session_id IS NOT NULL;

-- Desires / bounties
CREATE INDEX idx_desires_status ON desires(status, heat_score DESC);
CREATE INDEX idx_desires_author ON desires(author_id);

-- API keys
CREATE INDEX idx_api_keys_user ON api_keys(user_id) WHERE revoked_at IS NULL;
CREATE INDEX idx_api_keys_prefix ON api_keys(key_prefix);

-- Votes
CREATE INDEX idx_votes_shader ON votes(shader_id);
CREATE INDEX idx_votes_user ON votes(user_id);

-- Comments
CREATE INDEX idx_comments_shader ON comments(shader_id, created_at);
CREATE INDEX idx_comments_parent ON comments(parent_id);

-- Text search
CREATE INDEX idx_shaders_title_trgm ON shaders USING GIN(title gin_trgm_ops);
CREATE INDEX idx_desires_prompt_trgm ON desires USING GIN(prompt_text gin_trgm_ops);
