import type { Request, Response } from "express";
import asyncHandler from "express-async-handler";
import { prisma } from "../config/db.ts";
import { toIST } from "../utils/time.ts";

// Admin dashboard
export const getAdminStats = asyncHandler(async (req: Request, res: Response) => {
    // 1. Institution Base Counts
    const [
        totalInstitutions,
        activeInstitutions,
        inactiveInstitutions,
    ] = await Promise.all([
        prisma.user.count({ where: { role: "INSTITUTION", isDeleted: false } }),
        prisma.user.count({ where: { role: "INSTITUTION", isDeleted: false, isVerified: true } }),
        prisma.user.count({ where: { role: "INSTITUTION", isDeleted: false, isVerified: false } }),
    ]);

    // 2. Platform User Totals
    const [totalStudents, totalStaff] = await Promise.all([
        prisma.user.count({
            where: {
                role: "STUDENT",
                isDeleted: false,
                createdBy: { role: "INSTITUTION" }
            }
        }),
        prisma.user.count({
            where: {
                role: "STAFF",
                isDeleted: false,
                createdBy: { role: "INSTITUTION" }
            }
        }),
    ]);

    // 3. Recent 10 Institutions (Verified AND Pending/Unverified)
    const recentUsers = await prisma.user.findMany({
        where: {
            role: "INSTITUTION",
            isDeleted: false,
        },
        orderBy: { createdAt: "desc" },
        take: 10
    });

    const userIds = recentUsers.map(u => u.id);

    const institutions = await prisma.institution.findMany({
        where: {
            userId: { in: userIds }
        },
        include: {
            subscriptions: {
                where: { isCurrent: true },
                take: 1,
                include: {
                    plan: {
                        select: {
                            planName: true,
                            actualPrice: true,
                            planType: true
                        }
                    }
                }
            },
            students: {
                select: { id: true }
            },
            staffs: {
                where: { user: { isDeleted: false } },
                select: { id: true }
            }
        }
    });

    const instMap = new Map(institutions.map(inst => [inst.userId, inst]));

    const recentInstitutions = recentUsers.map((u) => {
        const inst = instMap.get(u.id);
        const currentSub = inst?.subscriptions?.[0] || null;

        return {
            id: inst?.id || u.id,
            userId: u.id,
            institutionName: u.institutionName || `${u.firstName || ''} ${u.lastName || ''}`.trim() || u.email,
            email: u.email,
            phone: u.phone,
            isVerified: u.isVerified ?? false,
            createdAt: toIST(u.createdAt),
            totalStudents: inst?.students?.length ?? 0,
            totalStaff: inst?.staffs?.length ?? 0,
            subscription: currentSub
                ? {
                      id: currentSub.id,
                      status: currentSub.status,
                      action: currentSub.action,
                      planName: currentSub.plan?.planName || "N/A",
                      planType: currentSub.plan?.planType || "N/A",
                      amount: currentSub.amount,
                      chargedAmount: currentSub.chargedAmount,
                      startDate: toIST(currentSub.startDate),
                      endDate: currentSub.endDate ? toIST(currentSub.endDate) : null,
                  }
                : null,
        };
    });

    // 4. Platform Registration Trend (Past 7 Days)
    const sevenDaysAgo = new Date();
    sevenDaysAgo.setDate(sevenDaysAgo.getDate() - 6);
    sevenDaysAgo.setHours(0, 0, 0, 0);

    const institutionUsers = await prisma.user.findMany({
        where: {
            role: "INSTITUTION",
            isDeleted: false,
            createdAt: { gte: sevenDaysAgo }
        },
        select: { createdAt: true }
    });

    const trendMap: Record<string, number> = {};
    for (let i = 0; i < 7; i++) {
        const d = new Date();
        d.setDate(d.getDate() - (6 - i));
        const dateStr = toIST(d, "YYYY-MM-DD");
        trendMap[dateStr] = 0;
    }

    institutionUsers.forEach((u) => {
        const dateStr = toIST(u.createdAt, "YYYY-MM-DD");
        if (trendMap[dateStr] !== undefined) {
            trendMap[dateStr] += 1;
        }
    });

    const platformRegistrationTrend = Object.entries(trendMap)
        .map(([date, count]) => ({ date, count }))
        .sort((a, b) => a.date.localeCompare(b.date));

    res.status(200).json({
        success: true,
        data: {
            role: "ADMIN",
            counts: {
                institutions: {
                    total: totalInstitutions,
                    verified: activeInstitutions,
                    unverified: inactiveInstitutions,
                },
                users: {
                    totalStudents,
                    totalStaff,
                    totalPlatformUsers: totalStudents + totalStaff,
                },
            },
            recentInstitutions,
            subscriptionDistribution: [],
            platformRegistrationTrend,
        },
    });
});

// Institution dashboard
export const getInstitutionStats = asyncHandler(async (req: Request, res: Response) => {
    const user = (req as any).user;
    const whereClause = { institutionId: user.institutionId };

    // Set up 7-day date
    const today = new Date();
    today.setHours(0, 0, 0, 0);

    const sevenDaysAgo = new Date(today);
    sevenDaysAgo.setDate(today.getDate() - 6);

    const dateMap: Record<string, { registeredCount: number; activeSubscriptionCount: number }> = {};
    for (let i = 0; i < 7; i++) {
        const d = new Date(sevenDaysAgo);
        d.setDate(sevenDaysAgo.getDate() + i);
        const dateKey = toIST(d, "YYYY-MM-DD");
        dateMap[dateKey] = { registeredCount: 0, activeSubscriptionCount: 0 };
    }

    // 1. 2. 3. Card stats count
    const [
        totalStudents,
        verifiedStudents,
        pendingStudents,
        paidStudents,
        expiredStudents,
        totalStaff,
        verifiedStaff,
        pendingStaff,
        totalQuestions,
        totalExams,
        totalSubjects,
        practiceTestsCount,
        mockTestsCount,
        pyqTestsCount,
        registeredStudentsRecent,
        subscriptionsRecent,
        totalRegisteredBefore,
        totalActiveSubscriptionsBefore
    ] = await Promise.all([
        prisma.studentInstitution.count({ where: { ...whereClause, deletedAt: null } }),

        prisma.studentInstitution.count({ where: { ...whereClause, deletedAt: null, isVerified: true } }),
        prisma.studentInstitution.count({ where: { ...whereClause, deletedAt: null, isVerified: false } }),

        prisma.studentInstitution.count({
            where: {
                ...whereClause,
                deletedAt: null,
                subscriptions: { some: { status: "ACTIVE", isCurrent: true } }
            }
        }),

        prisma.studentInstitution.count({
            where: {
                ...whereClause,
                deletedAt: null,
                subscriptions: { some: { status: "EXPIRED", isCurrent: true } }
            }
        }),

        prisma.staff.count({ where: { ...whereClause, user: { isDeleted: false } } }),
        prisma.staff.count({ where: { ...whereClause, user: { isDeleted: false, isVerified: true } } }),
        prisma.staff.count({ where: { ...whereClause, user: { isDeleted: false, isVerified: false } } }),

        prisma.questionBank.count({ where: whereClause }),
        prisma.exam.count({ where: whereClause }),
        prisma.subject.count({ where: whereClause }),

        prisma.practiceTest.count({ where: whereClause }),
        prisma.mockTest.count({ where: whereClause }),
        prisma.oldQuestionPaper.count({ where: whereClause }),

        // Registered students in last 7 days
        prisma.studentInstitution.findMany({
            where: {
                ...whereClause,
                deletedAt: null,
                createdAt: { gte: sevenDaysAgo }
            },
            select: { createdAt: true }
        }),

        // Active subscriptions created in last 7 days
        prisma.subscription.findMany({
            where: {
                studentInstitution: {
                    institutionId: user.institutionId,
                    deletedAt: null
                },
                status: "ACTIVE",
                isCurrent: true,
                createdAt: { gte: sevenDaysAgo }
            },
            select: { createdAt: true }
        }),

        // Baseline counts prior to 7 days
        prisma.studentInstitution.count({
            where: {
                ...whereClause,
                deletedAt: null,
                createdAt: { lt: sevenDaysAgo }
            }
        }),

        // Subscriptions baseline prior to 7 days
        prisma.subscription.count({
            where: {
                studentInstitution: {
                    institutionId: user.institutionId,
                    deletedAt: null
                },
                status: "ACTIVE",
                isCurrent: true,
                createdAt: { lt: sevenDaysAgo }
            }
        })
    ]);

    registeredStudentsRecent.forEach(student => {
        const dateStr = toIST(student.createdAt, "YYYY-MM-DD");
        if (dateMap[dateStr]) {
            dateMap[dateStr].registeredCount += 1;
        }
    });

    subscriptionsRecent.forEach(sub => {
        const dateStr = toIST(sub.createdAt, "YYYY-MM-DD");
        if (dateMap[dateStr]) {
            dateMap[dateStr].activeSubscriptionCount += 1;
        }
    });

    let cumulativeRegistered = totalRegisteredBefore;
    let cumulativeSubscriptions = totalActiveSubscriptionsBefore;

    const studentSubscriptionTrend = Object.entries(dateMap)
        .sort(([dateA], [dateB]) => dateA.localeCompare(dateB))
        .map(([date, counts]) => {
            cumulativeRegistered += counts.registeredCount;
            cumulativeSubscriptions += counts.activeSubscriptionCount;

            return {
                date,
                registeredCount: cumulativeRegistered,
                activeSubscriptionCount: cumulativeSubscriptions,
                newRegistrations: counts.registeredCount,
                newSubscriptions: counts.activeSubscriptionCount
            };
        });

    // 4. Submission Trend (7 Days)
    const trendResults = await prisma.examResult.findMany({
        where: {
            createdAt: { gte: sevenDaysAgo },
            ...whereClause
        },
        select: { createdAt: true }
    });

    const trendMap: Record<string, number> = {};
    trendResults.forEach(r => {
        const dateStr = toIST(r.createdAt, "YYYY-MM-DD");
        trendMap[dateStr] = (trendMap[dateStr] || 0) + 1;
    });

    const trend = Object.entries(trendMap)
        .map(([date, count]) => ({ date, count }))
        .sort((a, b) => a.date.localeCompare(b.date));

    // 5. Questions by Subject
    const qBySubjectRaw = await prisma.questionBank.groupBy({
        by: ['subjectId'],
        where: whereClause,
        _count: { id: true },
        orderBy: { _count: { id: 'desc' } },
        take: 6
    });

    const subjectIds = qBySubjectRaw.map(q => q.subjectId);
    const subjects = await prisma.subject.findMany({
        where: { id: { in: subjectIds } },
        select: { id: true, subjectName: true }
    });

    const questionsBySubject = qBySubjectRaw.map(q => {
        const s = subjects.find(sub => sub.id === q.subjectId);
        return {
            id: s?.id || "",
            subjectName: s?.subjectName || "Unknown",
            count: q._count.id
        };
    });

    // 6. Recent Results (Combined Practice, PYQ, and Mock Results)
    const [recentExamResultsRaw, recentMockResultsRaw] = await Promise.all([
        prisma.examResult.findMany({
            where: whereClause,
            include: {
                practiceTest: { select: { title: true, id: true, exam: { select: { examName: true } } } },
                oldQuestionPaper: { select: { title: true, id: true, exam: { select: { examName: true } } } },
                studentInstitution: {
                    select: {
                        student: { include: { user: { select: { firstName: true, lastName: true, email: true } } } }
                    }
                }
            },
            orderBy: { createdAt: 'desc' },
            take: 10
        }),
        prisma.mockTestResult.findMany({
            where: { studentInstitution: { institutionId: user.institutionId } },
            include: {
                mockTest: { select: { title: true, id: true, exam: { select: { examName: true } } } },
                studentInstitution: {
                    select: {
                        student: { include: { user: { select: { firstName: true, lastName: true, email: true } } } }
                    }
                }
            },
            orderBy: { createdAt: 'desc' },
            take: 10
        })
    ]);

    // Map Exam Results (Practice & OQP)
    const mappedExamResults = recentExamResultsRaw.map(r => {
        const resultStudent = r.studentInstitution?.student;
        return {
            ...r,
            createdAt: toIST(r.createdAt),
            updatedAt: toIST(r.updatedAt),
            testId: r.practiceTest
                ? { id: r.practiceTest.id, title: r.practiceTest.title }
                : { id: r.oldQuestionPaper?.id, title: r.oldQuestionPaper?.title || null },
            examName: r.practiceTest ? r.practiceTest.exam.examName : r.oldQuestionPaper?.exam.examName || "Unknown Exam",
            examType: r.practiceTest ? "PRACTICE" : "OQP",
            studentId: resultStudent?.user ? {
                id: resultStudent.userId,
                firstName: resultStudent.user.firstName,
                lastName: resultStudent.user.lastName,
                email: resultStudent.user.email
            } : null
        };
    });

    // Map Mock Results
    const mappedMockResults = recentMockResultsRaw.map(r => {
        const resultStudent = r.studentInstitution?.student;
        return {
            ...r,
            createdAt: toIST(r.createdAt),
            updatedAt: toIST(r.updatedAt),
            testId: r.mockTest ? { id: r.mockTest.id, title: r.mockTest.title } : { id: null, title: null },
            examName: r.mockTest?.exam?.examName || "Unknown Exam",
            examType: "MOCK",
            studentId: resultStudent?.user ? {
                id: resultStudent.userId,
                firstName: resultStudent.user.firstName,
                lastName: resultStudent.user.lastName,
                email: resultStudent.user.email
            } : null
        };
    });

    const recentResults = [...mappedExamResults, ...mappedMockResults]
        .sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime())
        .slice(0, 10);

    // Response Payload
    res.status(200).json({
        success: true,
        data: {
            role: user.role,
            counts: {
                students: {
                    total: totalStudents,
                    verified: verifiedStudents,
                    pending: pendingStudents,
                    paid: paidStudents,
                    expired: expiredStudents
                },
                staff: {
                    total: totalStaff,
                    verified: verifiedStaff,
                    pending: pendingStaff
                },
                questions: totalQuestions,
                tests: {
                    total: practiceTestsCount + mockTestsCount + pyqTestsCount,
                    practiceTest: practiceTestsCount,
                    mockTest: mockTestsCount,
                    pyqTest: pyqTestsCount
                },
                exams: totalExams,
                subjects: totalSubjects,
            },
            studentSubscriptionTrend,
            recentResults,
            questionsBySubject,
            trend
        },
    });
});

// Staff dashboard
export const getStaffStats = asyncHandler(async (req: Request, res: Response) => {
    const user = (req as any).user;
    const userId = user.id;

    const staffUser = await prisma.user.findUnique({
        where: { id: userId },
        select: { createdById: true }
    });

    if (!staffUser || !staffUser.createdById) {
        res.status(404).json({ message: "Staff owner not found" });
        return;
    }

    const ownerId = staffUser.createdById;

    // System-wide stats for this institution
    const [totalQuestions, totalTests] = await Promise.all([
        prisma.questionBank.count({
            where: {
                institutionId: user.institutionId
            }
        }),
        prisma.practiceTest.count({
            where: {
                institutionId: user.institutionId
            }
        })
    ]);

    // Personal stats
    const [myQuestionsCount, myTestsCount] = await Promise.all([
        prisma.questionBank.count({ where: { createdById: userId } }),
        prisma.practiceTest.count({ where: { createdById: userId } })
    ]);

    // Staff assignment
    const staffDetails = await prisma.staff.findUnique({
        where: { userId },
        include: {
            subjects: { select: { id: true, subjectName: true } },
        }
    });

    const assignedSubjects = staffDetails?.subjects || [];
    const assignedSubjectIds = assignedSubjects.map(s => s.id);

    // Subject-wise Question Count (ONLY assigned subjects)
    const qBySubjectRaw = await prisma.questionBank.groupBy({
        by: ['subjectId'],
        where: {
            createdById: userId,
            subjectId: { in: assignedSubjectIds }
        },
        _count: { id: true },
        orderBy: { _count: { id: 'desc' } }
    });

    const questionsBySubject = qBySubjectRaw.map(q => {
        const s = assignedSubjects.find(sub => sub.id === q.subjectId);
        return {
            id: q.subjectId,
            subjectName: s?.subjectName || "Unknown",
            count: q._count.id
        };
    });

    res.status(200).json({
        success: true,
        data: {
            role: "Staff",
            counts: {
                totalQuestions,
                totalTests,
                myQuestions: myQuestionsCount,
                myTests: myTestsCount,
                assignedSubjects: assignedSubjects.length,
            },
            assigned: {
                subjects: assignedSubjects,
            },
            questionsBySubject,
        },
    });
});
