CREATE EXTENSION IF NOT EXISTS "pgcrypto";

DO $$ BEGIN
    CREATE TYPE event_status AS ENUM ('draft', 'published', 'closed', 'archived');
EXCEPTION WHEN duplicate_object THEN NULL; END $$;

DO $$ BEGIN
    CREATE TYPE token_status AS ENUM ('active', 'used', 'revoked', 'expired');
EXCEPTION WHEN duplicate_object THEN NULL; END $$;

DO $$ BEGIN
    CREATE TYPE rsvp_response AS ENUM ('attending', 'declined', 'maybe');
EXCEPTION WHEN duplicate_object THEN NULL; END $$;

DO $$ BEGIN
    CREATE TYPE notification_channel AS ENUM ('sms', 'email');
EXCEPTION WHEN duplicate_object THEN NULL; END $$;

DO $$ BEGIN
    CREATE TYPE notification_type AS ENUM ('invitation', 'verification', 'confirmation', 'reminder');
EXCEPTION WHEN duplicate_object THEN NULL; END $$;

DO $$ BEGIN
    CREATE TYPE delivery_status AS ENUM ('queued', 'sent', 'delivered', 'failed', 'bounced');
EXCEPTION WHEN duplicate_object THEN NULL; END $$;

CREATE TABLE IF NOT EXISTS users (
    id          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    email       VARCHAR(255) UNIQUE NOT NULL,
    name        VARCHAR(255) NOT NULL,
    created_at  TIMESTAMPTZ NOT NULL DEFAULT now(),
    updated_at  TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE TABLE IF NOT EXISTS events (
    id           UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    host_id      UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    name         VARCHAR(255) NOT NULL,
    slug         VARCHAR(100) UNIQUE NOT NULL,
    event_date   TIMESTAMPTZ NOT NULL,
    venue        TEXT NOT NULL DEFAULT '',
    max_capacity INTEGER NOT NULL DEFAULT 0,
    settings     JSONB NOT NULL DEFAULT '{}'::jsonb,
    status       event_status NOT NULL DEFAULT 'draft',
    created_at   TIMESTAMPTZ NOT NULL DEFAULT now(),
    updated_at   TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE INDEX IF NOT EXISTS idx_events_host ON events(host_id);
CREATE INDEX IF NOT EXISTS idx_events_status ON events(status);

CREATE TABLE IF NOT EXISTS guests (
    id            UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    event_id      UUID NOT NULL REFERENCES events(id) ON DELETE CASCADE,
    name          VARCHAR(255) NOT NULL,
    email         VARCHAR(255),
    phone         VARCHAR(20),
    plus_ones     INTEGER NOT NULL DEFAULT 0,
    dietary_notes TEXT,
    table_number  INTEGER,
    created_at    TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE INDEX IF NOT EXISTS idx_guests_event ON guests(event_id);

CREATE TABLE IF NOT EXISTS tokens (
    id         UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    guest_id   UUID NOT NULL UNIQUE REFERENCES guests(id) ON DELETE CASCADE,
    token_hash VARCHAR(64) NOT NULL,
    expires_at TIMESTAMPTZ NOT NULL,
    status     token_status NOT NULL DEFAULT 'active',
    used_at    TIMESTAMPTZ,
    created_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE INDEX IF NOT EXISTS idx_tokens_hash ON tokens(token_hash) WHERE status = 'active';

CREATE TABLE IF NOT EXISTS rsvps (
    id                 UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    guest_id           UUID NOT NULL UNIQUE REFERENCES guests(id) ON DELETE CASCADE,
    response           rsvp_response NOT NULL,
    plus_ones          INTEGER NOT NULL DEFAULT 0,
    dietary_notes      TEXT,
    submitted_at       TIMESTAMPTZ NOT NULL DEFAULT now(),
    device_fingerprint JSONB,
    ip_address         INET,
    risk_score         SMALLINT
);

CREATE INDEX IF NOT EXISTS idx_rsvps_guest ON rsvps(guest_id);

CREATE TABLE IF NOT EXISTS access_logs (
    id           UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    guest_id     UUID NOT NULL REFERENCES guests(id) ON DELETE CASCADE,
    token_id     UUID REFERENCES tokens(id) ON DELETE SET NULL,
    fingerprint  JSONB,
    ip_address   INET,
    geo_location JSONB,
    risk_score   SMALLINT,
    risk_reasons TEXT[],
    flagged      BOOLEAN NOT NULL DEFAULT FALSE,
    created_at   TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE INDEX IF NOT EXISTS idx_access_logs_guest ON access_logs(guest_id, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_access_logs_flagged ON access_logs(flagged) WHERE flagged = TRUE;

CREATE TABLE IF NOT EXISTS notifications (
    id           UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    guest_id     UUID NOT NULL REFERENCES guests(id) ON DELETE CASCADE,
    channel      notification_channel NOT NULL,
    type         notification_type NOT NULL,
    status       delivery_status NOT NULL DEFAULT 'queued',
    provider_id  VARCHAR(100),
    attempts     SMALLINT NOT NULL DEFAULT 0,
    last_attempt TIMESTAMPTZ,
    delivered_at TIMESTAMPTZ,
    error        TEXT,
    created_at   TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE INDEX IF NOT EXISTS idx_notifications_status ON notifications(status) WHERE status IN ('queued', 'failed');
