-- Migration 078: Vereins-Feature-Registry (Mitai-v9c-Pattern) + club_plans/subscriptions
-- Spez: .claude/docs/technical/CLUB_MEMBERSHIP_AND_FEATURES.v1.md (M1)
-- Legacy 001 (SERIAL features, profile tier_limits) wird archiviert, nicht gelöscht.

-- ── 1. Legacy-Tabellen archivieren (nur alte Struktur) ─────────────────────
DO $migration$
BEGIN
    IF EXISTS (
        SELECT 1 FROM information_schema.tables
        WHERE table_schema = 'public' AND table_name = 'features'
    ) AND EXISTS (
        SELECT 1 FROM information_schema.columns
        WHERE table_schema = 'public' AND table_name = 'features' AND column_name = 'name'
    ) AND NOT EXISTS (
        SELECT 1 FROM information_schema.columns
        WHERE table_schema = 'public' AND table_name = 'features' AND column_name = 'limit_type'
    ) THEN
        ALTER TABLE features RENAME TO features_legacy_001;
    END IF;

    IF EXISTS (
        SELECT 1 FROM information_schema.tables
        WHERE table_schema = 'public' AND table_name = 'tier_limits'
    ) AND EXISTS (
        SELECT 1 FROM information_schema.columns
        WHERE table_schema = 'public' AND table_name = 'tier_limits' AND column_name = 'tier'
    ) THEN
        ALTER TABLE tier_limits RENAME TO tier_limits_legacy_001;
    END IF;

    IF EXISTS (
        SELECT 1 FROM information_schema.tables
        WHERE table_schema = 'public' AND table_name = 'user_feature_usage'
    ) AND EXISTS (
        SELECT 1 FROM information_schema.columns
        WHERE table_schema = 'public' AND table_name = 'user_feature_usage' AND column_name = 'profile_id'
    ) THEN
        ALTER TABLE user_feature_usage RENAME TO user_feature_usage_legacy_001;
    END IF;
END
$migration$;

-- ── 2. Feature-Registry (TEXT-PK, app=shinkan) ────────────────────────────
CREATE TABLE IF NOT EXISTS features (
    id                  TEXT PRIMARY KEY,
    app                 TEXT NOT NULL DEFAULT 'shinkan',
    name                TEXT NOT NULL,
    description         TEXT,
    category            TEXT NOT NULL DEFAULT 'content',
    limit_type          TEXT NOT NULL DEFAULT 'count'
        CHECK (limit_type IN ('count', 'boolean')),
    reset_period        TEXT NOT NULL DEFAULT 'never'
        CHECK (reset_period IN ('never', 'daily', 'monthly')),
    default_limit       INTEGER,
    enforcement_subject TEXT NOT NULL DEFAULT 'club'
        CHECK (enforcement_subject IN ('club', 'profile', 'portal')),
    active              BOOLEAN NOT NULL DEFAULT true,
    created_at          TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at          TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE INDEX IF NOT EXISTS idx_features_app ON features(app) WHERE active = true;

-- ── 3. Vereins-Produkte ─────────────────────────────────────────────────────
CREATE TABLE IF NOT EXISTS club_plans (
    id                  TEXT PRIMARY KEY,
    name                TEXT NOT NULL,
    description         TEXT,
    price_monthly_cents INTEGER,
    price_yearly_cents  INTEGER,
    stripe_price_id_monthly TEXT,
    stripe_price_id_yearly  TEXT,
    active              BOOLEAN NOT NULL DEFAULT true,
    sort_order          INTEGER NOT NULL DEFAULT 0,
    created_at          TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at          TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE TABLE IF NOT EXISTS club_plan_limits (
    id              SERIAL PRIMARY KEY,
    plan_id         TEXT NOT NULL REFERENCES club_plans(id) ON DELETE CASCADE,
    feature_id      TEXT NOT NULL REFERENCES features(id) ON DELETE CASCADE,
    limit_value     INTEGER,
    UNIQUE (plan_id, feature_id)
);

CREATE INDEX IF NOT EXISTS idx_club_plan_limits_plan ON club_plan_limits(plan_id);

CREATE TABLE IF NOT EXISTS club_subscriptions (
    id              SERIAL PRIMARY KEY,
    club_id         INT NOT NULL REFERENCES clubs(id) ON DELETE CASCADE,
    plan_id         TEXT NOT NULL REFERENCES club_plans(id),
    status          TEXT NOT NULL DEFAULT 'active'
        CHECK (status IN ('active', 'trial', 'past_due', 'cancelled')),
    started_at      TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    ends_at         TIMESTAMPTZ,
    trial_ends_at   TIMESTAMPTZ,
    created_at      TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at      TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    UNIQUE (club_id)
);

CREATE INDEX IF NOT EXISTS idx_club_subscriptions_plan ON club_subscriptions(plan_id);

CREATE TABLE IF NOT EXISTS club_feature_overrides (
    id                  SERIAL PRIMARY KEY,
    club_id             INT NOT NULL REFERENCES clubs(id) ON DELETE CASCADE,
    feature_id          TEXT NOT NULL REFERENCES features(id) ON DELETE CASCADE,
    limit_value         INTEGER NOT NULL,
    reason              TEXT,
    set_by_profile_id   INT REFERENCES profiles(id) ON DELETE SET NULL,
    created_at          TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    UNIQUE (club_id, feature_id)
);

CREATE TABLE IF NOT EXISTS club_access_grants (
    id                      SERIAL PRIMARY KEY,
    club_id                 INT NOT NULL REFERENCES clubs(id) ON DELETE CASCADE,
    plan_id                 TEXT REFERENCES club_plans(id) ON DELETE SET NULL,
    feature_id              TEXT REFERENCES features(id) ON DELETE SET NULL,
    grant_limit             INTEGER,
    starts_at               TIMESTAMPTZ NOT NULL,
    ends_at                 TIMESTAMPTZ NOT NULL,
    reason                  TEXT,
    created_by_profile_id   INT REFERENCES profiles(id) ON DELETE SET NULL,
    created_at              TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE INDEX IF NOT EXISTS idx_club_access_grants_club ON club_access_grants(club_id);
CREATE INDEX IF NOT EXISTS idx_club_access_grants_window ON club_access_grants(club_id, starts_at, ends_at);

CREATE TABLE IF NOT EXISTS club_feature_usage (
    id              SERIAL PRIMARY KEY,
    club_id         INT NOT NULL REFERENCES clubs(id) ON DELETE CASCADE,
    feature_id      TEXT NOT NULL REFERENCES features(id) ON DELETE CASCADE,
    usage_count     INTEGER NOT NULL DEFAULT 0,
    reset_at        TIMESTAMPTZ,
    last_used_at    TIMESTAMPTZ,
    created_at      TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at      TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    UNIQUE (club_id, feature_id)
);

CREATE INDEX IF NOT EXISTS idx_club_feature_usage_club ON club_feature_usage(club_id);

CREATE TABLE IF NOT EXISTS club_feature_usage_events (
    id              BIGSERIAL PRIMARY KEY,
    club_id         INT NOT NULL REFERENCES clubs(id) ON DELETE CASCADE,
    feature_id      TEXT NOT NULL REFERENCES features(id) ON DELETE CASCADE,
    profile_id      INT REFERENCES profiles(id) ON DELETE SET NULL,
    action          TEXT NOT NULL,
    created_at      TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE INDEX IF NOT EXISTS idx_club_feature_usage_events_club
    ON club_feature_usage_events(club_id, created_at DESC);

-- ── 4. Seed: Features ─────────────────────────────────────────────────────
INSERT INTO features (id, app, name, description, category, limit_type, reset_period, default_limit, enforcement_subject)
VALUES
    ('exercises', 'shinkan', 'Übungen', 'Anzahl Übungen im Verein (Bestand)', 'content', 'count', 'never', 100, 'club'),
    ('exercise_media', 'shinkan', 'Medien-Uploads', 'Medien-Uploads pro Monat', 'content', 'count', 'monthly', 20, 'club'),
    ('training_units', 'shinkan', 'Trainingseinheiten', 'Trainingseinheiten pro Monat', 'planning', 'count', 'monthly', 40, 'club'),
    ('training_programs', 'shinkan', 'Trainingsprogramme', 'Module und Rahmenprogramme (Bestand)', 'planning', 'count', 'never', 5, 'club'),
    ('training_groups', 'shinkan', 'Trainingsgruppen', 'Anzahl Trainingsgruppen', 'org', 'count', 'never', 10, 'club'),
    ('active_members', 'shinkan', 'Aktive Mitglieder', 'Anzahl aktiver Vereinsmitglieder', 'org', 'count', 'never', 25, 'club'),
    ('ai_calls', 'shinkan', 'KI-Aufrufe', 'KI-Aufrufe pro Monat (Suggest, Regenerate, Planung)', 'ai', 'count', 'monthly', 0, 'club'),
    ('ai_pipeline', 'shinkan', 'KI-Pipeline', 'Erweiterte KI-Batch-Pipelines', 'ai', 'boolean', 'never', 0, 'club'),
    ('wiki_import', 'shinkan', 'Wiki-Import', 'MediaWiki-Import (Plattform)', 'integration', 'boolean', 'never', 0, 'portal'),
    ('data_export', 'shinkan', 'Daten-Export', 'Export-Funktionen', 'integration', 'boolean', 'never', 0, 'club')
ON CONFLICT (id) DO NOTHING;

-- ── 5. Seed: Pläne ──────────────────────────────────────────────────────────
INSERT INTO club_plans (id, name, description, sort_order, active)
VALUES
    ('free', 'Free', 'Einstieg für Vereine', 0, true),
    ('verein_starter', 'Verein Starter', 'Erweiterte Kontingente', 10, true),
    ('verein_pro', 'Verein Pro', 'Hohe Limits und KI-Kontingent', 20, true),
    ('pilot', 'Pilot', 'Pilotverein mit großzügigen Limits', 5, true)
ON CONFLICT (id) DO NOTHING;

-- Plan-Limits: free
INSERT INTO club_plan_limits (plan_id, feature_id, limit_value)
SELECT 'free', f.id,
    CASE f.id
        WHEN 'exercises' THEN 100
        WHEN 'exercise_media' THEN 20
        WHEN 'training_units' THEN 40
        WHEN 'training_programs' THEN 5
        WHEN 'training_groups' THEN 10
        WHEN 'active_members' THEN 25
        WHEN 'ai_calls' THEN 0
        WHEN 'ai_pipeline' THEN 0
        WHEN 'wiki_import' THEN 0
        WHEN 'data_export' THEN 0
    END
FROM features f
WHERE f.app = 'shinkan'
ON CONFLICT (plan_id, feature_id) DO NOTHING;

-- Plan-Limits: verein_starter
INSERT INTO club_plan_limits (plan_id, feature_id, limit_value)
SELECT 'verein_starter', f.id,
    CASE f.id
        WHEN 'exercises' THEN 500
        WHEN 'exercise_media' THEN 80
        WHEN 'training_units' THEN 200
        WHEN 'training_programs' THEN 30
        WHEN 'training_groups' THEN 30
        WHEN 'active_members' THEN 80
        WHEN 'ai_calls' THEN 30
        WHEN 'ai_pipeline' THEN 0
        WHEN 'wiki_import' THEN 0
        WHEN 'data_export' THEN 1
    END
FROM features f
WHERE f.app = 'shinkan'
ON CONFLICT (plan_id, feature_id) DO NOTHING;

-- Plan-Limits: verein_pro (NULL = unbegrenzt wo sinnvoll)
INSERT INTO club_plan_limits (plan_id, feature_id, limit_value)
SELECT 'verein_pro', f.id,
    CASE f.id
        WHEN 'exercises' THEN NULL
        WHEN 'exercise_media' THEN 300
        WHEN 'training_units' THEN NULL
        WHEN 'training_programs' THEN NULL
        WHEN 'training_groups' THEN NULL
        WHEN 'active_members' THEN NULL
        WHEN 'ai_calls' THEN 200
        WHEN 'ai_pipeline' THEN 1
        WHEN 'wiki_import' THEN 0
        WHEN 'data_export' THEN 1
    END
FROM features f
WHERE f.app = 'shinkan'
ON CONFLICT (plan_id, feature_id) DO NOTHING;

-- Plan-Limits: pilot
INSERT INTO club_plan_limits (plan_id, feature_id, limit_value)
SELECT 'pilot', f.id,
    CASE f.id
        WHEN 'exercises' THEN NULL
        WHEN 'exercise_media' THEN NULL
        WHEN 'training_units' THEN NULL
        WHEN 'training_programs' THEN NULL
        WHEN 'training_groups' THEN NULL
        WHEN 'active_members' THEN NULL
        WHEN 'ai_calls' THEN 100
        WHEN 'ai_pipeline' THEN 1
        WHEN 'wiki_import' THEN 0
        WHEN 'data_export' THEN 1
    END
FROM features f
WHERE f.app = 'shinkan'
ON CONFLICT (plan_id, feature_id) DO NOTHING;

-- ── 6. Backfill: bestehende Vereine → Plan free ───────────────────────────
INSERT INTO club_subscriptions (club_id, plan_id, status)
SELECT c.id, 'free', 'active'
FROM clubs c
WHERE NOT EXISTS (
    SELECT 1 FROM club_subscriptions cs WHERE cs.club_id = c.id
);
