-- ============================================================================
-- SCHEMA: education
-- TABLE: enrollments
-- DESCRIPTION: Inscripciones de usuarios a cursos
-- VERSION: 1.0.0
-- CREATED: 2026-01-16
-- SPRINT: Sprint 2 - DDL Implementation Roadmap Q1-2026
-- ============================================================================

-- Enum para estado de inscripcion
DO $$ BEGIN
    CREATE TYPE education.enrollment_status AS ENUM (
        'active',           -- Inscripcion activa
        'completed',        -- Curso completado
        'expired',          -- Acceso expirado
        'cancelled',        -- Cancelada por usuario
        'refunded',         -- Reembolsada
        'suspended'         -- Suspendida por admin
    );
EXCEPTION
    WHEN duplicate_object THEN null;
END $$;

-- Enum para tipo de acceso
DO $$ BEGIN
    CREATE TYPE education.enrollment_type AS ENUM (
        'free',             -- Acceso gratuito
        'purchased',        -- Comprado individualmente
        'subscription',     -- Via suscripcion VIP
        'gift',             -- Regalado
        'promotional',      -- Promocional/Codigo
        'bundle',           -- Parte de un bundle
        'admin_granted'     -- Otorgado por admin
    );
EXCEPTION
    WHEN duplicate_object THEN null;
END $$;

-- Tabla de Inscripciones
CREATE TABLE IF NOT EXISTS education.enrollments (
    -- Identificadores
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id UUID NOT NULL REFERENCES users.users(id) ON DELETE CASCADE,
    course_id UUID NOT NULL REFERENCES education.courses(id) ON DELETE CASCADE,
    tenant_id UUID NOT NULL REFERENCES tenants.tenants(id) ON DELETE CASCADE,

    -- Tipo y estado
    type education.enrollment_type NOT NULL DEFAULT 'free',
    status education.enrollment_status NOT NULL DEFAULT 'active',

    -- Progreso general
    progress_percent DECIMAL(5, 2) NOT NULL DEFAULT 0 CHECK (progress_percent BETWEEN 0 AND 100),
    lessons_completed INTEGER NOT NULL DEFAULT 0,
    quizzes_completed INTEGER NOT NULL DEFAULT 0,
    quizzes_passed INTEGER NOT NULL DEFAULT 0,

    -- Tiempo
    total_time_spent_minutes INTEGER NOT NULL DEFAULT 0,
    last_activity_at TIMESTAMPTZ,
    last_lesson_id UUID,
    last_position_seconds INTEGER,                  -- Posicion en el ultimo video

    -- Pago (si aplica)
    payment_id UUID,
    amount_paid DECIMAL(10, 2),
    currency VARCHAR(3) DEFAULT 'USD',
    credits_used INTEGER DEFAULT 0,

    -- Acceso
    access_starts_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    access_ends_at TIMESTAMPTZ,                     -- NULL = acceso permanente

    -- Completado
    completed_at TIMESTAMPTZ,
    completion_time_days INTEGER,                   -- Dias desde inscripcion hasta completar

    -- Certificado
    certificate_issued BOOLEAN NOT NULL DEFAULT FALSE,
    certificate_id UUID,
    certificate_issued_at TIMESTAMPTZ,

    -- Calificacion final
    final_score DECIMAL(5, 2),
    final_grade VARCHAR(2),                         -- 'A', 'B', 'C', 'D', 'F'

    -- Gamificacion
    xp_earned INTEGER NOT NULL DEFAULT 0,
    badges_earned UUID[],

    -- Codigo promocional usado
    promo_code VARCHAR(50),

    -- Metadata
    metadata JSONB DEFAULT '{}'::JSONB,
    notes TEXT,                                     -- Notas del admin

    -- Timestamps
    enrolled_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),

    -- Constraints
    CONSTRAINT enrollments_unique_user_course UNIQUE (user_id, course_id)
);

COMMENT ON TABLE education.enrollments IS
'Inscripciones de usuarios a cursos con tracking de progreso';

COMMENT ON COLUMN education.enrollments.access_ends_at IS
'NULL indica acceso permanente al curso';

-- Indices
CREATE INDEX IF NOT EXISTS idx_enrollments_user
    ON education.enrollments(user_id, status);

CREATE INDEX IF NOT EXISTS idx_enrollments_course
    ON education.enrollments(course_id, status);

CREATE INDEX IF NOT EXISTS idx_enrollments_tenant
    ON education.enrollments(tenant_id);

CREATE INDEX IF NOT EXISTS idx_enrollments_status
    ON education.enrollments(status);

CREATE INDEX IF NOT EXISTS idx_enrollments_active
    ON education.enrollments(user_id, course_id)
    WHERE status = 'active';

CREATE INDEX IF NOT EXISTS idx_enrollments_completed
    ON education.enrollments(course_id, completed_at DESC)
    WHERE status = 'completed';

CREATE INDEX IF NOT EXISTS idx_enrollments_progress
    ON education.enrollments(course_id, progress_percent DESC)
    WHERE status = 'active';

CREATE INDEX IF NOT EXISTS idx_enrollments_last_activity
    ON education.enrollments(last_activity_at DESC)
    WHERE status = 'active';

-- Trigger para updated_at
DROP TRIGGER IF EXISTS enrollment_updated_at ON education.enrollments;
CREATE TRIGGER enrollment_updated_at
    BEFORE UPDATE ON education.enrollments
    FOR EACH ROW
    EXECUTE FUNCTION education.update_education_timestamp();

-- Trigger para actualizar estadisticas del curso
CREATE OR REPLACE FUNCTION education.update_course_enrollment_stats()
RETURNS TRIGGER AS $$
BEGIN
    IF TG_OP = 'INSERT' THEN
        UPDATE education.courses
        SET enrollment_count = enrollment_count + 1
        WHERE id = NEW.course_id;

    ELSIF TG_OP = 'DELETE' THEN
        UPDATE education.courses
        SET enrollment_count = enrollment_count - 1
        WHERE id = OLD.course_id;

    ELSIF TG_OP = 'UPDATE' THEN
        -- Si cambio a completado
        IF NEW.status = 'completed' AND OLD.status != 'completed' THEN
            UPDATE education.courses
            SET completion_count = completion_count + 1
            WHERE id = NEW.course_id;
        -- Si cambio de completado a otro estado
        ELSIF OLD.status = 'completed' AND NEW.status != 'completed' THEN
            UPDATE education.courses
            SET completion_count = completion_count - 1
            WHERE id = NEW.course_id;
        END IF;
    END IF;

    RETURN COALESCE(NEW, OLD);
END;
$$ LANGUAGE plpgsql;

DROP TRIGGER IF EXISTS enrollment_stats ON education.enrollments;
CREATE TRIGGER enrollment_stats
    AFTER INSERT OR UPDATE OF status OR DELETE ON education.enrollments
    FOR EACH ROW
    EXECUTE FUNCTION education.update_course_enrollment_stats();

-- Funcion para calcular progreso
CREATE OR REPLACE FUNCTION education.calculate_enrollment_progress(p_enrollment_id UUID)
RETURNS DECIMAL(5, 2) AS $$
DECLARE
    v_enrollment RECORD;
    v_total_lessons INTEGER;
    v_completed_lessons INTEGER;
    v_progress DECIMAL(5, 2);
BEGIN
    SELECT * INTO v_enrollment
    FROM education.enrollments
    WHERE id = p_enrollment_id;

    IF v_enrollment IS NULL THEN
        RETURN 0;
    END IF;

    -- Contar lecciones totales del curso
    SELECT COUNT(*) INTO v_total_lessons
    FROM education.lessons
    WHERE course_id = v_enrollment.course_id
      AND status = 'published'
      AND is_mandatory = TRUE;

    -- Contar lecciones completadas
    SELECT COUNT(*) INTO v_completed_lessons
    FROM education.lesson_progress lp
    WHERE lp.enrollment_id = p_enrollment_id
      AND lp.is_completed = TRUE;

    IF v_total_lessons = 0 THEN
        RETURN 0;
    END IF;

    v_progress := (v_completed_lessons::DECIMAL / v_total_lessons * 100);

    -- Actualizar enrollment
    UPDATE education.enrollments
    SET progress_percent = v_progress,
        lessons_completed = v_completed_lessons,
        status = CASE WHEN v_progress >= 100 THEN 'completed' ELSE status END,
        completed_at = CASE WHEN v_progress >= 100 AND completed_at IS NULL THEN NOW() ELSE completed_at END
    WHERE id = p_enrollment_id;

    RETURN v_progress;
END;
$$ LANGUAGE plpgsql;

-- Vista de mis cursos (para estudiante)
CREATE OR REPLACE VIEW education.v_my_courses AS
SELECT
    e.id AS enrollment_id,
    e.user_id,
    e.course_id,
    c.title,
    c.slug,
    c.thumbnail_url,
    c.difficulty,
    c.total_lessons,
    e.status,
    e.progress_percent,
    e.lessons_completed,
    e.last_activity_at,
    e.enrolled_at,
    e.completed_at,
    e.certificate_issued
FROM education.enrollments e
JOIN education.courses c ON e.course_id = c.id
WHERE e.status NOT IN ('cancelled', 'refunded')
ORDER BY e.last_activity_at DESC NULLS LAST;

-- Vista de estudiantes de un curso (para instructor)
CREATE OR REPLACE VIEW education.v_course_students AS
SELECT
    e.id AS enrollment_id,
    e.user_id,
    u.email,
    u.first_name,
    u.last_name,
    e.course_id,
    e.status,
    e.progress_percent,
    e.lessons_completed,
    e.quizzes_passed,
    e.final_score,
    e.total_time_spent_minutes,
    e.enrolled_at,
    e.last_activity_at,
    e.completed_at
FROM education.enrollments e
JOIN users.users u ON e.user_id = u.id
ORDER BY e.enrolled_at DESC;

-- RLS Policy para multi-tenancy
ALTER TABLE education.enrollments ENABLE ROW LEVEL SECURITY;

CREATE POLICY enrollments_tenant_isolation ON education.enrollments
    FOR ALL
    USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);

-- Los usuarios solo ven sus propias inscripciones
CREATE POLICY enrollments_user_isolation ON education.enrollments
    FOR SELECT
    USING (user_id = current_setting('app.current_user_id', true)::UUID);

-- Grants
GRANT SELECT, INSERT, UPDATE ON education.enrollments TO trading_app;
GRANT SELECT ON education.enrollments TO trading_readonly;
GRANT SELECT ON education.v_my_courses TO trading_app;
GRANT SELECT ON education.v_course_students TO trading_app;
GRANT EXECUTE ON FUNCTION education.calculate_enrollment_progress TO trading_app;
