import { Get, Body, Post, Route, Tags, SuccessResponse, Response, Security, Put, Path, Delete, Request, Example, FormField, UploadedFile, Query } from 'tsoa';
import { ValidationError } from '../middleware/errorHandler';
import { CoursesInstructorService } from '../services/CoursesInstructor.service';
import {
    createCourses,
    createCourseResponse,
    GetMyCourseResponse,
    ListMyCourseResponse,
    addinstructorCourseResponse,
    removeinstructorCourseResponse,
    setprimaryCourseInstructorResponse,
    UpdateMyCourse,
    UpdateMyCourseResponse,
    DeleteMyCourseResponse,
    submitCourseResponse,
    listinstructorCourseResponse,
    GetCourseApprovalsResponse,
    SearchInstructorResponse,
    GetEnrolledStudentsResponse,
    GetQuizScoresResponse,
    GetQuizAttemptDetailResponse,
    GetEnrolledStudentDetailResponse,
} from '../types/CoursesInstructor.types';
import { CreateCourseValidator } from "../validators/CoursesInstructor.validator";

import jwt from 'jsonwebtoken';
import { config } from '../config';

@Route('api/instructors/courses')
@Tags('CoursesInstructor')
export class CoursesInstructorController {

    /**
     * ดึงรายการคอร์สทั้งหมดของผู้สอน
     * Get all courses where the authenticated user is an instructor
     */
    @Get('')
    @Security('jwt', ['instructor'])
    @SuccessResponse('200', 'Courses retrieved successfully')
    @Response('401', 'Invalid or expired token')
    @Response('404', 'Courses not found')
    public async listMyCourses(@Request() request: any): Promise<ListMyCourseResponse> {
        const token = request.headers.authorization?.replace('Bearer ', '');
        if (!token) {
            throw new ValidationError('No token provided');
        }
        return await CoursesInstructorService.listMyCourses(token);
    }

    /**
     * ค้นหาผู้สอนทั้งหมดในระบบ (ไม่รวมตัวเองและคนที่อยู่ในคอร์สแล้ว)
     * Search all instructors in database (excluding self and existing course instructors)
     * @param courseId - รหัสคอร์ส / Course ID
     * @param query - คำค้นหา (email หรือ username) / Search query (email or username)
     */
    @Get('{courseId}/search-instructors')
    @Security('jwt', ['instructor'])
    @SuccessResponse('200', 'Instructors found')
    @Response('401', 'Invalid or expired token')
    public async searchInstructors(
        @Request() request: any,
        @Path() courseId: number,
        @Query() query: string
    ): Promise<SearchInstructorResponse> {
        const token = request.headers.authorization?.replace('Bearer ', '');
        if (!token) throw new ValidationError('No token provided');
        return await CoursesInstructorService.searchInstructors({ token, query, course_id: courseId });
    }

    /**
     * ดึงข้อมูลคอร์สเฉพาะของผู้สอน (พร้อมบทเรียนและเนื้อหา)
     * Get detailed course information including chapters, lessons, attachments, and quizzes
     * @param courseId - รหัสคอร์ส / Course ID
     */
    @Get('{courseId}')
    @Security('jwt', ['instructor'])
    @SuccessResponse('200', 'Course retrieved successfully')
    @Response('401', 'Invalid or expired token')
    @Response('404', 'Course not found')
    public async getMyCourse(@Request() request: any, @Path() courseId: number): Promise<GetMyCourseResponse> {
        const token = request.headers.authorization?.replace('Bearer ', '');
        if (!token) {
            throw new ValidationError('No token provided');
        }
        return await CoursesInstructorService.getmyCourse({ token, course_id: courseId });
    }

    /**
     * แก้ไขข้อมูลคอร์ส
     * Update course information (only for course instructors)
     * @param courseId - รหัสคอร์ส / Course ID
     */
    @Put('{courseId}')
    @Security('jwt', ['instructor'])
    @SuccessResponse('200', 'Course updated successfully')
    @Response('401', 'Invalid or expired token')
    @Response('404', 'Course not found')
    public async updateCourse(@Request() request: any, @Path() courseId: number, @Body() body: UpdateMyCourse): Promise<UpdateMyCourseResponse> {
        const token = request.headers.authorization?.replace('Bearer ', '');
        if (!token) {
            throw new ValidationError('No token provided');
        }
        return await CoursesInstructorService.updateCourse(token, courseId, body.data);
    }

    /**
     * สร้างคอร์สใหม่ (พร้อมอัปโหลดรูป thumbnail)
     * Create a new course with optional thumbnail upload (status will be DRAFT by default)
     * @param data - JSON string containing course data
     * @param thumbnail - Optional thumbnail image file
     */
    @Post('')
    @Security('jwt', ['instructor'])
    @SuccessResponse('201', 'Course created successfully')
    @Response('400', 'Validation error')
    @Response('500', 'Internal server error')
    public async createCourse(
        @Request() request: any,
        @FormField() data: string,
        @UploadedFile() thumbnail?: Express.Multer.File
    ): Promise<createCourseResponse> {
        const token = request.headers.authorization?.replace('Bearer ', '');
        if (!token) throw new ValidationError('No token provided');

        const decoded = jwt.verify(token, config.jwt.secret) as { id: number };
        const parsed = JSON.parse(data);
        const { error, value } = CreateCourseValidator.validate(parsed);
        if (error) throw new ValidationError(error.details[0].message);

        // Validate thumbnail file type if provided
        if (thumbnail && !thumbnail.mimetype?.startsWith('image/')) throw new ValidationError('Only image files are allowed for thumbnail');

        return await CoursesInstructorService.createCourse(value, decoded.id, thumbnail);
    }

    /**
     * อัปโหลดรูป thumbnail ของคอร์ส
     * Upload course thumbnail image
     * @param courseId - รหัสคอร์ส / Course ID
     * @param file - ไฟล์รูปภาพ / Image file
     */
    @Post('{courseId}/thumbnail')
    @Security('jwt', ['instructor'])
    @SuccessResponse('200', 'Thumbnail uploaded successfully')
    @Response('401', 'Invalid or expired token')
    @Response('400', 'Validation error')
    public async uploadThumbnail(
        @Request() request: any,
        @Path() courseId: number,
        @UploadedFile() file: Express.Multer.File
    ): Promise<{ code: number; message: string; data: { course_id: number; thumbnail_url: string } }> {
        const token = request.headers.authorization?.replace('Bearer ', '');
        if (!token) throw new ValidationError('No token provided');
        if (!file.mimetype?.startsWith('image/')) throw new ValidationError('Only image files are allowed');

        return await CoursesInstructorService.uploadThumbnail(token, courseId, file);
    }

    /**
     * ลบคอร์ส (เฉพาะผู้สอนหลักเท่านั้น)
     * Delete a course (only primary instructor can delete)
     * @param courseId - รหัสคอร์ส / Course ID
     */
    @Delete('{courseId}')
    @Security('jwt', ['instructor'])
    @SuccessResponse('200', 'Course deleted successfully')
    @Response('401', 'Invalid or expired token')
    @Response('404', 'Course not found')
    public async deleteCourse(@Request() request: any, @Path() courseId: number): Promise<DeleteMyCourseResponse> {
        const token = request.headers.authorization?.replace('Bearer ', '');
        if (!token) throw new ValidationError('No token provided')
        return await CoursesInstructorService.deleteCourse(token, courseId);
    }

    /**
     * ส่งคอร์สเพื่อขออนุมัติจากแอดมิน
     * Submit course for admin review and approval
     * @param courseId - รหัสคอร์ส / Course ID
     */
    @Post('send-review/{courseId}')
    @Security('jwt', ['instructor'])
    @SuccessResponse('200', 'Course submitted successfully')
    @Response('401', 'Invalid or expired token')
    @Response('404', 'Course not found')
    public async submitCourse(@Request() request: any, @Path() courseId: number): Promise<submitCourseResponse> {
        const token = request.headers.authorization?.replace('Bearer ', '');
        if (!token) throw new ValidationError('No token provided')
        return await CoursesInstructorService.sendCourseForReview({ token, course_id: courseId });
    }

    /**
     * ดึงประวัติการส่งอนุมัติคอร์สทั้งหมด
     * Get all course approval history
     * @param courseId - รหัสคอร์ส / Course ID
     */
    @Get('{courseId}/approvals')
    @Security('jwt', ['instructor'])
    @SuccessResponse('200', 'Course approvals retrieved successfully')
    @Response('401', 'Invalid or expired token')
    @Response('403', 'You are not an instructor of this course')
    @Response('404', 'Course not found')
    public async getCourseApprovals(@Request() request: any, @Path() courseId: number): Promise<GetCourseApprovalsResponse> {
        const token = request.headers.authorization?.replace('Bearer ', '');
        if (!token) throw new ValidationError('No token provided')
        return await CoursesInstructorService.getCourseApprovals(token, courseId);
    }

    /**
     * ดึงรายชื่อผู้สอนทั้งหมดในคอร์ส
     * Get list of all instructors in a specific course
     * @param courseId - รหัสคอร์ส / Course ID
     */
    @Get('listinstructor/{courseId}')
    @Security('jwt', ['instructor'])
    @SuccessResponse('200', 'Instructors retrieved successfully')
    @Response('401', 'Invalid or expired token')
    @Response('404', 'Instructors not found')
    public async listInstructorCourses(@Request() request: any, @Path() courseId: number): Promise<listinstructorCourseResponse> {
        const token = request.headers.authorization?.replace('Bearer ', '');
        if (!token) throw new ValidationError('No token provided')
        return await CoursesInstructorService.listInstructorsOfCourse({ token, course_id: courseId });
    }

    /**
     * เพิ่มผู้สอนเข้าในคอร์ส (ใช้ email หรือ username)
     * Add a new instructor to the course (using email or username)
     * @param courseId - รหัสคอร์ส / Course ID
     * @param emailOrUsername - email หรือ username ของผู้สอน / Instructor's email or username
     */
    @Post('add-instructor/{courseId}/{emailOrUsername}')
    @Security('jwt', ['instructor'])
    @SuccessResponse('200', 'Instructor added successfully')
    @Response('401', 'Invalid or expired token')
    @Response('404', 'Instructor not found')
    public async addInstructor(@Request() request: any, @Path() courseId: number, @Path() emailOrUsername: string): Promise<addinstructorCourseResponse> {
        const token = request.headers.authorization?.replace('Bearer ', '');
        if (!token) throw new ValidationError('No token provided')
        return await CoursesInstructorService.addInstructorToCourse({ token, course_id: courseId, email_or_username: emailOrUsername });
    }

    /**
     * ลบผู้สอนออกจากคอร์ส
     * Remove an instructor from the course
     * @param courseId - รหัสคอร์ส / Course ID
     * @param userId - รหัสผู้ใช้ที่ต้องการลบออกจากผู้สอน / User ID to remove from instructors
     */
    @Delete('remove-instructor/{courseId}/{userId}')
    @Security('jwt', ['instructor'])
    @SuccessResponse('200', 'Instructor removed successfully')
    @Response('401', 'Invalid or expired token')
    @Response('404', 'Instructor not found')
    public async removeInstructor(@Request() request: any, @Path() courseId: number, @Path() userId: number): Promise<removeinstructorCourseResponse> {
        const token = request.headers.authorization?.replace('Bearer ', '');
        if (!token) throw new ValidationError('No token provided')
        return await CoursesInstructorService.removeInstructorFromCourse({ token, course_id: courseId, user_id: userId });
    }

    /**
     * กำหนดผู้สอนหลักของคอร์ส
     * Set a user as the primary instructor of the course
     * @param courseId - รหัสคอร์ส / Course ID
     * @param userId - รหัสผู้ใช้ที่ต้องการตั้งเป็นผู้สอนหลัก / User ID to set as primary instructor
     */
    @Put('set-primary-instructor/{courseId}/{userId}')
    @Security('jwt', ['instructor'])
    @SuccessResponse('200', 'Primary instructor set successfully')
    @Response('401', 'Invalid or expired token')
    @Response('404', 'Primary instructor not found')
    public async setPrimaryInstructor(@Request() request: any, @Path() courseId: number, @Path() userId: number): Promise<setprimaryCourseInstructorResponse> {
        const token = request.headers.authorization?.replace('Bearer ', '');
        if (!token) throw new ValidationError('No token provided')
        return await CoursesInstructorService.setPrimaryInstructor({ token, course_id: courseId, user_id: userId });
    }

    /**
     * ดึงรายชื่อนักเรียนที่ลงทะเบียนในคอร์สพร้อม progress
     * Get all enrolled students with their progress
     * @param courseId - รหัสคอร์ส / Course ID
     * @param page - หน้าที่ต้องการ / Page number
     * @param limit - จำนวนต่อหน้า / Items per page
     * @param search - ค้นหาด้วย firstname, lastname, email, username
     * @param status - กรองตามสถานะ (ENROLLED, COMPLETED)
     */
    @Get('{courseId}/students')
    @Security('jwt', ['instructor'])
    @SuccessResponse('200', 'Enrolled students retrieved successfully')
    @Response('401', 'Invalid or expired token')
    @Response('403', 'Not an instructor of this course')
    public async getEnrolledStudents(
        @Request() request: any,
        @Path() courseId: number,
        @Query() page?: number,
        @Query() limit?: number,
        @Query() search?: string,
        @Query() status?: 'ENROLLED' | 'COMPLETED'
    ): Promise<GetEnrolledStudentsResponse> {
        const token = request.headers.authorization?.replace('Bearer ', '');
        if (!token) throw new ValidationError('No token provided');
        return await CoursesInstructorService.getEnrolledStudents({
            token,
            course_id: courseId,
            page,
            limit,
            search,
            status,
        });
    }

    /**
     * ดึงรายละเอียดการเรียนของนักเรียนแต่ละคน (progress ของแต่ละ lesson)
     * Get enrolled student detail with lesson progress
     * @param courseId - รหัสคอร์ส / Course ID
     * @param studentId - รหัสนักเรียน / Student ID
     */
    @Get('{courseId}/students/{studentId}')
    @Security('jwt', ['instructor'])
    @SuccessResponse('200', 'Enrolled student detail retrieved successfully')
    @Response('401', 'Invalid or expired token')
    @Response('403', 'Not an instructor of this course')
    @Response('404', 'Student not found or not enrolled')
    public async getEnrolledStudentDetail(
        @Request() request: any,
        @Path() courseId: number,
        @Path() studentId: number
    ): Promise<GetEnrolledStudentDetailResponse> {
        const token = request.headers.authorization?.replace('Bearer ', '');
        if (!token) throw new ValidationError('No token provided');
        return await CoursesInstructorService.getEnrolledStudentDetail({
            token,
            course_id: courseId,
            student_id: studentId,
        });
    }

    /**
     * ดึงคะแนนสอบของนักเรียนทุกคนในแต่ละ lesson quiz
     * Get quiz scores of all students for a specific lesson
     * @param courseId - รหัสคอร์ส / Course ID
     * @param lessonId - รหัสบทเรียน / Lesson ID
     * @param page - หน้าที่ต้องการ / Page number
     * @param limit - จำนวนต่อหน้า / Items per page
     * @param search - ค้นหาด้วย firstname, lastname, email, username
     * @param isPassed - กรองตามผลสอบ (true = ผ่าน, false = ไม่ผ่าน)
     */
    @Get('{courseId}/lessons/{lessonId}/quiz/scores')
    @Security('jwt', ['instructor'])
    @SuccessResponse('200', 'Quiz scores retrieved successfully')
    @Response('401', 'Invalid or expired token')
    @Response('403', 'Not an instructor of this course')
    @Response('404', 'Lesson or quiz not found')
    public async getQuizScores(
        @Request() request: any,
        @Path() courseId: number,
        @Path() lessonId: number,
        @Query() page?: number,
        @Query() limit?: number,
        @Query() search?: string,
        @Query() isPassed?: boolean
    ): Promise<GetQuizScoresResponse> {
        const token = request.headers.authorization?.replace('Bearer ', '');
        if (!token) throw new ValidationError('No token provided');
        return await CoursesInstructorService.getQuizScores({
            token,
            course_id: courseId,
            lesson_id: lessonId,
            page,
            limit,
            search,
            is_passed: isPassed,
        });
    }

    /**
     * ดูรายละเอียดการทำข้อสอบล่าสุดของนักเรียนแต่ละคน
     * Get latest quiz attempt detail for a specific student
     * @param courseId - รหัสคอร์ส / Course ID
     * @param lessonId - รหัสบทเรียน / Lesson ID
     * @param studentId - รหัสนักเรียน / Student ID
     */
    @Get('{courseId}/lessons/{lessonId}/quiz/students/{studentId}')
    @Security('jwt', ['instructor'])
    @SuccessResponse('200', 'Quiz attempt detail retrieved successfully')
    @Response('401', 'Invalid or expired token')
    @Response('403', 'Not an instructor of this course')
    @Response('404', 'Student or quiz attempt not found')
    public async getQuizAttemptDetail(
        @Request() request: any,
        @Path() courseId: number,
        @Path() lessonId: number,
        @Path() studentId: number
    ): Promise<GetQuizAttemptDetailResponse> {
        const token = request.headers.authorization?.replace('Bearer ', '');
        if (!token) throw new ValidationError('No token provided');
        return await CoursesInstructorService.getQuizAttemptDetail({
            token,
            course_id: courseId,
            lesson_id: lessonId,
            student_id: studentId,
        });
    }
}