-- =============================================================================
-- Migration 006: Übungsplanung & Dienstkalender
-- Training Schedule & Service Calendar for Feuerwehr Rems Dashboard
-- =============================================================================

-- -----------------------------------------------------------------------------
-- 1. Calendar token table for iCal subscribe URLs (no auth required per-request)
-- -----------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS calendar_tokens (
    id          UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    user_id     UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    token       VARCHAR(64) UNIQUE NOT NULL,
    created_at  TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    last_used_at TIMESTAMPTZ
);

CREATE INDEX idx_calendar_tokens_token   ON calendar_tokens(token);
CREATE INDEX idx_calendar_tokens_user_id ON calendar_tokens(user_id);

-- -----------------------------------------------------------------------------
-- 2. Main events table
-- -----------------------------------------------------------------------------
CREATE TYPE uebung_typ AS ENUM (
    'Übungsabend',
    'Lehrgang',
    'Sonderdienst',
    'Versammlung',
    'Gemeinschaftsübung',
    'Sonstiges'
);

CREATE TABLE uebungen (
    id                  UUID        PRIMARY KEY DEFAULT uuid_generate_v4(),
    titel               VARCHAR(255) NOT NULL,
    beschreibung        TEXT,
    typ                 uebung_typ  NOT NULL,
    datum_von           TIMESTAMPTZ NOT NULL,
    datum_bis           TIMESTAMPTZ NOT NULL,
    ort                 VARCHAR(255),
    treffpunkt          VARCHAR(255),
    pflichtveranstaltung BOOLEAN    NOT NULL DEFAULT FALSE,
    mindest_teilnehmer  INT         CHECK (mindest_teilnehmer > 0),
    max_teilnehmer      INT         CHECK (max_teilnehmer > 0),
    angelegt_von        UUID        REFERENCES users(id) ON DELETE SET NULL,
    erstellt_am         TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    aktualisiert_am     TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    abgesagt            BOOLEAN     NOT NULL DEFAULT FALSE,
    absage_grund        TEXT,

    CONSTRAINT datum_reihenfolge CHECK (datum_bis >= datum_von),
    CONSTRAINT max_groesser_min  CHECK (
        max_teilnehmer IS NULL OR
        mindest_teilnehmer IS NULL OR
        max_teilnehmer >= mindest_teilnehmer
    )
);

CREATE INDEX idx_uebungen_datum_von         ON uebungen(datum_von);
CREATE INDEX idx_uebungen_typ               ON uebungen(typ);
CREATE INDEX idx_uebungen_pflichtveranstaltung ON uebungen(pflichtveranstaltung) WHERE pflichtveranstaltung = TRUE;
CREATE INDEX idx_uebungen_abgesagt          ON uebungen(abgesagt) WHERE abgesagt = FALSE;
-- Compound index for the most common calendar-range query
CREATE INDEX idx_uebungen_datum_von_bis     ON uebungen(datum_von, datum_bis);

-- Keep aktualisiert_am in sync via trigger (reuse function from migration 001)
CREATE TRIGGER update_uebungen_aktualisiert_am
    BEFORE UPDATE ON uebungen
    FOR EACH ROW
    EXECUTE FUNCTION update_updated_at_column();

-- -----------------------------------------------------------------------------
-- 3. Attendance / RSVP table
-- -----------------------------------------------------------------------------
CREATE TYPE teilnahme_status AS ENUM (
    'zugesagt',
    'abgesagt',
    'erschienen',
    'entschuldigt',
    'unbekannt'
);

CREATE TABLE uebung_teilnahmen (
    uebung_id               UUID            NOT NULL REFERENCES uebungen(id) ON DELETE CASCADE,
    user_id                 UUID            NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    status                  teilnahme_status NOT NULL DEFAULT 'unbekannt',
    antwort_am              TIMESTAMPTZ,
    erschienen_erfasst_am   TIMESTAMPTZ,
    erschienen_erfasst_von  UUID            REFERENCES users(id) ON DELETE SET NULL,
    bemerkung               VARCHAR(500),

    PRIMARY KEY (uebung_id, user_id)
);

CREATE INDEX idx_teilnahmen_uebung_id ON uebung_teilnahmen(uebung_id);
CREATE INDEX idx_teilnahmen_user_id   ON uebung_teilnahmen(user_id);
CREATE INDEX idx_teilnahmen_status    ON uebung_teilnahmen(status);

-- -----------------------------------------------------------------------------
-- 4. Trigger: auto-create 'unbekannt' rows for all active members on new event
-- -----------------------------------------------------------------------------
CREATE OR REPLACE FUNCTION fn_create_teilnahmen_for_all_active_members()
RETURNS TRIGGER AS $$
BEGIN
    INSERT INTO uebung_teilnahmen (uebung_id, user_id, status)
    SELECT NEW.id, u.id, 'unbekannt'
    FROM users u
    WHERE u.is_active = TRUE
    ON CONFLICT (uebung_id, user_id) DO NOTHING;
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER trg_auto_teilnahmen_after_insert
    AFTER INSERT ON uebungen
    FOR EACH ROW
    EXECUTE FUNCTION fn_create_teilnahmen_for_all_active_members();

-- -----------------------------------------------------------------------------
-- 5. Trigger: when a new member becomes active, add them to all future events
-- -----------------------------------------------------------------------------
CREATE OR REPLACE FUNCTION fn_add_member_to_future_events()
RETURNS TRIGGER AS $$
BEGIN
    -- Only run when is_active transitions FALSE -> TRUE
    IF (OLD.is_active = FALSE OR OLD.is_active IS NULL) AND NEW.is_active = TRUE THEN
        INSERT INTO uebung_teilnahmen (uebung_id, user_id, status)
        SELECT u.id, NEW.id, 'unbekannt'
        FROM uebungen u
        WHERE u.datum_von > NOW()
          AND u.abgesagt = FALSE
        ON CONFLICT (uebung_id, user_id) DO NOTHING;
    END IF;
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER trg_add_member_to_future_events
    AFTER UPDATE OF is_active ON users
    FOR EACH ROW
    EXECUTE FUNCTION fn_add_member_to_future_events();

-- -----------------------------------------------------------------------------
-- 6. Convenience view: event overview with attendance counts
-- -----------------------------------------------------------------------------
CREATE OR REPLACE VIEW uebung_uebersicht AS
SELECT
    u.id,
    u.titel,
    u.typ,
    u.datum_von,
    u.datum_bis,
    u.ort,
    u.treffpunkt,
    u.pflichtveranstaltung,
    u.mindest_teilnehmer,
    u.max_teilnehmer,
    u.abgesagt,
    u.absage_grund,
    u.angelegt_von,
    u.erstellt_am,
    u.aktualisiert_am,
    -- Attendance aggregates
    COUNT(t.user_id)                                                    AS gesamt_eingeladen,
    COUNT(t.user_id) FILTER (WHERE t.status = 'zugesagt')               AS anzahl_zugesagt,
    COUNT(t.user_id) FILTER (WHERE t.status = 'abgesagt')               AS anzahl_abgesagt,
    COUNT(t.user_id) FILTER (WHERE t.status = 'erschienen')             AS anzahl_erschienen,
    COUNT(t.user_id) FILTER (WHERE t.status = 'entschuldigt')           AS anzahl_entschuldigt,
    COUNT(t.user_id) FILTER (WHERE t.status = 'unbekannt')              AS anzahl_unbekannt
FROM uebungen u
LEFT JOIN uebung_teilnahmen t ON t.uebung_id = u.id
GROUP BY u.id;

-- -----------------------------------------------------------------------------
-- 7. View: per-member participation statistics (feeds Tier 3 reporting)
-- -----------------------------------------------------------------------------
CREATE OR REPLACE VIEW member_participation_stats AS
SELECT
    usr.id                                                              AS user_id,
    COALESCE(usr.name, usr.preferred_username, usr.email)              AS name,
    COUNT(t.uebung_id)                                                 AS total_eingeladen,
    COUNT(t.uebung_id) FILTER (WHERE t.status = 'erschienen')          AS total_erschienen,
    COUNT(t.uebung_id) FILTER (
        WHERE u.pflichtveranstaltung = TRUE AND t.status = 'erschienen'
    )                                                                  AS pflicht_erschienen,
    COUNT(t.uebung_id) FILTER (WHERE u.pflichtveranstaltung = TRUE)    AS pflicht_gesamt,
    ROUND(
        CASE
            WHEN COUNT(t.uebung_id) FILTER (WHERE u.typ = 'Übungsabend') = 0 THEN 0
            ELSE
                COUNT(t.uebung_id) FILTER (
                    WHERE u.typ = 'Übungsabend' AND t.status = 'erschienen'
                )::NUMERIC /
                COUNT(t.uebung_id) FILTER (WHERE u.typ = 'Übungsabend') * 100
        END, 1
    )                                                                  AS uebungsabend_quote_pct
FROM users usr
JOIN uebung_teilnahmen t ON t.user_id = usr.id
JOIN uebungen u ON u.id = t.uebung_id
WHERE usr.is_active = TRUE
  AND u.abgesagt = FALSE
GROUP BY usr.id, usr.name, usr.preferred_username, usr.email;
