-- t-paliad-349 (m/paliad#157): docforge slice 4 — template authoring tables.
--
-- These three tables are the persistence home for the docforge authoring
-- flow (upload a base .docx → place variable slots → save as a reusable
-- template) and the generation flow (pick a template → bind data →
-- export). They are paliad's implementation of the docforge.TemplateStore
-- contract; docforge itself owns no tables (the litigationplanner pattern).
--
-- Generic on purpose (NOT submission_*-named): authoring is a
-- domain-neutral capability, so the eventual second docforge consumer can
-- reuse the same shape. submission_bases (Gitea-backed, section_spec) stays
-- for the legacy base catalog during the transition; convergence is a
-- later, separate task.
--
--   paliad.templates          — one row per template (the catalog entry).
--   paliad.template_versions  — immutable snapshots; editing a template
--                               inserts a new version. The carrier .docx
--                               bytes live here (bytea) — the TemplateStore
--                               bytea backend. A draft pins a version
--                               (snapshot-at-create, PRD §4 A3) so later
--                               edits don't shift an in-flight draft.
--   paliad.template_slots     — the variable slots placed in a version's
--                               carrier. anchor is the sentinel token the
--                               authoring surface injects into the carrier
--                               OOXML to locate the slot (PRD §5 lean);
--                               slot_key is the variable bound there.
--
-- Visibility: the template catalog is shared firm-wide (every
-- authenticated user generates from it), so SELECT is open to
-- authenticated, mirroring submission_bases. Mutations (upload, edit) are
-- admin-only and gated in Go at the handler layer — no INSERT/UPDATE/DELETE
-- RLS path means RLS denies them by default.
--
-- Slice 4 ships the schema + the TemplateStore only; no rows are seeded and
-- no UI writes here yet (authoring is slice 6, generation-on-templates is
-- slice 7).

CREATE TABLE IF NOT EXISTS paliad.templates (
    id                 uuid PRIMARY KEY DEFAULT gen_random_uuid(),
    slug               text UNIQUE,
    name_de            text NOT NULL,
    name_en            text NOT NULL,
    kind               text NOT NULL DEFAULT 'submission',
    source_format      text NOT NULL DEFAULT 'docx',
    firm               text,
    is_active          bool NOT NULL DEFAULT true,
    current_version_id uuid,
    created_by         uuid NOT NULL,
    created_at         timestamptz NOT NULL DEFAULT now(),
    updated_at         timestamptz NOT NULL DEFAULT now(),

    CONSTRAINT templates_source_format_check CHECK (source_format IN ('docx'))
);

CREATE TABLE IF NOT EXISTS paliad.template_versions (
    id           uuid PRIMARY KEY DEFAULT gen_random_uuid(),
    template_id  uuid NOT NULL REFERENCES paliad.templates(id) ON DELETE CASCADE,
    version      int  NOT NULL,
    carrier_blob bytea NOT NULL,
    stylemap     jsonb NOT NULL DEFAULT '{}'::jsonb,
    created_by   uuid NOT NULL,
    created_at   timestamptz NOT NULL DEFAULT now(),

    CONSTRAINT template_versions_unique_per_template UNIQUE (template_id, version)
);

CREATE TABLE IF NOT EXISTS paliad.template_slots (
    id                  uuid PRIMARY KEY DEFAULT gen_random_uuid(),
    template_version_id uuid NOT NULL REFERENCES paliad.template_versions(id) ON DELETE CASCADE,
    slot_key            text NOT NULL,
    anchor              text NOT NULL,
    label               text,
    order_index         int  NOT NULL DEFAULT 0,
    created_at          timestamptz NOT NULL DEFAULT now(),

    CONSTRAINT template_slots_unique_anchor UNIQUE (template_version_id, anchor)
);

-- current_version_id FK is added after template_versions exists to avoid a
-- circular CREATE-TABLE dependency. ON DELETE SET NULL: dropping the
-- pinned version detaches it rather than cascading the template away.
ALTER TABLE paliad.templates
    DROP CONSTRAINT IF EXISTS templates_current_version_fk;
ALTER TABLE paliad.templates
    ADD CONSTRAINT templates_current_version_fk
    FOREIGN KEY (current_version_id)
    REFERENCES paliad.template_versions(id) ON DELETE SET NULL;

CREATE INDEX IF NOT EXISTS templates_firm_kind_idx
    ON paliad.templates (firm, kind) WHERE is_active;
CREATE INDEX IF NOT EXISTS template_versions_template_idx
    ON paliad.template_versions (template_id, version);
CREATE INDEX IF NOT EXISTS template_slots_version_idx
    ON paliad.template_slots (template_version_id, order_index);

ALTER TABLE paliad.templates         ENABLE ROW LEVEL SECURITY;
ALTER TABLE paliad.template_versions ENABLE ROW LEVEL SECURITY;
ALTER TABLE paliad.template_slots    ENABLE ROW LEVEL SECURITY;

-- Firm-shared catalog: any authenticated user reads. Mutations are
-- admin-only, gated in Go (no mutation RLS policy = RLS denies by default).
DROP POLICY IF EXISTS templates_select ON paliad.templates;
CREATE POLICY templates_select
    ON paliad.templates FOR SELECT TO authenticated
    USING (true);

DROP POLICY IF EXISTS template_versions_select ON paliad.template_versions;
CREATE POLICY template_versions_select
    ON paliad.template_versions FOR SELECT TO authenticated
    USING (true);

DROP POLICY IF EXISTS template_slots_select ON paliad.template_slots;
CREATE POLICY template_slots_select
    ON paliad.template_slots FOR SELECT TO authenticated
    USING (true);

DROP TRIGGER IF EXISTS templates_set_updated_at ON paliad.templates;
CREATE TRIGGER templates_set_updated_at
    BEFORE UPDATE ON paliad.templates
    FOR EACH ROW EXECUTE FUNCTION paliad.tg_set_updated_at();

COMMENT ON TABLE paliad.templates IS
    't-paliad-349: docforge template catalog. One row per uploaded template; current_version_id pins the live version.';
COMMENT ON TABLE paliad.template_versions IS
    't-paliad-349: immutable docforge template snapshots. carrier_blob holds the base .docx bytes (TemplateStore bytea backend).';
COMMENT ON TABLE paliad.template_slots IS
    't-paliad-349: variable slots placed in a template version. anchor = sentinel token locating the slot in the carrier OOXML; slot_key = the bound variable.';
