-- Initial schema for AI Code Battle
-- This migration creates all core tables for the application
-- Includes: bots, matches, jobs, ratings, seasons, series, maps, programs, playlists, feedback, enrichment

-- =====================================================
-- Core Tables
-- =====================================================

CREATE TABLE bots (
    bot_id        VARCHAR(16) PRIMARY KEY,
    name          VARCHAR(32) UNIQUE NOT NULL,
    owner         VARCHAR(128) NOT NULL,
    endpoint_url  TEXT NOT NULL,
    shared_secret TEXT NOT NULL,
    status        VARCHAR(16) NOT NULL DEFAULT 'pending',
    rating_mu     DOUBLE PRECISION NOT NULL DEFAULT 1500.0,
    rating_phi    DOUBLE PRECISION NOT NULL DEFAULT 350.0,
    rating_sigma  DOUBLE PRECISION NOT NULL DEFAULT 0.06,
    evolved       BOOLEAN NOT NULL DEFAULT FALSE,
    island        VARCHAR(16),
    generation    INTEGER,
    parent_ids    JSONB,
    description   TEXT,
    created_at    TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    last_active   TIMESTAMPTZ,
    consec_fails  INTEGER NOT NULL DEFAULT 0,
    archetype     VARCHAR(64),
    crash_strikes INTEGER NOT NULL DEFAULT 0,
    cooldown_until TIMESTAMPTZ,
    debug_public  BOOLEAN NOT NULL DEFAULT FALSE
);

CREATE TABLE matches (
    match_id      VARCHAR(32) PRIMARY KEY,
    map_id        VARCHAR(32) NOT NULL,
    map_seed      BIGINT,
    status        VARCHAR(16) NOT NULL DEFAULT 'pending',
    winner        INTEGER,
    condition     VARCHAR(32),
    turn_count    INTEGER,
    combat_turns  INTEGER NOT NULL DEFAULT 0,
    scores_json   JSONB,
    enrichment_requested_at TIMESTAMPTZ,
    created_at    TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    completed_at  TIMESTAMPTZ
);

CREATE TABLE match_participants (
    match_id      VARCHAR(32) NOT NULL REFERENCES matches(match_id),
    bot_id        VARCHAR(16) NOT NULL REFERENCES bots(bot_id),
    player_slot   INTEGER NOT NULL,
    score         INTEGER,
    status        VARCHAR(16),
    PRIMARY KEY (match_id, bot_id)
);

CREATE TABLE jobs (
    job_id        VARCHAR(32) PRIMARY KEY,
    match_id      VARCHAR(32) NOT NULL REFERENCES matches(match_id),
    status        VARCHAR(16) NOT NULL DEFAULT 'pending',
    worker_id     VARCHAR(64),
    config_json   JSONB NOT NULL,
    claimed_at    TIMESTAMPTZ,
    completed_at  TIMESTAMPTZ,
    heartbeat_at  TIMESTAMPTZ,
    created_at    TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE TABLE rating_history (
    bot_id        VARCHAR(16) NOT NULL REFERENCES bots(bot_id),
    match_id      VARCHAR(32) NOT NULL REFERENCES matches(match_id),
    rating        DOUBLE PRECISION NOT NULL,
    recorded_at   TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    PRIMARY KEY (bot_id, match_id)
);
CREATE INDEX idx_rating_history_bot ON rating_history(bot_id, recorded_at);

-- =====================================================
-- Season & Series Tables (Phase 9)
-- =====================================================

CREATE TABLE seasons (
    id            BIGSERIAL PRIMARY KEY,
    name          VARCHAR(64) NOT NULL,
    theme         VARCHAR(128),
    rules_version VARCHAR(32) NOT NULL DEFAULT '1.0',
    status        VARCHAR(16) NOT NULL DEFAULT 'active',
    champion_id   VARCHAR(16),
    starts_at     TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    ends_at       TIMESTAMPTZ,
    created_at    TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE TABLE season_snapshots (
    id         BIGSERIAL PRIMARY KEY,
    season_id  BIGINT NOT NULL REFERENCES seasons(id),
    bot_id     VARCHAR(16) NOT NULL REFERENCES bots(bot_id),
    rank       INTEGER NOT NULL,
    rating     DOUBLE PRECISION NOT NULL,
    wins       INTEGER NOT NULL DEFAULT 0,
    losses     INTEGER NOT NULL DEFAULT 0,
    recorded_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_season_snapshots_season ON season_snapshots(season_id, rank);

CREATE TABLE series (
    id               BIGSERIAL PRIMARY KEY,
    bot_a_id         VARCHAR(16) NOT NULL REFERENCES bots(bot_id),
    bot_b_id         VARCHAR(16) NOT NULL REFERENCES bots(bot_id),
    format           INTEGER NOT NULL DEFAULT 5,
    a_wins           INTEGER NOT NULL DEFAULT 0,
    b_wins           INTEGER NOT NULL DEFAULT 0,
    status           VARCHAR(16) NOT NULL DEFAULT 'active',
    winner_id        VARCHAR(16),
    season_id        BIGINT REFERENCES seasons(id),
    bracket_round    VARCHAR(32),
    bracket_position INTEGER,
    featured         BOOLEAN NOT NULL DEFAULT FALSE,
    created_at       TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at       TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_series_bots ON series(bot_a_id, bot_b_id);
CREATE INDEX idx_series_status ON series(status);
CREATE INDEX idx_series_season ON series(season_id);
CREATE INDEX idx_series_bracket ON series(season_id, bracket_round) WHERE bracket_round IS NOT NULL;
CREATE INDEX idx_series_featured ON series(featured, created_at DESC) WHERE featured = TRUE;

CREATE TABLE series_games (
    id        BIGSERIAL PRIMARY KEY,
    series_id BIGINT NOT NULL REFERENCES series(id),
    match_id  VARCHAR(32) REFERENCES matches(match_id),
    game_num  INTEGER NOT NULL,
    winner_id VARCHAR(16),
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_series_games_series ON series_games(series_id);

-- =====================================================
-- Prediction Tables
-- =====================================================

CREATE TABLE predictions (
    id            BIGSERIAL PRIMARY KEY,
    match_id      VARCHAR(32) NOT NULL REFERENCES matches(match_id),
    predictor_id  VARCHAR(64) NOT NULL,
    predicted_bot VARCHAR(16) NOT NULL,
    confidence    SMALLINT CHECK (confidence >= 1 AND confidence <= 100),
    correct       BOOLEAN,
    created_at    TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    resolved_at   TIMESTAMPTZ,
    UNIQUE(match_id, predictor_id)
);
CREATE INDEX idx_predictions_match ON predictions(match_id);
CREATE INDEX idx_predictions_predictor ON predictions(predictor_id);

CREATE TABLE predictor_stats (
    predictor_id  VARCHAR(64) PRIMARY KEY,
    correct       INTEGER NOT NULL DEFAULT 0,
    incorrect     INTEGER NOT NULL DEFAULT 0,
    streak        INTEGER NOT NULL DEFAULT 0,
    best_streak   INTEGER NOT NULL DEFAULT 0,
    updated_at    TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

-- =====================================================
-- Map Tables
-- =====================================================

CREATE TABLE maps (
    map_id          VARCHAR(32) PRIMARY KEY,
    player_count    INTEGER NOT NULL,
    status          VARCHAR(16) NOT NULL DEFAULT 'active',
    engagement      DOUBLE PRECISION NOT NULL DEFAULT 0.0,
    wall_density    DOUBLE PRECISION NOT NULL DEFAULT 0.0,
    energy_count    INTEGER NOT NULL DEFAULT 0,
    grid_width      INTEGER NOT NULL,
    grid_height     INTEGER NOT NULL,
    map_json        JSONB NOT NULL,
    created_at      TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    retired_at      TIMESTAMPTZ
);
CREATE INDEX idx_maps_status ON maps(status, player_count);
CREATE INDEX idx_maps_engagement ON maps(player_count, engagement DESC);

CREATE TABLE map_scores (
    map_id          VARCHAR(32) PRIMARY KEY,
    engagement      DOUBLE PRECISION NOT NULL DEFAULT 0.0,
    symmetry_score  DOUBLE PRECISION NOT NULL DEFAULT 0.0,
    wall_density    DOUBLE PRECISION NOT NULL DEFAULT 0.0,
    last_used_at    TIMESTAMPTZ,
    match_count     INTEGER NOT NULL DEFAULT 0,
    avg_turns       DOUBLE PRECISION,
    scored_at       TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE TABLE map_votes (
    id          BIGSERIAL PRIMARY KEY,
    map_id      VARCHAR(32) NOT NULL REFERENCES maps(map_id) ON DELETE CASCADE,
    voter_id    VARCHAR(64) NOT NULL,
    vote        SMALLINT NOT NULL,
    created_at  TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    UNIQUE(map_id, voter_id)
);
CREATE INDEX idx_map_votes_map ON map_votes(map_id);

CREATE TABLE map_fairness (
    map_id      VARCHAR(32) NOT NULL REFERENCES maps(map_id) ON DELETE CASCADE,
    player_slot INTEGER NOT NULL,
    games       INTEGER NOT NULL DEFAULT 0,
    wins        INTEGER NOT NULL DEFAULT 0,
    last_check  TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    PRIMARY KEY (map_id, player_slot)
);

-- =====================================================
-- Program Tables (Evolution)
-- =====================================================

CREATE TABLE programs (
    id              BIGSERIAL PRIMARY KEY,
    code            TEXT NOT NULL,
    language        VARCHAR(32) NOT NULL,
    island          VARCHAR(16) NOT NULL,
    generation      INTEGER NOT NULL DEFAULT 0,
    parent_ids      JSONB NOT NULL DEFAULT '[]',
    behavior_vector DOUBLE PRECISION[] NOT NULL DEFAULT '{}',
    fitness         DOUBLE PRECISION NOT NULL DEFAULT 0.0,
    promoted        BOOLEAN NOT NULL DEFAULT FALSE,
    created_at      TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_programs_island ON programs(island);
CREATE INDEX idx_programs_island_fitness ON programs(island, fitness DESC);

-- =====================================================
-- Playlist Tables
-- =====================================================

CREATE TABLE playlists (
    slug        VARCHAR(64) PRIMARY KEY,
    title       VARCHAR(128) NOT NULL,
    description TEXT NOT NULL DEFAULT '',
    category    VARCHAR(32) NOT NULL DEFAULT 'featured',
    is_auto     BOOLEAN NOT NULL DEFAULT TRUE,
    created_at  TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at  TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE TABLE playlist_matches (
    playlist_slug VARCHAR(64) NOT NULL REFERENCES playlists(slug) ON DELETE CASCADE,
    match_id      VARCHAR(32) NOT NULL REFERENCES matches(match_id),
    sort_order    INTEGER NOT NULL DEFAULT 0,
    curation_tag  TEXT NOT NULL DEFAULT '',
    added_at      TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    PRIMARY KEY (playlist_slug, match_id)
);
CREATE INDEX idx_playlist_matches_playlist ON playlist_matches(playlist_slug, sort_order);

-- =====================================================
-- Feedback Tables
-- =====================================================

CREATE TABLE replay_feedback (
    feedback_id   VARCHAR(32) PRIMARY KEY,
    match_id      VARCHAR(32) NOT NULL REFERENCES matches(match_id),
    turn          INTEGER NOT NULL,
    type          VARCHAR(16) NOT NULL CHECK (type IN ('insight', 'mistake', 'idea', 'highlight')),
    body          TEXT NOT NULL,
    author        VARCHAR(128) NOT NULL,
    upvotes       INTEGER NOT NULL DEFAULT 0,
    created_at    TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_feedback_match ON replay_feedback(match_id, turn);

CREATE TABLE feedback_upvotes (
    feedback_id VARCHAR(32) NOT NULL REFERENCES replay_feedback(feedback_id) ON DELETE CASCADE,
    voter_id    VARCHAR(36) NOT NULL,
    created_at  TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    PRIMARY KEY (feedback_id, voter_id)
);

-- =====================================================
-- Enrichment Tables
-- =====================================================

CREATE TABLE enrichment_requests (
    request_id   VARCHAR(32) PRIMARY KEY,
    match_id     VARCHAR(32) NOT NULL REFERENCES matches(match_id),
    bot_id       VARCHAR(16) NOT NULL REFERENCES bots(bot_id),
    status       VARCHAR(16) NOT NULL DEFAULT 'pending',
    requested_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    processed_at TIMESTAMPTZ,
    error_msg    TEXT,
    UNIQUE(match_id, bot_id)
);
CREATE INDEX idx_enrichment_requests_status ON enrichment_requests(status, requested_at);
CREATE INDEX idx_enrichment_requests_bot ON enrichment_requests(bot_id, requested_at);
