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

export const createFeedbackSchema = yup.object({
    feedbackMessage: yup
        .string()
        .required("Message is required")
        .min(3, "Message must be at least 3 characters"),
    rating: yup.number().default(0),
    target: yup.string().oneOf(["INSTITUTION", "PLATFORM"]).required("Target is required"),
    studentInstitutionId: yup.string().nullable().optional()
});

export const replyFeedbackSchema = yup.object({
    replyMessage: yup.string().optional().nullable(),
    status: yup.string().oneOf(["PENDING", "REVIEWED", "RESOLVED", "CLOSED"]).optional()
});

export const createFeedback = expressAsyncHandler(async (req, res) => {
    try {
        await createFeedbackSchema.validate(req.body, { abortEarly: false });
        const { feedbackMessage, rating, target, studentInstitutionId } = req.body;
        const user = req.user;

        const insertData: any = {
            feedbackMessage,
            rating: rating || 0,
            userId: user.id,
            status: "PENDING",
            target: target // INSTITUTION or PLATFORM
        };

        if (target === "INSTITUTION") {
            if (user.role !== "STUDENT") {
                res.status(403).json({ message: "Only students can submit feedback to institutions" });
                return;
            }

            if (!studentInstitutionId) {
                res.status(400).json({ message: "studentInstitutionId is required for institution feedback" });
                return;
            }
            insertData.studentInstitutionId = studentInstitutionId;

            const mapping = await prisma.studentInstitution.findUnique({
                where: { id: studentInstitutionId },
                select: { institutionId: true }
            });
            if (!mapping) {
                res.status(404).json({ message: "Invalid StudentInstitution mapping context" });
                return;
            }
            insertData.institutionId = mapping.institutionId;
        }
        else if (target === "PLATFORM") {
            if (user.role === "STUDENT") {
                res.status(403).json({ message: "Students cannot submit feedback to the platform" });
                return;
            }

            if (user.institutionId) {
                insertData.institutionId = user.institutionId;
            }
            insertData.studentInstitutionId = null;
        }

        const feedback = await prisma.feedback.create({ data: insertData });

        res.status(201).json({
            message: "Submitted successfully",
            data: {
                ...feedback,
                submittedAt: toIST(feedback.submittedAt),
                repliedAt: feedback.repliedAt ? toIST(feedback.repliedAt) : null,
                updatedAt: toIST(feedback.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 getAllFeedbacks = 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 targetFilter = (req.query.target as string)?.trim();

    const where: any = {
        AND: []
    };

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

        const upperSearch = search.toUpperCase();

        const validStatuses = ["PENDING", "RESOLVED", "OPEN", "CLOSED"];
        const isStatusEnum = validStatuses.includes(upperSearch);

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

            { feedbackMessage: { contains: search } },
            { replyMessage: { contains: search } },

            ...(isStatusEnum ? [{ status: upperSearch }] : []),

            {
                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 } }
                                ]
                            }))
                        }] : [])
                    ]
                }
            }
        ]
    }

    if (targetFilter) {
        where.AND.push({ target: targetFilter });
    }

    if (user.role === "ADMIN") {
    }
    else if (user.role === "INSTITUTION" || user.role === "STAFF") {
        where.AND.push({
            OR: [
                { institutionId: user.institutionId, target: "INSTITUTION" },
                { userId: user.id, target: "PLATFORM" }
            ]
        });
    }
    else {
        where.AND.push({ userId: user.id });
    }

    if (where.AND.length === 0) {
        delete where.AND;
    }

    const [feedbacks, total] = await Promise.all([
        prisma.feedback.findMany({
            where,
            include: {
                user: { select: { id: true, firstName: true, lastName: true, email: true } },
                institution: {
                    include: {
                        user: { select: { institutionName: true } }
                    }
                }
            },
            orderBy: { submittedAt: 'desc' },
            skip,
            take: limit,
        }),
        prisma.feedback.count({ where }),
    ]);

    const data = feedbacks.map((feedback: any) => {
        const emailPrefix = feedback.user?.email ? feedback.user.email.split("@")[0] : "";
        const computedName = `${feedback.user?.firstName || ""} ${feedback.user?.lastName || ""}`.trim();
        const finalName = computedName || emailPrefix || "Anonymous User";

        const instName = feedback.institution?.user?.institutionName || null;

        return {
            id: feedback.id,
            feedbackMessage: feedback.feedbackMessage,
            replyMessage: feedback.replyMessage,
            rating: feedback.rating,
            status: feedback.status,
            target: feedback.target,
            studentInstitutionId: feedback.studentInstitutionId,
            institutionId: feedback.institutionId,
            user: feedback.user
                ? {
                    id: feedback.user.id,
                    name: finalName,
                    email: feedback.user.email,
                    institutionName: instName
                }
                : { id: null, name: "Anonymous User", email: "N/A", institutionName: null },
            submittedAt: toIST(feedback.submittedAt),
            repliedAt: feedback.repliedAt ? toIST(feedback.repliedAt) : null,
            updatedAt: toIST(feedback.updatedAt),
        };
    });

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

export const replyToFeedback = expressAsyncHandler(async (req, res) => {
    try {
        await replyFeedbackSchema.validate(req.body, { abortEarly: false });
        const { id } = req.params;
        const { replyMessage, status } = req.body;
        const user = req.user;

        const existingFeedback = await prisma.feedback.findUnique({
            where: { id }
        });

        if (!existingFeedback) {
            res.status(404).json({ message: "Feedback log record not found" });
            return;
        }

        if (user.role === "ADMIN") {
            if (existingFeedback.target !== "PLATFORM") {
                res.status(403).json({ message: "Admin can only reply to platform feedback" });
                return;
            }
        }
        else if (user.role === "INSTITUTION" || user.role === "STAFF") {
            if (existingFeedback.target !== "INSTITUTION" || existingFeedback.institutionId !== user.institutionId) {
                res.status(403).json({ message: "Not authorized to modify this feedback context thread" });
                return;
            }
        }
        else {
            res.status(403).json({ message: "Students are blocked from initiating structural replies" });
            return;
        }

        const updateData: any = {};
        if (status) updateData.status = status;
        if (replyMessage !== undefined) {
            updateData.replyMessage = replyMessage || null;
            updateData.repliedAt = replyMessage ? new Date() : null;
        }

        const feedback = await prisma.feedback.update({
            where: { id },
            data: updateData
        });

        res.status(200).json({
            message: "Feedback updated successfully",
            data: {
                ...feedback,
                submittedAt: toIST(feedback.submittedAt),
                repliedAt: feedback.repliedAt ? toIST(feedback.repliedAt) : null,
                updatedAt: toIST(feedback.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" });
    }
});