-- 988_dmca_notices.sql
-- v1.0.9 W3 Day 14 — DMCA notice handler + workflow.
--
-- Creates the table that holds incoming DMCA takedown requests + the
-- admin's response trail, and adds a `dmca_blocked` flag on tracks
-- so a takedown is enforced both at the visibility layer (is_public)
-- AND at the playback layer (dmca_blocked stops authenticated owners
-- from playing back too).
--
-- Workflow states :
--   pending       — submitted by claimant, waiting for admin review
--   takedown      — admin honored the takedown ; track is_public=false + dmca_blocked=true
--   dismissed     — admin rejected the notice (insufficient grounds, fraud, ...)
--   counter_notice — uploader filed a counter-notice ; tracking only, no auto-restore
--   restored      — admin reviewed the counter-notice and restored the track
--
-- audit_log : JSONB array of {ts, actor_user_id, action, note} entries,
-- appended on every state change. Lets us reconstruct the trail without
-- joining audit_logs (which has cardinality issues on hot queries).

CREATE TABLE IF NOT EXISTS public.dmca_notices (
    id                  UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    status              VARCHAR(32) NOT NULL DEFAULT 'pending'
        CHECK (status IN ('pending', 'takedown', 'dismissed', 'counter_notice', 'restored')),

    -- Claimant identity (required by 17 USC § 512(c)(3) — DMCA safe harbor).
    claimant_email      VARCHAR(255) NOT NULL,
    claimant_name       VARCHAR(255) NOT NULL,
    claimant_address    TEXT         NOT NULL,
    work_description    TEXT         NOT NULL,

    -- The allegedly infringing track. ON DELETE SET NULL — keep the
    -- record if the track is deleted later (audit trail must persist).
    infringing_track_id UUID         REFERENCES public.tracks(id) ON DELETE SET NULL,

    -- "Under penalty of perjury" statement — the claimant must check
    -- a box; we record the timestamp it was acknowledged. Required by
    -- DMCA § 512(c)(3)(A)(vi).
    sworn_statement_at  TIMESTAMPTZ  NOT NULL,

    -- Admin action trail.
    takedown_at         TIMESTAMPTZ,
    counter_notice_at   TIMESTAMPTZ,
    restored_at         TIMESTAMPTZ,

    -- Free-form audit trail. Each entry : {ts, actor_user_id, action, note}.
    audit_log           JSONB        NOT NULL DEFAULT '[]'::jsonb,

    created_at          TIMESTAMPTZ  NOT NULL DEFAULT now(),
    updated_at          TIMESTAMPTZ  NOT NULL DEFAULT now()
);

-- Pending queue index — admin lists pending notices oldest-first.
CREATE INDEX IF NOT EXISTS idx_dmca_notices_pending
    ON public.dmca_notices(created_at ASC)
    WHERE status = 'pending';

-- Lookup by track — when an admin opens a track they should see if any
-- DMCA history exists.
CREATE INDEX IF NOT EXISTS idx_dmca_notices_track
    ON public.dmca_notices(infringing_track_id)
    WHERE infringing_track_id IS NOT NULL;

COMMENT ON TABLE public.dmca_notices IS
    'DMCA takedown requests + admin response trail. v1.0.9 W3 Day 14.';
COMMENT ON COLUMN public.dmca_notices.audit_log IS
    'JSONB array of {ts, actor_user_id, action, note} appended on each state change.';

-- ---------------------------------------------------------------------
-- Track flag : dmca_blocked. When TRUE, no playback path serves the
-- track regardless of `is_public`. The visibility flag (is_public)
-- gets flipped too, but `dmca_blocked` is the authoritative gate
-- because an owner can re-public their own track in the UI ; only
-- a `restored_at` action on the notice clears the block.
-- ---------------------------------------------------------------------
ALTER TABLE public.tracks
    ADD COLUMN IF NOT EXISTS dmca_blocked BOOLEAN NOT NULL DEFAULT FALSE;

COMMENT ON COLUMN public.tracks.dmca_blocked IS
    'TRUE when a DMCA takedown is in force ; gates playback regardless of is_public. v1.0.9 W3 Day 14.';

-- updated_at maintenance trigger, mirroring the pattern used elsewhere.
CREATE OR REPLACE FUNCTION dmca_notices_updated_at()
RETURNS TRIGGER AS $$
BEGIN
    NEW.updated_at = now();
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

DROP TRIGGER IF EXISTS dmca_notices_updated_at_trg ON public.dmca_notices;
CREATE TRIGGER dmca_notices_updated_at_trg
    BEFORE UPDATE ON public.dmca_notices
    FOR EACH ROW
    EXECUTE FUNCTION dmca_notices_updated_at();
