import type { Request, Response } from 'express';
import asyncHandler from 'express-async-handler';
import crypto from 'crypto';
import { prisma } from '../config/db.ts';
import { razorpay } from '../config/razorpay.ts';
import { toIST } from '../utils/time.ts';
import { sendNotification } from '../config/firebase.ts';

// ── Web: Create Request (Institution/Staff) ──
export const createRequest = asyncHandler(async (req: Request, res: Response) => {
    const { planId, studentId, studentInstitutionId } = req.body;
    const user = req.user;

    if (!planId || !studentId) {
        res.status(400).json({ message: "planId and studentId are required" });
        return;
    }

    const plan = await prisma.subscriptionPlan.findUnique({
        where: { id: planId, isActive: true, isDeleted: false }
    });

    if (!plan) {
        res.status(400).json({ message: "Plan not found or not available" });
        return;
    }

    const studentInstitution = await prisma.studentInstitution.findFirst({
        where: {
            id: studentInstitutionId || undefined,
            studentId: studentId,
            institutionId: user.institutionId
        },
        include: { student: true }
    });

    if (!studentInstitution) {
        res.status(400).json({ message: "Student not found in your institution" });
        return;
    }

    const existingProcessing = await prisma.subscriptionRequest.findFirst({
        where: { studentId, status: "PROCESSING" }
    });

    if (existingProcessing) {
        res.status(400).json({ message: "Student has a payment in progress" });
        return;
    }

    const existingPending = await prisma.subscriptionRequest.findFirst({
        where: { studentId, status: "PENDING" }
    });

    if (existingPending) {
        await prisma.subscriptionRequest.update({
            where: { id: existingPending.id },
            data: { status: "CANCELLED" }
        });
    }

    const finalAmount = Number(plan.priceAfterDiscount) + (Number(plan.priceAfterDiscount) * Number(plan.gstPercentage) / 100);
    const expiryDate = new Date();
    expiryDate.setDate(expiryDate.getDate() + 7);

    const request = await prisma.subscriptionRequest.create({
        data: {
            subscriptionPlanId: planId,
            studentId,
            studentInstitutionId: studentInstitution.id,
            institutionId: user.institutionId,
            createdById: user.id,
            amount: finalAmount,
            actualPrice: Number(plan.actualPrice),
            discountPercentage: Number(plan.discountPercentage),
            gstPercentage: Number(plan.gstPercentage),
            priceAfterDiscount: Number(plan.priceAfterDiscount),
            duration: plan.duration,
            planSnapshot: JSON.parse(JSON.stringify(plan)),
            expiryDate,
            status: "PENDING",
        },
        include: {
            student: { include: { user: true } },
            subscriptionPlan: true,
        }
    });

    res.status(201).json({
        message: "Subscription request created",
        data: {
            ...request,
            createdAt: toIST(request.createdAt),
            updatedAt: toIST(request.updatedAt),
        }
    });
});

// ── Web: List Requests (Institution/Staff) ──
export const listRequests = asyncHandler(async (req: Request, res: Response) => {
    const user = req.user;
    const search = (req.query.search as string)?.trim() || "";
    const status = req.query.status as string;
    const page = Number(req.query.page || 1);
    const limit = Number(req.query.limit || 10);
    const skip = (page - 1) * limit;

    const where: any = { institutionId: user.institutionId };

    if (status) where.status = status;

    if (search) {
        const searchWords = search.split(/\s+/).filter(Boolean);

        where.student = {
            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 [total, requests] = await Promise.all([
        prisma.subscriptionRequest.count({ where }),
        prisma.subscriptionRequest.findMany({
            where,
            include: {
                student: {
                    include: {
                        user: { select: { id: true, firstName: true, lastName: true, email: true, phone: true } }
                    }
                },
                subscriptionPlan: { select: { id: true, planName: true, planType: true, duration: true } },
                createdBy: { select: { id: true, firstName: true, lastName: true } },
                subscription: { select: { id: true, startDate: true, endDate: true } },
            },
            orderBy: { createdAt: 'desc' },
            skip,
            take: limit,
        }),
    ]);

    const data = requests.map((r) => ({
        ...r,
        createdAt: toIST(r.createdAt),
        updatedAt: toIST(r.updatedAt),
        expiryDate: r.expiryDate ? toIST(r.expiryDate) : null,
        paidAt: r.paidAt ? toIST(r.paidAt) : null,
    }));

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

// ── Web: Get Single Request ──
export const getRequest = asyncHandler(async (req: Request, res: Response) => {
    const { id } = req.params;
    const user = req.user;

    const request = await prisma.subscriptionRequest.findFirst({
        where: { id, institutionId: user.institutionId },
        include: {
            student: {
                include: {
                    user: { select: { id: true, firstName: true, lastName: true, email: true, phone: true } }
                }
            },
            subscriptionPlan: true,
            createdBy: { select: { id: true, firstName: true, lastName: true } },
            subscription: true,
        }
    });

    if (!request) {
        res.status(404).json({ message: "Request not found" });
        return;
    }

    res.status(200).json({
        data: {
            ...request,
            createdAt: toIST(request.createdAt),
            updatedAt: toIST(request.updatedAt),
            expiryDate: request.expiryDate ? toIST(request.expiryDate) : null,
            paidAt: request.paidAt ? toIST(request.paidAt) : null,
        }
    });
});

// ── Web: Cancel Request ──
export const cancelRequest = asyncHandler(async (req: Request, res: Response) => {
    const { id } = req.params;
    const user = req.user;

    const result = await prisma.subscriptionRequest.updateMany({
        where: { id, institutionId: user.institutionId, status: { in: ["PENDING"] } },
        data: { status: "CANCELLED" }
    });

    if (result.count === 0) {
        res.status(400).json({ message: "Request cannot be cancelled (already processed)" });
        return;
    }

    res.status(200).json({ message: "Request cancelled successfully" });
});

// ── Web: Bulk Validate Requests (Institution/Staff) ──
export const bulkValidate = asyncHandler(async (req: Request, res: Response) => {
    const { studentInstitutionIds, planId } = req.body;

    const validations = [
        {
            validate: () => !Array.isArray(studentInstitutionIds),
            message: "students must be an array",
        },
        {
            validate: () => studentInstitutionIds.length < 1,
            message: "students is required",
        },
        {
            validate: () => !planId,
            message: "planId is required",
        },
    ];

    for (const validation of validations) {
        if (validation.validate()) {
            res.status(400).json({ message: validation.message });
            return
        }
    }

    const plan = await prisma.subscriptionPlan.findUnique({
        where: { id: planId, isActive: true, isDeleted: false }
    });

    if (!plan) {
        res.status(404).json({ message: "Subscription plan not found" });
        return;
    }

    const studentInstitutions = await prisma.studentInstitution.findMany({
        where: {
            id: { in: studentInstitutionIds },
            deletedAt: null,
            isVerified: true
        },
        include: {
            student: {
                include: {
                    user: { select: { firstName: true, lastName: true, email: true } },
                }
            },
            subscriptions: {
                where: { isCurrent: true },
                include: {
                    plan: { select: { planName: true, duration: true, planType: true, priceAfterDiscount: true, gstPercentage: true } }
                }
            }
        }
    });

    const foundIds = studentInstitutions.map(si => si.id);
    const missingIds = studentInstitutionIds.filter((id: string) => !foundIds.includes(id));

    const processingRequests = await prisma.subscriptionRequest.findMany({
        where: {
            studentInstitutionId: { in: foundIds },
            status: "PROCESSING"
        }
    });

    const processingStudentIds = processingRequests.map(r => r.studentInstitutionId);

    const students = studentInstitutions
        .filter(si => !processingStudentIds.includes(si.id))
        .map(si => {
            const currentSub = si.subscriptions[0];
            return {
                studentId: si.studentId,
                studentInstitutionId: si.id,
                name: `${si.student.user.firstName} ${si.student.user.lastName}`,
                email: si.student.user.email,
                currentPlan: currentSub?.planId || "TRIAL",
                currentPlanName: currentSub?.plan?.planName || "TRIAL",
                currentPlanType: currentSub?.plan?.planType || "TRIAL",
                currentPlanStatus: currentSub?.status || "TRIAL",
            };
        });

    res.status(200).json({
        message: "Bulk validation complete",
        data: {
            planName: plan.planName,
            duration: plan.duration,
            priceAfterDiscount: Number(plan.priceAfterDiscount),
            gstPercentage: Number(plan.gstPercentage),
            totalEligible: students.length,
            totalSelected: studentInstitutionIds.length,
            students,
            skipped: {
                missingFromInstitution: missingIds,
                hasProcessingPayment: processingStudentIds,
            }
        }
    });
});

// ── Web: Bulk Send Requests (Institution/Staff) ──
export const bulkSend = asyncHandler(async (req: Request, res: Response) => {
    const { studentInstitutionIds, planId } = req.body;
    const user = req.user;

    const validations = [
        {
            validate: () => !Array.isArray(studentInstitutionIds),
            message: "students must be an array",
        },
        {
            validate: () => studentInstitutionIds.length < 1,
            message: "students is required",
        },
        {
            validate: () => !planId,
            message: "planId is required",
        },
    ];

    for (const validation of validations) {
        if (validation.validate()) {
            res.status(400).json({ message: validation.message });
            return
        }
    }

    const plan = await prisma.subscriptionPlan.findUnique({
        where: { id: planId, isActive: true, isDeleted: false, }
    });

    if (!plan) {
        res.status(404).json({ message: "Plan not found or not available" });
        return;
    }

    const studentInstitutions = await prisma.studentInstitution.findMany({
        where: {
            id: { in: studentInstitutionIds }
        }
    });

    const eligibleStudentInstitutionsIds = studentInstitutions.map(si => si.id);

    const processingRequests = await prisma.subscriptionRequest.findMany({
        where: {
            studentInstitutionId: { in: eligibleStudentInstitutionsIds },
            status: "PROCESSING"
        }
    });

    const processingStudentInstitutionIds = processingRequests.map(r => r.studentInstitutionId);
    const validStudentInstitutionIds = eligibleStudentInstitutionsIds.filter(id => !processingStudentInstitutionIds.includes(id));

    if (validStudentInstitutionIds.length === 0) {
        res.status(400).json({ message: "No eligible students to send requests" });
        return;
    }

    const existingPending = await prisma.subscriptionRequest.findMany({
        where: {
            studentInstitutionId: { in: validStudentInstitutionIds },
            status: "PENDING"
        }
    });

    if (existingPending.length > 0) {
        await prisma.subscriptionRequest.updateMany({
            where: { id: { in: existingPending.map(r => r.id) } },
            data: { status: "CANCELLED" }
        });
    }

    const finalAmount = Number(plan.priceAfterDiscount)
    // + (Number(plan.priceAfterDiscount) * Number(plan.gstPercentage) / 100);
    const expiryDate = new Date();
    expiryDate.setDate(expiryDate.getDate() + 3);

    const requests = await prisma.subscriptionRequest.createMany({
        data: validStudentInstitutionIds.map(studentInstitutionId => ({
            subscriptionPlanId: plan.id,
            studentId: studentInstitutions.find(s => s.id == studentInstitutionId)?.studentId,
            studentInstitutionId: studentInstitutionId,
            institutionId: user.institutionId,
            createdById: user.id,
            amount: finalAmount,
            actualPrice: Number(plan.actualPrice),
            discountPercentage: Number(plan.discountPercentage),
            gstPercentage: Number(plan.gstPercentage),
            priceAfterDiscount: Number(plan.priceAfterDiscount),
            duration: plan.duration,
            planSnapshot: JSON.parse(JSON.stringify(plan)),
            expiryDate,
            status: "PENDING",
        }))
    });
    
    try {
        const students = await prisma.studentInstitution.findMany({
            where: { id: { in: validStudentInstitutionIds } },
            select: {
                student: {
                    select: {
                        fcmToken: true
                    }
                }
            }
        })
        if (students.length > 0) {
            console.log(students)
            const tokens = students.map(s => s?.student?.fcmToken).filter((token): token is string => !!token);
            if (tokens.length > 0) {
                await sendNotification(
                    tokens,
                    "New Subscription Request Added",
                    "For Plan: " + plan.planName,
                    { type: "subscription_request" }
                );
            }
        }
    } catch (notifyError) {
        console.error("Failed to send push notifications:", notifyError);
    }
    res.status(201).json({
        message: "Bulk requests sent successfully",
        data: {
            totalSent: requests.count,
            planName: plan.planName,
        }
    });
});

// ── Student: Get My Requests ──
export const getMyRequests = asyncHandler(async (req: Request, res: Response) => {
    const user = req.user;
    const studentInstitution = await prisma.studentInstitution.findUnique({ where: { id: user.studentInstitutionId } });
    if (!studentInstitution) {
        res.status(404).json({ message: "Student not found" });
        return;
    }

    const request = await prisma.subscriptionRequest.findFirst({
        where: { studentInstitutionId: studentInstitution.id, status: "PENDING" },
        include: {
            subscriptionPlan: { select: { id: true, planName: true, planType: true, duration: true, features: true, description: true } },
            institution: {
                select: {
                    id: true,
                    user: { select: { institutionName: true } }
                }
            },
            subscription: { select: { id: true, startDate: true, endDate: true, status: true } },
        },
        orderBy: { createdAt: 'desc' },
    });
    const data = request ? {
        ...request,
        subscriptionRequestId: request.id,
        id:undefined,
        createdAt: toIST(request.createdAt),
        expiryDate: request.expiryDate ? toIST(request.expiryDate) : null,
        paidAt: request.paidAt ? toIST(request.paidAt) : null,
        institutionName: request.institution?.user?.institutionName || null,
        planSnapshot: null
    } : {};

    res.status(200).json({
        message: "Requests fetched successfully", data
    });
    return
});
