-- #186. What subtitles exist for a media file, and what arr has tried per
-- wanted language (DESIGN.md §15). Settings rows (#198) and the budget
-- buckets (#197) are deliberately absent.

-- One row per subtitle arr knows about. An embedded track that was never
-- extracted has no `path`: it is recorded because it satisfies a language,
-- not because there is a file. Everything else is a sidecar next to the
-- video (§15, §7.4), so the path is the row's identity on disk.
CREATE TABLE subtitle_files (
    id            INTEGER PRIMARY KEY,
    media_file_id INTEGER NOT NULL REFERENCES media_files (id) ON DELETE CASCADE,
    -- As `arr_core::Language` spells it: `pt-PT`, `pt-BR`, `en`.
    language      TEXT NOT NULL,
    origin        TEXT NOT NULL
                  CHECK (origin IN ('embedded', 'extracted', 'provider', 'translated')),
    -- §15. The named provider a fetch came from, and the candidate id it was
    -- ranked as, so a re-fetch of the same candidate is recognisable.
    provider      TEXT,
    candidate_id  TEXT,
    -- §15. The translation backend that produced it, when machine made.
    engine        TEXT,
    -- §15. A forced track never satisfies a want; an SDH one does, ranked
    -- below a plain subtitle. Both are facts about the file, so both are
    -- stored and the ranking rule stays in `arr-core`.
    forced        INTEGER NOT NULL DEFAULT 0 CHECK (forced IN (0, 1)),
    sdh           INTEGER NOT NULL DEFAULT 0 CHECK (sdh IN (0, 1)),
    -- §15. `alass` reports no confidence, so its output is accepted unless
    -- implausible. `synced` is an accepted shift; `sync_rejected` means the
    -- unsynced original was kept and this file is flagged. Never both.
    synced        INTEGER NOT NULL DEFAULT 0 CHECK (synced IN (0, 1)),
    sync_rejected INTEGER NOT NULL DEFAULT 0 CHECK (sync_rejected IN (0, 1)),
    path          TEXT UNIQUE,
    created_at    TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
    updated_at    TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
    CHECK ((path IS NULL) = (origin = 'embedded')),
    CHECK ((provider IS NOT NULL) = (origin = 'provider')),
    CHECK (candidate_id IS NULL OR provider IS NOT NULL),
    CHECK ((engine IS NOT NULL) = (origin = 'translated')),
    CHECK (NOT (synced = 1 AND sync_rejected = 1))
) STRICT;

-- §15's satisfaction check is "is there a subtitle in this language", asked
-- per file per tick.
CREATE INDEX subtitle_files_media_file ON subtitle_files (media_file_id, language);

-- An embedded track is identified by what it satisfies, not by a file, so a
-- second probe of the same video re-records it rather than duplicating it.
CREATE UNIQUE INDEX subtitle_files_embedded
    ON subtitle_files (media_file_id, language, forced, sdh)
    WHERE origin = 'embedded';

-- One row per (media file, wanted language). What the reconcile loop reads to
-- decide whether a language is a gap, what backs a failing provider off, and
-- what the missing-subtitles queue renders.
--
-- `capped` is a state and not an error (§15): being at a daily allowance is
-- something the queue shows. The allowance itself is #197 and not here.
-- `unavailable` is the end of the line — no provider has it and there is no
-- text source to translate from, so retrying costs budget for nothing.
CREATE TABLE subtitle_attempts (
    media_file_id   INTEGER NOT NULL REFERENCES media_files (id) ON DELETE CASCADE,
    language        TEXT NOT NULL,
    state           TEXT NOT NULL DEFAULT 'wanted'
                    CHECK (state IN ('wanted', 'satisfied', 'failed', 'capped', 'unavailable')),
    attempts        INTEGER NOT NULL DEFAULT 0 CHECK (attempts >= 0),
    last_attempt_at TEXT,
    -- Why the last attempt failed, for the queue and for backoff. Cleared
    -- when an attempt succeeds.
    last_failure    TEXT,
    created_at      TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
    updated_at      TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ', 'now')),
    PRIMARY KEY (media_file_id, language),
    CHECK ((attempts = 0) = (last_attempt_at IS NULL))
) STRICT;

-- §8, §15. The work list is every language that is not satisfied yet, least
-- recently attempted first within it; the ordering across files is
-- newest-import-first and comes from the join to `media_files`.
CREATE INDEX subtitle_attempts_pending
    ON subtitle_attempts (state, last_attempt_at)
    WHERE state <> 'satisfied';
