-- Migration: Create Academy Tables
-- Description: Schema for the Compliance Academy module (courses, lessons, quizzes, enrollments, certificates, progress)

-- Enable UUID extension if not already enabled
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

-- ============================================================================
-- 1. academy_courses - Training courses for compliance education
-- ============================================================================

CREATE TABLE IF NOT EXISTS academy_courses (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    tenant_id VARCHAR(255) NOT NULL,
    title VARCHAR(255) NOT NULL,
    description TEXT,
    category VARCHAR(50),
    passing_score INTEGER DEFAULT 70,
    duration_minutes INTEGER,
    required_for_roles JSONB DEFAULT '["all"]',
    status VARCHAR(50) DEFAULT 'draft',
    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

-- Indexes for academy_courses
CREATE INDEX IF NOT EXISTS idx_academy_courses_tenant ON academy_courses(tenant_id);
CREATE INDEX IF NOT EXISTS idx_academy_courses_status ON academy_courses(status);
CREATE INDEX IF NOT EXISTS idx_academy_courses_category ON academy_courses(category);

-- Auto-update trigger for academy_courses.updated_at
CREATE OR REPLACE FUNCTION update_academy_courses_updated_at()
RETURNS TRIGGER AS $$
BEGIN
    NEW.updated_at = NOW();
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

DROP TRIGGER IF EXISTS trigger_academy_courses_updated_at ON academy_courses;
CREATE TRIGGER trigger_academy_courses_updated_at
    BEFORE UPDATE ON academy_courses
    FOR EACH ROW
    EXECUTE FUNCTION update_academy_courses_updated_at();

-- Comments for academy_courses
COMMENT ON TABLE academy_courses IS 'Stores compliance training courses per tenant';
COMMENT ON COLUMN academy_courses.tenant_id IS 'Identifier for the tenant owning this course';
COMMENT ON COLUMN academy_courses.title IS 'Course title displayed to users';
COMMENT ON COLUMN academy_courses.category IS 'Course category (e.g. dsgvo, ai-act, security)';
COMMENT ON COLUMN academy_courses.passing_score IS 'Minimum score (0-100) required to pass the course';
COMMENT ON COLUMN academy_courses.duration_minutes IS 'Estimated total duration of the course in minutes';
COMMENT ON COLUMN academy_courses.required_for_roles IS 'JSON array of roles required to complete this course';
COMMENT ON COLUMN academy_courses.status IS 'Course status: draft, published, archived';

-- ============================================================================
-- 2. academy_lessons - Individual lessons within a course
-- ============================================================================

CREATE TABLE IF NOT EXISTS academy_lessons (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    course_id UUID NOT NULL REFERENCES academy_courses(id) ON DELETE CASCADE,
    title VARCHAR(255) NOT NULL,
    type VARCHAR(20) NOT NULL,
    content_markdown TEXT,
    video_url VARCHAR(500),
    audio_url VARCHAR(500),
    sort_order INTEGER NOT NULL DEFAULT 0,
    duration_minutes INTEGER,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

-- Indexes for academy_lessons
CREATE INDEX IF NOT EXISTS idx_academy_lessons_course ON academy_lessons(course_id);
CREATE INDEX IF NOT EXISTS idx_academy_lessons_sort ON academy_lessons(course_id, sort_order);

-- Auto-update trigger for academy_lessons.updated_at
CREATE OR REPLACE FUNCTION update_academy_lessons_updated_at()
RETURNS TRIGGER AS $$
BEGIN
    NEW.updated_at = NOW();
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

DROP TRIGGER IF EXISTS trigger_academy_lessons_updated_at ON academy_lessons;
CREATE TRIGGER trigger_academy_lessons_updated_at
    BEFORE UPDATE ON academy_lessons
    FOR EACH ROW
    EXECUTE FUNCTION update_academy_lessons_updated_at();

-- Comments for academy_lessons
COMMENT ON TABLE academy_lessons IS 'Individual lessons belonging to a course';
COMMENT ON COLUMN academy_lessons.course_id IS 'Foreign key to the parent course';
COMMENT ON COLUMN academy_lessons.type IS 'Lesson type: text, video, audio, quiz, interactive';
COMMENT ON COLUMN academy_lessons.content_markdown IS 'Lesson content in Markdown format';
COMMENT ON COLUMN academy_lessons.video_url IS 'URL to video content (if type is video)';
COMMENT ON COLUMN academy_lessons.audio_url IS 'URL to audio content (if type is audio)';
COMMENT ON COLUMN academy_lessons.sort_order IS 'Order of the lesson within the course';
COMMENT ON COLUMN academy_lessons.duration_minutes IS 'Estimated duration of this lesson in minutes';

-- ============================================================================
-- 3. academy_quiz_questions - Quiz questions attached to lessons
-- ============================================================================

CREATE TABLE IF NOT EXISTS academy_quiz_questions (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    lesson_id UUID NOT NULL REFERENCES academy_lessons(id) ON DELETE CASCADE,
    question TEXT NOT NULL,
    options JSONB NOT NULL,
    correct_option_index INTEGER NOT NULL,
    explanation TEXT,
    sort_order INTEGER NOT NULL DEFAULT 0,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

-- Indexes for academy_quiz_questions
CREATE INDEX IF NOT EXISTS idx_academy_quiz_questions_lesson ON academy_quiz_questions(lesson_id);
CREATE INDEX IF NOT EXISTS idx_academy_quiz_questions_sort ON academy_quiz_questions(lesson_id, sort_order);

-- Comments for academy_quiz_questions
COMMENT ON TABLE academy_quiz_questions IS 'Quiz questions belonging to a lesson';
COMMENT ON COLUMN academy_quiz_questions.lesson_id IS 'Foreign key to the parent lesson';
COMMENT ON COLUMN academy_quiz_questions.question IS 'The question text';
COMMENT ON COLUMN academy_quiz_questions.options IS 'JSON array of answer options (strings)';
COMMENT ON COLUMN academy_quiz_questions.correct_option_index IS 'Zero-based index of the correct option';
COMMENT ON COLUMN academy_quiz_questions.explanation IS 'Explanation shown after answering (correct or incorrect)';
COMMENT ON COLUMN academy_quiz_questions.sort_order IS 'Order of the question within the lesson quiz';

-- ============================================================================
-- 4. academy_enrollments - User enrollments in courses
-- ============================================================================

CREATE TABLE IF NOT EXISTS academy_enrollments (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    tenant_id VARCHAR(255) NOT NULL,
    course_id UUID NOT NULL REFERENCES academy_courses(id) ON DELETE CASCADE,
    user_id VARCHAR(255) NOT NULL,
    user_name VARCHAR(255),
    user_email VARCHAR(255),
    status VARCHAR(20) DEFAULT 'not_started',
    progress INTEGER DEFAULT 0,
    started_at TIMESTAMP WITH TIME ZONE,
    completed_at TIMESTAMP WITH TIME ZONE,
    certificate_id UUID,
    deadline TIMESTAMP WITH TIME ZONE,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

-- Indexes for academy_enrollments
CREATE INDEX IF NOT EXISTS idx_academy_enrollments_tenant ON academy_enrollments(tenant_id);
CREATE INDEX IF NOT EXISTS idx_academy_enrollments_course ON academy_enrollments(course_id);
CREATE INDEX IF NOT EXISTS idx_academy_enrollments_user ON academy_enrollments(user_id);
CREATE INDEX IF NOT EXISTS idx_academy_enrollments_status ON academy_enrollments(status);
CREATE INDEX IF NOT EXISTS idx_academy_enrollments_tenant_user ON academy_enrollments(tenant_id, user_id);

-- Auto-update trigger for academy_enrollments.updated_at
CREATE OR REPLACE FUNCTION update_academy_enrollments_updated_at()
RETURNS TRIGGER AS $$
BEGIN
    NEW.updated_at = NOW();
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

DROP TRIGGER IF EXISTS trigger_academy_enrollments_updated_at ON academy_enrollments;
CREATE TRIGGER trigger_academy_enrollments_updated_at
    BEFORE UPDATE ON academy_enrollments
    FOR EACH ROW
    EXECUTE FUNCTION update_academy_enrollments_updated_at();

-- Comments for academy_enrollments
COMMENT ON TABLE academy_enrollments IS 'Tracks user enrollments and progress in courses';
COMMENT ON COLUMN academy_enrollments.tenant_id IS 'Identifier for the tenant';
COMMENT ON COLUMN academy_enrollments.course_id IS 'Foreign key to the enrolled course';
COMMENT ON COLUMN academy_enrollments.user_id IS 'Identifier of the enrolled user';
COMMENT ON COLUMN academy_enrollments.user_name IS 'Display name of the enrolled user';
COMMENT ON COLUMN academy_enrollments.user_email IS 'Email address of the enrolled user';
COMMENT ON COLUMN academy_enrollments.status IS 'Enrollment status: not_started, in_progress, completed, expired';
COMMENT ON COLUMN academy_enrollments.progress IS 'Completion percentage (0-100)';
COMMENT ON COLUMN academy_enrollments.certificate_id IS 'Reference to issued certificate (if completed)';
COMMENT ON COLUMN academy_enrollments.deadline IS 'Deadline by which the course must be completed';

-- ============================================================================
-- 5. academy_certificates - Certificates issued upon course completion
-- ============================================================================

CREATE TABLE IF NOT EXISTS academy_certificates (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    tenant_id VARCHAR(255) NOT NULL,
    enrollment_id UUID NOT NULL UNIQUE REFERENCES academy_enrollments(id) ON DELETE CASCADE,
    course_id UUID NOT NULL REFERENCES academy_courses(id) ON DELETE CASCADE,
    user_id VARCHAR(255) NOT NULL,
    user_name VARCHAR(255),
    course_name VARCHAR(255),
    score INTEGER,
    issued_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    valid_until TIMESTAMP WITH TIME ZONE,
    pdf_url VARCHAR(500)
);

-- Indexes for academy_certificates
CREATE INDEX IF NOT EXISTS idx_academy_certificates_tenant ON academy_certificates(tenant_id);
CREATE INDEX IF NOT EXISTS idx_academy_certificates_user ON academy_certificates(user_id);
CREATE INDEX IF NOT EXISTS idx_academy_certificates_course ON academy_certificates(course_id);
CREATE INDEX IF NOT EXISTS idx_academy_certificates_enrollment ON academy_certificates(enrollment_id);

-- Comments for academy_certificates
COMMENT ON TABLE academy_certificates IS 'Certificates issued when a user completes a course';
COMMENT ON COLUMN academy_certificates.tenant_id IS 'Identifier for the tenant';
COMMENT ON COLUMN academy_certificates.enrollment_id IS 'Unique reference to the enrollment (one certificate per enrollment)';
COMMENT ON COLUMN academy_certificates.course_id IS 'Foreign key to the completed course';
COMMENT ON COLUMN academy_certificates.user_id IS 'Identifier of the certified user';
COMMENT ON COLUMN academy_certificates.user_name IS 'Name of the user as printed on the certificate';
COMMENT ON COLUMN academy_certificates.course_name IS 'Name of the course as printed on the certificate';
COMMENT ON COLUMN academy_certificates.score IS 'Final quiz score achieved (0-100)';
COMMENT ON COLUMN academy_certificates.issued_at IS 'Timestamp when the certificate was issued';
COMMENT ON COLUMN academy_certificates.valid_until IS 'Expiry date of the certificate (NULL = no expiry)';
COMMENT ON COLUMN academy_certificates.pdf_url IS 'URL to the generated certificate PDF';

-- ============================================================================
-- 6. academy_lesson_progress - Per-lesson progress tracking
-- ============================================================================

CREATE TABLE IF NOT EXISTS academy_lesson_progress (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    enrollment_id UUID NOT NULL REFERENCES academy_enrollments(id) ON DELETE CASCADE,
    lesson_id UUID NOT NULL REFERENCES academy_lessons(id) ON DELETE CASCADE,
    completed BOOLEAN DEFAULT false,
    quiz_score INTEGER,
    completed_at TIMESTAMP WITH TIME ZONE,
    CONSTRAINT uq_academy_lesson_progress_enrollment_lesson UNIQUE (enrollment_id, lesson_id)
);

-- Indexes for academy_lesson_progress
CREATE INDEX IF NOT EXISTS idx_academy_lesson_progress_enrollment ON academy_lesson_progress(enrollment_id);
CREATE INDEX IF NOT EXISTS idx_academy_lesson_progress_lesson ON academy_lesson_progress(lesson_id);

-- Comments for academy_lesson_progress
COMMENT ON TABLE academy_lesson_progress IS 'Tracks completion status and quiz scores per lesson per enrollment';
COMMENT ON COLUMN academy_lesson_progress.enrollment_id IS 'Foreign key to the enrollment';
COMMENT ON COLUMN academy_lesson_progress.lesson_id IS 'Foreign key to the lesson';
COMMENT ON COLUMN academy_lesson_progress.completed IS 'Whether the lesson has been completed';
COMMENT ON COLUMN academy_lesson_progress.quiz_score IS 'Quiz score for this lesson (0-100), NULL if no quiz';
COMMENT ON COLUMN academy_lesson_progress.completed_at IS 'Timestamp when the lesson was completed';

-- ============================================================================
-- Helper: Upsert function for lesson progress (ON CONFLICT handling)
-- ============================================================================

CREATE OR REPLACE FUNCTION upsert_academy_lesson_progress(
    p_enrollment_id UUID,
    p_lesson_id UUID,
    p_completed BOOLEAN,
    p_quiz_score INTEGER DEFAULT NULL
)
RETURNS academy_lesson_progress AS $$
DECLARE
    result academy_lesson_progress;
BEGIN
    INSERT INTO academy_lesson_progress (enrollment_id, lesson_id, completed, quiz_score, completed_at)
    VALUES (
        p_enrollment_id,
        p_lesson_id,
        p_completed,
        p_quiz_score,
        CASE WHEN p_completed THEN NOW() ELSE NULL END
    )
    ON CONFLICT ON CONSTRAINT uq_academy_lesson_progress_enrollment_lesson
    DO UPDATE SET
        completed = EXCLUDED.completed,
        quiz_score = COALESCE(EXCLUDED.quiz_score, academy_lesson_progress.quiz_score),
        completed_at = CASE
            WHEN EXCLUDED.completed AND academy_lesson_progress.completed_at IS NULL THEN NOW()
            WHEN NOT EXCLUDED.completed THEN NULL
            ELSE academy_lesson_progress.completed_at
        END
    RETURNING * INTO result;

    RETURN result;
END;
$$ LANGUAGE plpgsql;

COMMENT ON FUNCTION upsert_academy_lesson_progress IS 'Insert or update lesson progress with ON CONFLICT handling on the unique (enrollment_id, lesson_id) constraint';

-- ============================================================================
-- Helper: Cleanup function for expired certificates
-- ============================================================================

CREATE OR REPLACE FUNCTION cleanup_expired_academy_certificates(days_past_expiry INTEGER DEFAULT 0)
RETURNS INTEGER AS $$
DECLARE
    deleted_count INTEGER;
BEGIN
    DELETE FROM academy_certificates
    WHERE valid_until IS NOT NULL
      AND valid_until < NOW() - (days_past_expiry || ' days')::INTERVAL;

    GET DIAGNOSTICS deleted_count = ROW_COUNT;
    RETURN deleted_count;
END;
$$ LANGUAGE plpgsql;

COMMENT ON FUNCTION cleanup_expired_academy_certificates IS 'Removes certificates that have expired beyond the specified number of days';
