import { prisma } from '../config/database';
import { config } from '../config';
import { logger } from '../config/logger';
import { NotFoundError, ForbiddenError, ValidationError } from '../middleware/errorHandler';
import jwt from 'jsonwebtoken';
import { PDFDocument, rgb } from 'pdf-lib';
import fontkit from '@pdf-lib/fontkit';
import * as fs from 'fs';
import * as path from 'path';
import { uploadFile, getPresignedUrl } from '../config/minio';
import {
    GenerateCertificateInput,
    GenerateCertificateResponse,
    GetCertificateInput,
    GetCertificateResponse,
    ListMyCertificatesInput,
    ListMyCertificatesResponse,
} from '../types/certificate.types';

export class CertificateService {
    private static TEMPLATE_PATH = path.join(__dirname, '../../assets/templates/Certificate.pdf');
    private static FONT_REGULAR_PATH = path.join(__dirname, '../../assets/fonts/THSarabunNew.ttf');
    private static FONT_BOLD_PATH = path.join(__dirname, '../../assets/fonts/THSarabunNew Bold.ttf');

    /**
     * Generate certificate PDF for a completed course
     */
    async generateCertificate(input: GenerateCertificateInput): Promise<GenerateCertificateResponse> {
        try {
            const { token, course_id } = input;
            const decoded = jwt.verify(token, config.jwt.secret) as { id: number };

            // Check enrollment and completion
            const enrollment = await prisma.enrollment.findUnique({
                where: {
                    unique_enrollment: {
                        user_id: decoded.id,
                        course_id,
                    },
                },
                include: {
                    course: {
                        select: {
                            id: true,
                            title: true,
                            have_certificate: true,
                        },
                    },
                    user: {
                        include: {
                            profile: true,
                        },
                    },
                },
            });

            if (!enrollment) {
                throw new NotFoundError('Enrollment not found');
            }

            if (enrollment.status !== 'COMPLETED') {
                throw new ForbiddenError('Course not completed yet');
            }

            if (!enrollment.course.have_certificate) {
                throw new ValidationError('This course does not offer certificates');
            }

            // Check if certificate already exists
            const existingCertificate = await prisma.certificate.findFirst({
                where: {
                    user_id: decoded.id,
                    course_id,
                },
            });

            if (existingCertificate) {
                // Return existing certificate
                const downloadUrl = await getPresignedUrl(existingCertificate.file_path, 3600);
                return {
                    code: 200,
                    message: 'Certificate already exists',
                    data: {
                        certificate_id: existingCertificate.id,
                        file_path: existingCertificate.file_path,
                        download_url: downloadUrl,
                        issued_at: existingCertificate.issued_at,
                    },
                };
            }

            // Get user full name
            const firstName = enrollment.user.profile?.first_name || '';
            const lastName = enrollment.user.profile?.last_name || '';
            const fullName = `${firstName} ${lastName}`.trim() || enrollment.user.username;

            // Get course title
            const courseTitle = enrollment.course.title as { th: string; en: string };

            // Generate PDF
            const pdfBytes = await this.createCertificatePDF({
                studentName: fullName,
                courseTitleTh: courseTitle.th,
                courseTitleEn: courseTitle.en,
                completionDate: enrollment.completed_at || new Date(),
            });

            // Upload to MinIO
            const timestamp = Date.now();
            const filePath = `certificates/${course_id}/${decoded.id}/${timestamp}.pdf`;
            await uploadFile(filePath, Buffer.from(pdfBytes), 'application/pdf');

            // Save to database
            const certificate = await prisma.certificate.create({
                data: {
                    user_id: decoded.id,
                    course_id,
                    enrollment_id: enrollment.id,
                    file_path: filePath,
                    issued_at: new Date(),
                },
            });

            const downloadUrl = await getPresignedUrl(filePath, 3600);

            return {
                code: 201,
                message: 'Certificate generated successfully',
                data: {
                    certificate_id: certificate.id,
                    file_path: certificate.file_path,
                    download_url: downloadUrl,
                    issued_at: certificate.issued_at,
                },
            };
        } catch (error) {
            logger.error('Failed to generate certificate', { error });
            throw error;
        }
    }

    /**
     * Get certificate for a specific course
     */
    async getCertificate(input: GetCertificateInput): Promise<GetCertificateResponse> {
        try {
            const { token, course_id } = input;
            const decoded = jwt.verify(token, config.jwt.secret) as { id: number };

            const certificate = await prisma.certificate.findFirst({
                where: {
                    user_id: decoded.id,
                    course_id,
                },
                include: {
                    enrollment: {
                        include: {
                            course: {
                                select: {
                                    title: true,
                                },
                            },
                        },
                    },
                },
            });

            if (!certificate) {
                throw new NotFoundError('Certificate not found');
            }

            const downloadUrl = await getPresignedUrl(certificate.file_path, 3600);
            const courseTitle = certificate.enrollment.course.title as { th: string; en: string };

            return {
                code: 200,
                message: 'Certificate retrieved successfully',
                data: {
                    certificate_id: certificate.id,
                    course_id: certificate.course_id,
                    course_title: courseTitle,
                    file_path: certificate.file_path,
                    download_url: downloadUrl,
                    issued_at: certificate.issued_at,
                },
            };
        } catch (error) {
            logger.error('Failed to get certificate', { error });
            throw error;
        }
    }

    /**
     * List all certificates for the authenticated user
     */
    async listMyCertificates(input: ListMyCertificatesInput): Promise<ListMyCertificatesResponse> {
        try {
            const { token } = input;
            const decoded = jwt.verify(token, config.jwt.secret) as { id: number };

            const certificates = await prisma.certificate.findMany({
                where: {
                    user_id: decoded.id,
                },
                include: {
                    enrollment: {
                        include: {
                            course: {
                                select: {
                                    title: true,
                                },
                            },
                        },
                    },
                },
                orderBy: {
                    issued_at: 'desc',
                },
            });

            const data = await Promise.all(
                certificates.map(async (cert) => {
                    const downloadUrl = await getPresignedUrl(cert.file_path, 3600);
                    const courseTitle = cert.enrollment.course.title as { th: string; en: string };
                    return {
                        certificate_id: cert.id,
                        course_id: cert.course_id,
                        course_title: courseTitle,
                        download_url: downloadUrl,
                        issued_at: cert.issued_at,
                    };
                })
            );

            return {
                code: 200,
                message: 'Certificates retrieved successfully',
                data,
            };
        } catch (error) {
            logger.error('Failed to list certificates', { error });
            throw error;
        }
    }

    /**
     * Create certificate PDF from template
     */
    private async createCertificatePDF(params: {
        studentName: string;
        courseTitleTh: string;
        courseTitleEn: string;
        completionDate: Date;
    }): Promise<Uint8Array> {
        const { studentName, courseTitleTh, courseTitleEn, completionDate } = params;

        // Load template PDF
        const templateBytes = fs.readFileSync(CertificateService.TEMPLATE_PATH);
        const pdfDoc = await PDFDocument.load(templateBytes);

        // Register fontkit for custom fonts
        pdfDoc.registerFontkit(fontkit);

        // Load Thai fonts
        const fontRegularBytes = fs.readFileSync(CertificateService.FONT_REGULAR_PATH);
        const fontBoldBytes = fs.readFileSync(CertificateService.FONT_BOLD_PATH);
        const fontRegular = await pdfDoc.embedFont(fontRegularBytes);
        const fontBold = await pdfDoc.embedFont(fontBoldBytes);

        // Get first page
        const pages = pdfDoc.getPages();
        const page = pages[0];
        const { width, height } = page.getSize();

        // Format date in Thai
        const thaiMonths = [
            'มกราคม', 'กุมภาพันธ์', 'มีนาคม', 'เมษายน', 'พฤษภาคม', 'มิถุนายน',
            'กรกฎาคม', 'สิงหาคม', 'กันยายน', 'ตุลาคม', 'พฤศจิกายน', 'ธันวาคม'
        ];
        const day = completionDate.getDate();
        const month = thaiMonths[completionDate.getMonth()];
        const year = completionDate.getFullYear() + 543; // Buddhist Era
        const dateText = `${day} ${month} ${year}`;

        // Colors for dark blue background
        const whiteColor = rgb(1, 1, 1); // White text
        const lightGrayColor = rgb(0.85, 0.85, 0.85); // Light gray for secondary text

        // Draw student name (centered) - positioned below "HAS SUCCESSFULLY COMPLETED"
        const nameSize = 42;
        const nameWidth = fontBold.widthOfTextAtSize(studentName, nameSize);
        page.drawText(studentName, {
            x: (width - nameWidth) / 2,
            y: height * 0.59,
            size: nameSize,
            font: fontBold,
            color: whiteColor,
        });

        // Draw course title (Thai + English combined, centered)
        const courseTitle = `${courseTitleTh} ${courseTitleEn}`;
        const courseTitleSize = 28;
        const courseTitleWidth = fontRegular.widthOfTextAtSize(courseTitle, courseTitleSize);
        page.drawText(courseTitle, {
            x: (width - courseTitleWidth) / 2,
            y: height * 0.43,
            size: courseTitleSize,
            font: fontRegular,
            color: whiteColor,
        });

        // Draw completion date (centered) - at bottom
        const dateSize = 18;
        const dateWidth = fontRegular.widthOfTextAtSize(dateText, dateSize);
        page.drawText(dateText, {
            x: (width - dateWidth) / 2,
            y: height * 0.30,
            size: dateSize,
            font: fontRegular,
            color: lightGrayColor,
        });

        // Save and return PDF bytes
        return await pdfDoc.save();
    }
}
