import expressAsyncHandler from "express-async-handler";
import * as yup from "yup";
import { prisma } from "../config/db.ts";
import { toIST } from "../utils/time.ts";
import { getHost } from "../utils/utils.ts";

export const createSupportSchema = yup.object({
    message: yup
        .string()
        .required("Message is required")
        .min(3, "Message must be at least 3 characters"),
    questionId: yup
        .string()
        .nullable()
        .required("questionId is required"),
    questionType: yup
        .string()
        .nullable()
        .required("questionType is required"),
});

export const createQuestionSupport = expressAsyncHandler(async (req, res) => {
    try {
        await createSupportSchema.validate(req.body, { abortEarly: false });
        const user = req.user;
        const { message, questionId, questionType } = req.body;
        const userId = user.id;
        let question;
        const type = questionType?.toLowerCase();
        if (type === "oldquestion" || type === "pyq") {
            question = await prisma.oldQuestion.findUnique({ where: { id: questionId, institutionId: user.institutionId } });
        } else if (type === "questionbank" || type === "mocktest" || type === "practicetest") {
            question = await prisma.questionBank.findUnique({ where: { id: questionId, institutionId: user.institutionId } });
        } else {
            res.status(400).json({ message: "Invalid question type" });
            return;
        }
        if (!question) {
            res.status(404).json({ message: "Question not found" });
            return;
        }

        const support = await prisma.support.create({
            data: {
                message,
                questionId,
                userId,
                questionType,
                institutionId: user.institutionId,
            },
        });

        res.status(201).json({
            message: "Submitted successfully",
            data: {
                ...support,
                createdAt: toIST(support.createdAt),
                updatedAt: toIST(support.updatedAt),
            },
        });

    } catch (err) {
        if (err instanceof yup.ValidationError) {
            res.status(400).json({
                message: "Validation failed",
                errors: err.errors,
            });
            return;
        }
        res.status(500).json({ message: "Server error" });
    }
});
export const getAllSupports = expressAsyncHandler(async (req, res) => {
    const user = req.user;

    const page = Math.max(Number(req.query.page) || 1, 1);
    const limit = Math.max(Number(req.query.limit) || 10, 1);
    const skip = (page - 1) * limit;
    const search = (req.query.search as string)?.trim();
    const statusFilter = (req.query.status as string)?.trim();

    const isAdmin = user.role === "ADMIN";
    const where: any = {};
    if (!isAdmin) {
        where.institutionId = user.institutionId;
    }
    if (user.role === "STUDENT") {
        where.userId = user.id;
    }

    if (statusFilter && statusFilter.toLowerCase() !== 'all') {
        where.status = statusFilter;
    }

    if (search) {
        const searchWords = search.split(/\s+/).filter(Boolean);
        const cleanTicketId = search.replace(/ticket/i, "").replace("#", "").trim();

        where.OR = [
            { id: { contains: cleanTicketId ? cleanTicketId : search } },

            { message: { contains: search } },
            { status: { contains: search } },
            {
                user: {
                    OR: [
                        { firstName: { contains: search } },
                        { lastName: { contains: search } },
                        { email: { contains: search } },
                        ...(searchWords.length > 1 ? [{
                            AND: searchWords.map(word => ({
                                OR: [
                                    { firstName: { contains: word } },
                                    { lastName: { contains: word } }
                                ]
                            }))
                        }] : [])
                    ]
                }
            }
        ];
    }

    const [supports, total] = await Promise.all([
        prisma.support.findMany({
            where,
            include: {
                user: {
                    select: {
                        id: true,
                        firstName: true,
                        lastName: true,
                        email: true
                    }
                }
            },
            orderBy: { createdAt: 'desc' },
            skip,
            take: limit
        }),

        prisma.support.count({ where })
    ]);

    // Collect IDs by type
    const qbIds: string[] = [];
    const oldIds: string[] = [];

    supports.forEach((s) => {
        if (!s.questionId) return;
        const type = s.questionType?.toLowerCase();
        if (type === 'oldquestion' || type === 'pyq') oldIds.push(s.questionId);
        else if (type === 'questionbank' || type === 'mocktest' || type === 'practicetest') qbIds.push(s.questionId);
    });

    const [qbQuestions, oldQuestions] = await Promise.all([
        prisma.questionBank.findMany({
            where: { id: { in: qbIds } },
            select: { 
                id: true, questionText: true, questionImage: true, options: true, correctAnswer: true, explanation: true,
                testQuestions: { select: { test: { select: { practiceTests: { select: { id: true, title: true } } } } } },
                mockTestQuestions: { select: { mockTest: { select: { id: true, title: true } } } }
            }
        }),

        prisma.oldQuestion.findMany({
            where: { id: { in: oldIds } },
            select: { 
                id: true, questionText: true, questionImage: true, options: true, correctAnswer: true, explanation: true,
                oldQuestionPapers: { select: { id: true, title: true, year: true, exam: { select: { examName: true } } } }
            }
        }),
    ]);
    // Create lookup maps
    const qbMap = new Map(qbQuestions.map(q => [q.id, q]));
    const oldMap = new Map(oldQuestions.map(q => [q.id, q]));

    const data = supports.map((support) => {

        let question = null;
        let testName = "Unknown";
        let testType = "Unknown";
        const type = support.questionType?.toLowerCase();

        if (type === 'questionbank' || type === 'mocktest' || type === 'practicetest') {
            const qbQ = qbMap.get(support.questionId);
            if (qbQ) {
                if (type === 'mocktest') {
                    testType = "Mock Test";
                    testName = qbQ.mockTestQuestions?.[0]?.mockTest?.title || "Mock Test";
                } else {
                    testType = "Practice Test";
                    let practiceTestTitle = null;
                    for (const tq of qbQ.testQuestions || []) {
                        if (tq.test?.practiceTests && tq.test.practiceTests.length > 0) {
                            practiceTestTitle = tq.test.practiceTests[0].title;
                            break;
                        }
                    }
                    testName = practiceTestTitle || "Practice Test";
                }
                
                question = {
                    ...qbQ,
                    correctAnswer: qbQ.correctAnswer
                };
            }
        } else if (type === 'oldquestion' || type === 'pyq') {
            const oldQ = oldMap.get(support.questionId);
            if (oldQ) {
                testType = "PYQ";
                const oqp = oldQ.oldQuestionPapers?.[0];
                if (oqp) {
                    const title = oqp.title || oqp.exam?.examName || 'PYQ Exam';
                    testName = `${title} (${oqp.year})`;
                } else {
                    testName = "PYQ";
                }

                question = {
                    ...oldQ,
                    correctAnswer: oldQ.correctAnswer
                };
            }
        }

        return {
            id: support.id,
            message: support.message,
            status: support.status,
            resolutionMessage: (support as any).resolutionMessage,
            questionId: support.questionId,
            testName,
            testType,
            questionType: support.questionType,

            question: question
                ? {
                    id: question.id,
                    questionText: question.questionText || question.title,
                    questionImage: question.questionImage ? `${getHost()}${question.questionImage}` : null,
                    options: Array.isArray(question.options)
                        ? question.options.map((opt: any) => ({
                            ...opt,
                            optionImage: opt.optionImage ? `${getHost()}${opt.optionImage}` : null,
                        }))
                        : question.options,
                    correctAnswer: question.correctAnswer ?? question.correctOption,
                    explanation: question.explanation,
                    explanationImage: question.explanationImage ? `${getHost()}${question.explanationImage}` : null
                }
                : null,

            user: support.user
                ? {
                    id: support.user.id,
                    name: `${support.user.firstName} ${support.user.lastName}`.trim(),
                    email: support.user.email
                }
                : null,

            createdAt: toIST(support.createdAt),
            updatedAt: toIST(support.updatedAt)
        };
    });

    res.status(200).json({
        success: true,
        data,
        meta: {
            page,
            limit,
            total,
            totalPages: Math.ceil(total / limit)
        }
    });
});

export const updateSupportStatus = expressAsyncHandler(async (req, res) => {
    const { id } = req.params;
    const { status, resolutionMessage } = req.body;
    const user = req.user;

    // Based on Prisma schema default is "pending"
    if (!['pending', 'resolved', 'closed'].includes(status)) {
        res.status(400).json({ success: false, message: "Invalid status" });
        return;
    }

    const isAdmin = user.role === "ADMIN";
    const whereClause: any = { id };
    if (!isAdmin) {
        whereClause.institutionId = user.institutionId;
    }

    try {
        const support = await prisma.support.update({
            where: whereClause,
            data: { 
                status,
                ...(resolutionMessage !== undefined && { resolutionMessage })
            }
        });

        res.status(200).json({
            success: true,
            message: "Status updated successfully",
            data: {
                ...support,
                createdAt: toIST(support.createdAt),
                updatedAt: toIST(support.updatedAt),
            }
        });
    } catch (error) {
        res.status(404).json({ success: false, message: "Support ticket not found" });
    }
});
