-- FocusFlow Initial Schema
-- Migration 001: Core tables for ADHD Task Manager MVP

BEGIN;

-- ============================================================
-- EXTENSIONS
-- ============================================================

CREATE EXTENSION IF NOT EXISTS "pgcrypto";

-- ============================================================
-- USERS & AUTH
-- ============================================================

CREATE TABLE users (
    id                      UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    email                   VARCHAR(255) UNIQUE NOT NULL,
    password_hash           VARCHAR(255) NOT NULL,
    display_name            VARCHAR(100) NOT NULL,
    avatar_url              VARCHAR(500),
    -- ADHD-specific preferences
    default_energy_level    SMALLINT DEFAULT 3 CHECK (default_energy_level BETWEEN 1 AND 5),
    focus_duration_minutes  INTEGER DEFAULT 25,
    reward_style            VARCHAR(20) DEFAULT 'playful',  -- playful | minimal | data
    forgiveness_enabled     BOOLEAN DEFAULT TRUE,
    daily_task_limit        INTEGER DEFAULT 10,
    -- Subscription
    subscription_tier       VARCHAR(20) DEFAULT 'free',  -- free | premium | lifetime
    subscription_expires_at TIMESTAMPTZ,
    -- Timestamps
    created_at              TIMESTAMPTZ DEFAULT NOW(),
    updated_at              TIMESTAMPTZ DEFAULT NOW(),
    deleted_at              TIMESTAMPTZ
);

CREATE INDEX idx_users_email ON users(email) WHERE deleted_at IS NULL;

CREATE TABLE refresh_tokens (
    id          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id     UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    token       VARCHAR(255) NOT NULL,
    expires_at  TIMESTAMPTZ NOT NULL,
    revoked     BOOLEAN DEFAULT FALSE,
    created_at  TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX idx_refresh_tokens_user ON refresh_tokens(user_id) WHERE revoked = FALSE;
CREATE INDEX idx_refresh_tokens_token ON refresh_tokens(token) WHERE revoked = FALSE;

-- ============================================================
-- TASKS
-- ============================================================

CREATE TABLE tasks (
    id                  UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id             UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    title               VARCHAR(300) NOT NULL,
    description         TEXT,
    status              VARCHAR(20) DEFAULT 'pending',  -- pending | in_progress | completed | skipped | archived
    priority            SMALLINT DEFAULT 3 CHECK (priority BETWEEN 1 AND 5),
    energy_level        SMALLINT DEFAULT 3 CHECK (energy_level BETWEEN 1 AND 5),
    -- Time estimation
    estimated_minutes   INTEGER,
    actual_minutes      INTEGER,
    -- Dopamine scoring inputs
    dopamine_score      NUMERIC(5,4) DEFAULT 0,
    novelty_factor      NUMERIC(3,2) DEFAULT 0.5,
    times_postponed     INTEGER DEFAULT 0,
    last_interacted_at  TIMESTAMPTZ,
    -- Organization
    category            VARCHAR(100),
    tags                TEXT[] DEFAULT '{}',
    due_date            TIMESTAMPTZ,
    -- Recurrence
    is_recurring        BOOLEAN DEFAULT FALSE,
    recurrence_rule     VARCHAR(200),  -- RRULE format
    parent_task_id      UUID REFERENCES tasks(id),
    -- Completion
    completed_at        TIMESTAMPTZ,
    -- Sync
    version             INTEGER DEFAULT 1,
    -- Timestamps
    created_at          TIMESTAMPTZ DEFAULT NOW(),
    updated_at          TIMESTAMPTZ DEFAULT NOW(),
    deleted_at          TIMESTAMPTZ
);

CREATE INDEX idx_tasks_user_status ON tasks(user_id, status) WHERE deleted_at IS NULL;
CREATE INDEX idx_tasks_user_due ON tasks(user_id, due_date) WHERE deleted_at IS NULL AND status = 'pending';
CREATE INDEX idx_tasks_dopamine ON tasks(user_id, dopamine_score DESC) WHERE deleted_at IS NULL AND status = 'pending';
CREATE INDEX idx_tasks_tags ON tasks USING GIN(tags);
CREATE INDEX idx_tasks_parent ON tasks(parent_task_id) WHERE parent_task_id IS NOT NULL;

-- ============================================================
-- STREAKS
-- ============================================================

CREATE TABLE streaks (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id         UUID UNIQUE NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    current_count   INTEGER DEFAULT 0,
    longest_count   INTEGER DEFAULT 0,
    -- Forgiveness mechanics
    grace_days      SMALLINT DEFAULT 2,
    grace_used      SMALLINT DEFAULT 0,
    frozen_until    DATE,
    -- Decay instead of reset (premium)
    decay_enabled   BOOLEAN DEFAULT FALSE,
    -- Tracking
    last_completed_date DATE,
    started_at      TIMESTAMPTZ DEFAULT NOW(),
    updated_at      TIMESTAMPTZ DEFAULT NOW()
);

CREATE TABLE streak_entries (
    id          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    streak_id   UUID NOT NULL REFERENCES streaks(id) ON DELETE CASCADE,
    entry_date  DATE NOT NULL,
    tasks_done  INTEGER DEFAULT 0,
    was_forgiven BOOLEAN DEFAULT FALSE,
    was_frozen  BOOLEAN DEFAULT FALSE,
    -- Points earned on this day
    points_earned INTEGER DEFAULT 0,
    created_at  TIMESTAMPTZ DEFAULT NOW(),
    UNIQUE(streak_id, entry_date)
);

CREATE INDEX idx_streak_entries_date ON streak_entries(streak_id, entry_date DESC);

-- ============================================================
-- REWARDS
-- ============================================================

CREATE TABLE rewards (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id         UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    task_id         UUID REFERENCES tasks(id),
    -- Reward details
    reward_type     VARCHAR(20) NOT NULL,  -- points | badge | animation | message | unlock | surprise
    magnitude       NUMERIC(8,2) NOT NULL DEFAULT 1.0,
    is_surprise     BOOLEAN DEFAULT FALSE,
    -- Content
    title           VARCHAR(200),
    description     TEXT,
    animation_key   VARCHAR(100),  -- Lottie animation identifier
    -- Metadata
    created_at      TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX idx_rewards_user ON rewards(user_id, created_at DESC);
CREATE INDEX idx_rewards_type ON rewards(user_id, reward_type);

-- User point balance (materialized for fast reads)
CREATE TABLE user_points (
    user_id     UUID PRIMARY KEY REFERENCES users(id) ON DELETE CASCADE,
    total       INTEGER DEFAULT 0,
    level       INTEGER DEFAULT 1,
    updated_at  TIMESTAMPTZ DEFAULT NOW()
);

-- ============================================================
-- TIME PERCEPTION TRACKING
-- ============================================================

CREATE TABLE time_estimates (
    id                  UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id             UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    task_id             UUID REFERENCES tasks(id),
    -- Estimate vs actual
    estimated_minutes   INTEGER NOT NULL,
    actual_minutes      INTEGER,
    accuracy_ratio      NUMERIC(5,2),  -- actual / estimated
    -- Context
    category            VARCHAR(100),
    energy_level        SMALLINT,
    -- Timestamps
    started_at          TIMESTAMPTZ,
    completed_at        TIMESTAMPTZ,
    created_at          TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX idx_time_estimates_user ON time_estimates(user_id, created_at DESC);
CREATE INDEX idx_time_estimates_category ON time_estimates(user_id, category);

-- ============================================================
-- BODY DOUBLING / CO-WORKING ROOMS (Phase 2)
-- ============================================================

CREATE TABLE coworking_rooms (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    name            VARCHAR(100) NOT NULL,
    description     TEXT,
    host_id         UUID NOT NULL REFERENCES users(id),
    is_public       BOOLEAN DEFAULT TRUE,
    max_participants INTEGER DEFAULT 10,
    ambient_sound   VARCHAR(50) DEFAULT 'none',  -- none | cafe | rain | lofi | forest
    status          VARCHAR(20) DEFAULT 'active',  -- active | ended
    started_at      TIMESTAMPTZ DEFAULT NOW(),
    ended_at        TIMESTAMPTZ
);

CREATE TABLE room_participants (
    room_id         UUID NOT NULL REFERENCES coworking_rooms(id) ON DELETE CASCADE,
    user_id         UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    current_task    VARCHAR(200),
    joined_at       TIMESTAMPTZ DEFAULT NOW(),
    left_at         TIMESTAMPTZ,
    PRIMARY KEY (room_id, user_id)
);

CREATE INDEX idx_room_participants_active ON room_participants(room_id) WHERE left_at IS NULL;

-- ============================================================
-- ACCOUNTABILITY PARTNERS (Phase 2)
-- ============================================================

CREATE TABLE accountability_partners (
    id          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id     UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    partner_id  UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    status      VARCHAR(20) DEFAULT 'pending',  -- pending | active | blocked
    created_at  TIMESTAMPTZ DEFAULT NOW(),
    UNIQUE(user_id, partner_id)
);

CREATE TABLE nudges (
    id          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    from_id     UUID NOT NULL REFERENCES users(id),
    to_id       UUID NOT NULL REFERENCES users(id),
    message     TEXT,
    nudge_type  VARCHAR(20) DEFAULT 'gentle',  -- gentle | encouraging | celebratory
    read_at     TIMESTAMPTZ,
    created_at  TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX idx_nudges_to ON nudges(to_id, created_at DESC) WHERE read_at IS NULL;

-- ============================================================
-- COACHING MARKETPLACE (Phase 3)
-- ============================================================

CREATE TABLE coaches (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id         UUID UNIQUE NOT NULL REFERENCES users(id),
    bio             TEXT,
    specializations TEXT[] DEFAULT '{}',
    hourly_rate     NUMERIC(8,2),
    currency        VARCHAR(3) DEFAULT 'USD',
    rating_avg      NUMERIC(3,2) DEFAULT 0,
    rating_count    INTEGER DEFAULT 0,
    verified        BOOLEAN DEFAULT FALSE,
    status          VARCHAR(20) DEFAULT 'pending',  -- pending | active | suspended
    created_at      TIMESTAMPTZ DEFAULT NOW()
);

CREATE TABLE coaching_sessions (
    id          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    coach_id    UUID NOT NULL REFERENCES coaches(id),
    client_id   UUID NOT NULL REFERENCES users(id),
    status      VARCHAR(20) DEFAULT 'scheduled',  -- scheduled | in_progress | completed | cancelled
    scheduled_at TIMESTAMPTZ NOT NULL,
    duration_min INTEGER DEFAULT 30,
    notes       TEXT,
    rating      SMALLINT CHECK (rating BETWEEN 1 AND 5),
    amount      NUMERIC(8,2),
    commission  NUMERIC(8,2),
    created_at  TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX idx_coaching_sessions_coach ON coaching_sessions(coach_id, scheduled_at);
CREATE INDEX idx_coaching_sessions_client ON coaching_sessions(client_id, scheduled_at);

-- ============================================================
-- PUSH NOTIFICATIONS
-- ============================================================

CREATE TABLE push_tokens (
    id          UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id     UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    token       VARCHAR(500) NOT NULL,
    platform    VARCHAR(20) NOT NULL,  -- ios | android | web
    created_at  TIMESTAMPTZ DEFAULT NOW(),
    UNIQUE(user_id, token)
);

CREATE TABLE notification_log (
    id              UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id         UUID NOT NULL REFERENCES users(id),
    notification_type VARCHAR(50) NOT NULL,
    title           VARCHAR(200),
    body            TEXT,
    data_json       JSONB,
    sent_at         TIMESTAMPTZ DEFAULT NOW(),
    read_at         TIMESTAMPTZ
);

CREATE INDEX idx_notification_log_user ON notification_log(user_id, sent_at DESC);

-- ============================================================
-- SYNC TRACKING
-- ============================================================

CREATE TABLE sync_changelog (
    id          BIGSERIAL PRIMARY KEY,
    entity_type VARCHAR(50) NOT NULL,  -- task | streak | reward | time_estimate
    entity_id   UUID NOT NULL,
    action      VARCHAR(20) NOT NULL,  -- insert | update | delete
    changed_at  TIMESTAMPTZ DEFAULT NOW(),
    changed_by  UUID REFERENCES users(id)
);

CREATE INDEX idx_sync_changelog_type_time ON sync_changelog(entity_type, changed_at);
CREATE INDEX idx_sync_changelog_user ON sync_changelog(changed_by, changed_at);

-- ============================================================
-- SUBSCRIPTIONS
-- ============================================================

CREATE TABLE subscriptions (
    id                  UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id             UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    provider            VARCHAR(20) NOT NULL,  -- stripe | revenuecat | apple | google
    provider_subscription_id VARCHAR(200),
    plan                VARCHAR(50) NOT NULL,  -- premium_monthly | premium_yearly | lifetime
    status              VARCHAR(20) DEFAULT 'active',  -- active | cancelled | expired | past_due
    current_period_start TIMESTAMPTZ,
    current_period_end  TIMESTAMPTZ,
    cancelled_at        TIMESTAMPTZ,
    created_at          TIMESTAMPTZ DEFAULT NOW(),
    updated_at          TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX idx_subscriptions_user ON subscriptions(user_id);
CREATE INDEX idx_subscriptions_provider ON subscriptions(provider, provider_subscription_id);

-- ============================================================
-- UPDATED_AT TRIGGER FUNCTION
-- ============================================================

CREATE OR REPLACE FUNCTION update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
    NEW.updated_at = NOW();
    RETURN NEW;
END;
$$ language 'plpgsql';

-- Apply trigger to tables with updated_at
CREATE TRIGGER update_users_updated_at BEFORE UPDATE ON users
    FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();

CREATE TRIGGER update_tasks_updated_at BEFORE UPDATE ON tasks
    FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();

CREATE TRIGGER update_streaks_updated_at BEFORE UPDATE ON streaks
    FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();

CREATE TRIGGER update_subscriptions_updated_at BEFORE UPDATE ON subscriptions
    FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();

-- ============================================================
-- SYNC TRIGGER: Auto-log changes to sync_changelog
-- ============================================================

CREATE OR REPLACE FUNCTION log_sync_change()
RETURNS TRIGGER AS $$
BEGIN
    IF TG_OP = 'DELETE' THEN
        INSERT INTO sync_changelog (entity_type, entity_id, action, changed_by)
        VALUES (TG_TABLE_NAME, OLD.id, 'delete', OLD.user_id);
        RETURN OLD;
    ELSE
        INSERT INTO sync_changelog (entity_type, entity_id, action, changed_by)
        VALUES (TG_TABLE_NAME, NEW.id, TG_OP::VARCHAR, NEW.user_id);
        RETURN NEW;
    END IF;
END;
$$ language 'plpgsql';

-- Track task changes for offline sync
CREATE TRIGGER sync_tasks_changes AFTER INSERT OR UPDATE OR DELETE ON tasks
    FOR EACH ROW EXECUTE FUNCTION log_sync_change();

COMMIT;
