-- TTS layer schema. Synthesis pipeline lands in v0.2; the schema
-- ships now so v0.1 imports already carry the right shape.
--
-- Voice sources are restricted to AI-consent-released training
-- corpora (LJ Speech, Hi-Fi TTS, VCTK, LibriTTS-R) so generated
-- audio is airtight to share — even if a story eventually lands
-- on a public site. LibriVox narrators are not seed defaults; if
-- the operator adds one they accept the "volunteered for
-- public-domain reading, didn't sign up for AI cloning" caveat.

CREATE TABLE voices (
    id                UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    name              TEXT NOT NULL UNIQUE,
    display_name      TEXT NOT NULL,
    gender            TEXT,
    accent            TEXT,
    -- Source identifier — e.g. "lj_speech", "hifi_tts:92",
    -- "vctk:p225", "librivox:phil-chenevert", "self".
    source            TEXT NOT NULL,
    -- License posture — "PD-ai-consent" (LJ Speech, Hi-Fi TTS,
    -- VCTK, LibriTTS-R, etc — corpora released specifically for
    -- TTS training), "PD-non-ai" (raw LibriVox, weaker consent),
    -- "self" (operator's own recording), "licensed" (paid voice
    -- with explicit cloning rights).
    license           TEXT NOT NULL,
    -- On-disk path inside the container to a 10-15s reference WAV.
    -- Nullable: a row can be metadata-only until the operator
    -- places the audio.
    reference_path    TEXT,
    -- Transcript of `reference_path`. F5-TTS needs both the audio
    -- and the text to clone.
    reference_text    TEXT,
    sample_rate_hz    INTEGER,
    duration_seconds  REAL,
    notes             TEXT,
    is_default        BOOLEAN NOT NULL DEFAULT false,
    created_at        TIMESTAMPTZ NOT NULL DEFAULT now()
);

-- At most one default voice.
CREATE UNIQUE INDEX idx_voices_one_default
    ON voices((is_default))
    WHERE is_default = true;

-- Per-story (and optionally global) pronunciation overrides. The
-- TTS pipeline pre-processes every chapter text through this map
-- before handing it to F5. Solves the proper-noun problem
-- (Pripyat, Dyatlov, Toptunov, etc) without retraining.
CREATE TABLE pronunciation_overrides (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    -- NULL story_id = global default across all stories.
    story_id        UUID REFERENCES stories(id) ON DELETE CASCADE,
    word            TEXT NOT NULL,
    -- The phonemes string in `phoneme_format` notation. e.g. IPA
    -- /ˈpɹɪpʲɪt/ or arpabet "P R IH1 P Y AH0 T".
    phonemes        TEXT NOT NULL,
    -- "ipa" | "arpabet" | "espeak" | "raw"  — depends on what F5
    -- accepts in the rendering pipeline.
    phoneme_format  TEXT NOT NULL DEFAULT 'ipa',
    notes           TEXT,
    -- "auto" = LLM-generated (Opus extracted proper nouns + IPA).
    -- "manual" = hand-edited.
    source          TEXT NOT NULL DEFAULT 'manual'
                    CHECK (source IN ('auto', 'manual')),
    created_at      TIMESTAMPTZ NOT NULL DEFAULT now()
);

-- One row per (story, word) pair.
CREATE UNIQUE INDEX idx_pron_overrides_story_word
    ON pronunciation_overrides(story_id, word)
    WHERE story_id IS NOT NULL;

-- One global row per word (NULL story_id).
CREATE UNIQUE INDEX idx_pron_overrides_global_word
    ON pronunciation_overrides(word)
    WHERE story_id IS NULL;

CREATE INDEX idx_pron_overrides_story ON pronunciation_overrides(story_id);

-- Stories can declare a preferred voice. NULL → fall back to the
-- system-default voice (voices.is_default = true).
ALTER TABLE stories
    ADD COLUMN preferred_voice_id UUID REFERENCES voices(id) ON DELETE SET NULL;

CREATE INDEX idx_stories_preferred_voice ON stories(preferred_voice_id);

-- A narration_runs table mirroring generation_runs but for TTS
-- jobs. Each chapter render is a row. Keeps narration audit trail
-- separate from text-generation audit trail.
CREATE TABLE narration_runs (
    id                  UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    chapter_id          UUID NOT NULL REFERENCES chapters(id) ON DELETE CASCADE,
    voice_id            UUID NOT NULL REFERENCES voices(id) ON DELETE CASCADE,
    -- "f5-tts" | "xtts-v2" | future engines.
    engine              TEXT NOT NULL,
    engine_version      TEXT,
    -- Output WAV/MP3 on disk. Nullable until the run completes.
    output_path         TEXT,
    duration_seconds    REAL,
    seed                BIGINT,
    started_at          TIMESTAMPTZ NOT NULL DEFAULT now(),
    ended_at            TIMESTAMPTZ,
    status              TEXT NOT NULL DEFAULT 'running'
                        CHECK (status IN ('running', 'succeeded', 'failed', 'rerolled')),
    error               TEXT
);

CREATE INDEX idx_narration_runs_chapter ON narration_runs(chapter_id);
CREATE INDEX idx_narration_runs_voice ON narration_runs(voice_id);
