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


// Helper: Find or Create Exam in Target Institution
async function getOrCreateTargetExam(tx: any, sourceExamId: string | null | undefined, targetInstId: string) {
    if (!sourceExamId) return null;

    const sourceExam = await tx.exam.findUnique({
        where: { id: sourceExamId },
    });

    if (!sourceExam) return null;

    const existingTargetExam = await tx.exam.findFirst({
        where: {
            examName: { equals: sourceExam.examName.trim() },
            institutionId: targetInstId,
        },
    });

    if (existingTargetExam) {
        return existingTargetExam.id;
    }

    const newExam = await tx.exam.create({
        data: {
            examName: sourceExam.examName,
            institutionId: targetInstId,
        },
    });

    return newExam.id;
}

// Get Available Resources 
export const getAvailableResources = asyncHandler(async (req: Request, res: Response) => {
    const { institutionId, resourceType, search, page = "1", limit = "10", targetInstitutionId, sharedStatus, subjectId, examId, year } = req.query;

    if (!institutionId || !resourceType) {
        res.status(400).json({ success: false, message: "Missing required fields" });
        return;
    }

    const pageNum = parseInt(page as string) || 1;
    const limitNum = parseInt(limit as string) || 10;
    const skip = (pageNum - 1) * limitNum;

    const institutionRecord = await prisma.institution.findFirst({
        where: { userId: institutionId as string },
        select: { id: true },
    });
    const resolvedInstitutionId = institutionRecord?.id ?? (institutionId as string);

    let data = [];
    let total = 0;
    let stats: any = undefined;

    const searchQuery = search ? {
        title: { contains: search as string }
    } : {};

    let resolvedTargetInstId: string | null = null;
    if (targetInstitutionId) {
        const targetRec = await prisma.institution.findFirst({ where: { userId: targetInstitutionId as string }, select: { id: true } });
        resolvedTargetInstId = targetRec?.id ?? (targetInstitutionId as string);
    }

    if (resourceType === "TEST") {
        const whereClause: any = { institutionId: resolvedInstitutionId, referenceSourceId: null, ...searchQuery };
        if (subjectId) {
            whereClause.subjectId = subjectId as string;
        }
        if (resolvedTargetInstId && sharedStatus) {
            if (sharedStatus === 'SHARED') {
                whereClause.sharedCopies = { some: { institutionId: resolvedTargetInstId } };
            } else if (sharedStatus === 'NOT_SHARED') {
                whereClause.sharedCopies = { none: { institutionId: resolvedTargetInstId } };
            }
        }
        const [tests, count] = await Promise.all([
            prisma.test.findMany({
                where: whereClause,
                skip,
                take: limitNum,
                include: { subject: true, _count: { select: { testQuestions: true } } },
                orderBy: { createdAt: "desc" },
            }),
            prisma.test.count({ where: whereClause }),
        ]);
        if (resolvedTargetInstId) {
            const processedResources = [] as any[];
            for (const t of tests) {
                const shared = await prisma.test.findFirst({ where: { referenceSourceId: t.id, institutionId: resolvedTargetInstId } });
                let isRemovable = false;
                if (shared) {
                    const mappedPracticeTests = await prisma.practiceTest.findMany({ where: { testId: shared.id, institutionId: resolvedTargetInstId }, select: { id: true } });
                    if (mappedPracticeTests.length === 0) {
                        isRemovable = true;
                    } else {
                        const practiceIds = mappedPracticeTests.map(p => p.id);
                        const resultsCount = await prisma.examResult.count({ where: { practiceTestId: { in: practiceIds } } });
                        if (resultsCount === 0) isRemovable = true;
                    }
                }

                processedResources.push({
                    ...t,
                    isShared: !!shared,
                    sharedId: shared?.id || null,
                    isRemovable,
                });
            }
            data = processedResources;
        } else {
            data = tests;
        }
        total = count;

        if (resolvedTargetInstId) {
            const [totalCount, sharedCount, availableCount] = await Promise.all([
                prisma.test.count({
                    where: {
                        institutionId: resolvedInstitutionId,
                        referenceSourceId: null,
                        subjectId: subjectId ? (subjectId as string) : undefined
                    }
                }),
                prisma.test.count({
                    where: {
                        institutionId: resolvedInstitutionId,
                        referenceSourceId: null,
                        subjectId: subjectId ? (subjectId as string) : undefined,
                        sharedCopies: {
                            some: {
                                institutionId: resolvedTargetInstId
                            }
                        }
                    }
                }),
                prisma.test.count({
                    where: {
                        institutionId: resolvedInstitutionId,
                        referenceSourceId: null,
                        subjectId: subjectId ? (subjectId as string) : undefined,
                        sharedCopies: {
                            none: {
                                institutionId: resolvedTargetInstId
                            }
                        }
                    }
                })
            ]);
            stats = {
                totalCount,
                sharedCount,
                availableCount
            };
        } else {
            const totalCount = await prisma.test.count({
                where: {
                    institutionId: resolvedInstitutionId,
                    referenceSourceId: null,
                    subjectId: subjectId ? (subjectId as string) : undefined
                }
            });
            stats = {
                totalCount,
                sharedCount: 0,
                availableCount: totalCount
            };
        }
    } else if (resourceType === "PYQ") {
        const whereClause: any = { institutionId: resolvedInstitutionId, referenceSourceId: null, questions: { some: {} }, ...searchQuery };
        if (examId) {
            whereClause.examId = examId as string;
        }
        if (year) {
            whereClause.year = String(year);
        }
        if (resolvedTargetInstId && sharedStatus) {
            if (sharedStatus === 'SHARED') {
                whereClause.sharedCopies = { some: { institutionId: resolvedTargetInstId } };
            } else if (sharedStatus === 'NOT_SHARED') {
                whereClause.sharedCopies = { none: { institutionId: resolvedTargetInstId } };
            }
        }
        const [pyqs, count] = await Promise.all([
            prisma.oldQuestionPaper.findMany({
                where: whereClause,
                skip,
                take: limitNum,
                include: { _count: { select: { questions: true } }, exam: true },
                orderBy: { createdAt: "desc" },
            }),
            prisma.oldQuestionPaper.count({ where: whereClause }),
        ]);
        if (resolvedTargetInstId) {
            const processedResources = [] as any[];
            for (const p of pyqs) {
                const shared = await prisma.oldQuestionPaper.findFirst({ where: { referenceSourceId: p.id, institutionId: resolvedTargetInstId } });
                let isRemovable = false;
                if (shared) {
                    const resultsCount = await prisma.examResult.count({ where: { oldQuestionPaperId: shared.id, institutionId: resolvedTargetInstId } });
                    isRemovable = resultsCount === 0;
                }
                processedResources.push({ ...p, isShared: !!shared, sharedId: shared?.id || null, isRemovable });
            }
            data = processedResources;
        } else {
            data = pyqs;
        }
        total = count;

        if (resolvedTargetInstId) {
            const [totalCount, sharedCount, availableCount] = await Promise.all([
                prisma.oldQuestionPaper.count({
                    where: {
                        institutionId: resolvedInstitutionId,
                        referenceSourceId: null,
                        questions: { some: {} },
                        examId: examId ? (examId as string) : undefined,
                        year: year ? String(year) : undefined
                    }
                }),
                prisma.oldQuestionPaper.count({
                    where: {
                        institutionId: resolvedInstitutionId,
                        referenceSourceId: null,
                        questions: { some: {} },
                        examId: examId ? (examId as string) : undefined,
                        year: year ? String(year) : undefined,
                        sharedCopies: {
                            some: {
                                institutionId: resolvedTargetInstId
                            }
                        }
                    }
                }),
                prisma.oldQuestionPaper.count({
                    where: {
                        institutionId: resolvedInstitutionId,
                        referenceSourceId: null,
                        questions: { some: {} },
                        examId: examId ? (examId as string) : undefined,
                        year: year ? String(year) : undefined,
                        sharedCopies: {
                            none: {
                                institutionId: resolvedTargetInstId
                            }
                        }
                    }
                })
            ]);
            stats = {
                totalCount,
                sharedCount,
                availableCount
            };
        } else {
            const totalCount = await prisma.oldQuestionPaper.count({
                where: {
                    institutionId: resolvedInstitutionId,
                    referenceSourceId: null,
                    questions: { some: {} },
                    examId: examId ? (examId as string) : undefined,
                    year: year ? String(year) : undefined
                }
            });
            stats = {
                totalCount,
                sharedCount: 0,
                availableCount: totalCount
            };
        }

    } else if (resourceType === "MOCK_TEST") {
        const whereClause: any = { institutionId: resolvedInstitutionId, referenceSourceId: null, ...searchQuery };
        if (examId) {
            whereClause.examId = examId as string;
        }
        if (resolvedTargetInstId && sharedStatus) {
            if (sharedStatus === 'SHARED') {
                whereClause.sharedCopies = { some: { institutionId: resolvedTargetInstId } };
            } else if (sharedStatus === 'NOT_SHARED') {
                whereClause.sharedCopies = { none: { institutionId: resolvedTargetInstId } };
            }
        }
        const [mocks, count] = await Promise.all([
            prisma.mockTest.findMany({
                where: whereClause,
                skip,
                take: limitNum,
                include: { exam: true },
                orderBy: { createdAt: "desc" },
            }),
            prisma.mockTest.count({ where: whereClause }),
        ]);
        if (resolvedTargetInstId) {
            const processedResources = [] as any[];
            for (const m of mocks) {
                const shared = await prisma.mockTest.findFirst({ where: { referenceSourceId: m.id, institutionId: resolvedTargetInstId } });
                let isRemovable = false;
                if (shared) {
                    const resultsCount = await prisma.mockTestResult.count({ where: { mockTestId: shared.id } });
                    isRemovable = resultsCount === 0;
                }
                console.log(`Mock Test ${m.id} shared status:`, !!shared, shared?.id);
                processedResources.push({ ...m, isShared: !!shared, sharedId: shared?.id || null, isRemovable });
            }
            data = processedResources;
        } else {
            data = mocks;
        }
        total = count;

        if (resolvedTargetInstId) {
            const [totalCount, sharedCount, availableCount] = await Promise.all([
                prisma.mockTest.count({
                    where: {
                        institutionId: resolvedInstitutionId,
                        referenceSourceId: null,
                        examId: examId ? (examId as string) : undefined
                    }
                }),
                prisma.mockTest.count({
                    where: {
                        institutionId: resolvedInstitutionId,
                        referenceSourceId: null,
                        examId: examId ? (examId as string) : undefined,
                        sharedCopies: {
                            some: {
                                institutionId: resolvedTargetInstId
                            }
                        }
                    }
                }),
                prisma.mockTest.count({
                    where: {
                        institutionId: resolvedInstitutionId,
                        referenceSourceId: null,
                        examId: examId ? (examId as string) : undefined,
                        sharedCopies: {
                            none: {
                                institutionId: resolvedTargetInstId
                            }
                        }
                    }
                })
            ]);
            stats = {
                totalCount,
                sharedCount,
                availableCount
            };
        } else {
            const totalCount = await prisma.mockTest.count({
                where: {
                    institutionId: resolvedInstitutionId,
                    referenceSourceId: null,
                    examId: examId ? (examId as string) : undefined
                }
            });
            stats = {
                totalCount,
                sharedCount: 0,
                availableCount: totalCount
            };
        }


    } else {
        res.status(400).json({ success: false, message: "Invalid resource type" });
        return;
    }

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

// Helpers for Share Resource
async function shareTestToInstitution(tx: any, resourceId: string, resolvedSourceInstId: string, targetInstId: string, user: any) {
    const sourceTest: any = await tx.test.findFirst({
        where: { id: resourceId, institutionId: resolvedSourceInstId },
        include: {
            testQuestions: { include: { question: true } },
        },
    });

    if (!sourceTest) throw new Error("Test not found");
    if (sourceTest.referenceSourceId) throw new Error("Cannot share a resource that was shared with you");

    const alreadyShared = await tx.test.findFirst({
        where: {
            referenceSourceId: sourceTest.id,
            institutionId: targetInstId,
        },
    });
    if (alreadyShared) throw new Error("Resource already shared");

    const targetSubjectId = sourceTest.subjectId;

    const testPayload: any = {
        title: sourceTest.title,
        subjectId: targetSubjectId,
        duration: sourceTest.duration,
        institutionId: targetInstId,
        createdById: user.id,
        referenceSourceId: sourceTest.id,
        referenceInstitutionId: resolvedSourceInstId,
        topic: sourceTest.topic,
        language: sourceTest.language,
        publish: false,
    };

    if (sourceTest.marks !== undefined) testPayload.marks = sourceTest.marks;
    if (sourceTest.difficulty !== undefined) testPayload.difficulty = sourceTest.difficulty;

    const newTest = await tx.test.create({
        data: testPayload,
    });

    return newTest;
}

async function sharePYQToInstitution(tx: any, resourceId: string, resolvedSourceInstId: string, targetInstId: string, user: any) {
    const sourcePYQ: any = await tx.oldQuestionPaper.findFirst({
        where: { id: resourceId, institutionId: resolvedSourceInstId },
        include: {
            questions: true,
            exam: true,
        },
    });

    if (!sourcePYQ) throw new Error("PYQ / Old Question Paper not found");
    if (sourcePYQ.referenceSourceId) throw new Error("Cannot share a resource that was shared with you");

    const alreadyShared = await tx.oldQuestionPaper.findFirst({
        where: {
            referenceSourceId: sourcePYQ.id,
            institutionId: targetInstId,
        },
    });
    if (alreadyShared) throw new Error("Resource already shared");

    const targetExamId = await getOrCreateTargetExam(tx, sourcePYQ.examId, targetInstId) || sourcePYQ.examId;

    const pyqPayload: any = {
        title: sourcePYQ.title,
        examId: targetExamId,
        year: sourcePYQ.year,
        language: sourcePYQ.language,
        duration: sourcePYQ.duration,
        marks: sourcePYQ.marks,
        difficulty: sourcePYQ.difficulty,
        publish: false,
        createdById: user.id,
        institutionId: targetInstId,
        referenceSourceId: sourcePYQ.id,
        referenceInstitutionId: resolvedSourceInstId,
    };

    const newPYQ = await tx.oldQuestionPaper.create({
        data: pyqPayload,
    });

    return newPYQ;
}

async function shareMockTestToInstitution(tx: any, resourceId: string, resolvedSourceInstId: string, targetInstId: string, user: any) {
    const sourceMock: any = await tx.mockTest.findFirst({
        where: { id: resourceId, institutionId: resolvedSourceInstId },
        include: {
            questions: { include: { question: true } },
            exam: true,
        },
    });

    if (!sourceMock) throw new Error("Mock Test not found");
    if (sourceMock.referenceSourceId) throw new Error("Cannot share a resource that was shared with you");

    const alreadyShared = await tx.mockTest.findFirst({
        where: {
            referenceSourceId: sourceMock.id,
            institutionId: targetInstId,
        },
    });
    if (alreadyShared) throw new Error("Resource already shared");

    const targetExamId = await getOrCreateTargetExam(tx, sourceMock.examId, targetInstId) || sourceMock.examId;

    const newMock = await tx.mockTest.create({
        data: {
            title: sourceMock.title,
            examId: targetExamId,
            language: sourceMock.language,
            duration: sourceMock.duration,
            totalMarks: sourceMock.totalMarks,
            questionCount: sourceMock.questionCount,
            generationMode: sourceMock.generationMode,
            publish: false,
            createdById: user.id,
            institutionId: targetInstId,
            referenceSourceId: sourceMock.id,
            referenceInstitutionId: resolvedSourceInstId,
        },
    });


    return newMock;
}

// Share Mock Test to Institution
export const shareMockTest = asyncHandler(async (req: Request, res: Response) => {
    const user = (req as any).user;
    const { resourceIds, sourceInstitutionId, targetInstitutionIds } = req.body;

    if (!resourceIds || !Array.isArray(resourceIds) || resourceIds.length === 0) {
        res.status(400).json({ success: false, message: "resourceIds is required" });
        return;
    }

    if (!sourceInstitutionId) {
        res.status(400).json({ success: false, message: "sourceInstitutionId is required" });
        return;
    }

    if (!targetInstitutionIds || !Array.isArray(targetInstitutionIds) || targetInstitutionIds.length === 0) {
        res.status(400).json({ success: false, message: "targetInstitutionIds array is required" });
        return;
    }

    if (targetInstitutionIds.length > 1) {
        res.status(400).json({ success: false, message: "Only one institution can be selected per sharing request" });
        return;
    }

    const shareResults: Array<{ resourceId: string; institutionId: string; sharedId: string }> = [];

    const sourceInstRecord = await prisma.institution.findFirst({
        where: { userId: sourceInstitutionId },
        select: { id: true },
    });
    const resolvedSourceInstId = sourceInstRecord?.id ?? sourceInstitutionId;

    const resolvedTargetInstIds: string[] = [];
    for (const userId of targetInstitutionIds) {
        const rec = await prisma.institution.findFirst({
            where: { userId },
            select: { id: true },
        });
        if (rec?.id) resolvedTargetInstIds.push(rec.id);
    }

    for (const resourceId of resourceIds) {
        for (const targetInstId of resolvedTargetInstIds) {
            if (targetInstId === resolvedSourceInstId) continue;

            try {
                const sharedResult = await prisma.$transaction(async (tx) => {
                    return await shareMockTestToInstitution(tx, resourceId, resolvedSourceInstId, targetInstId, user);
                });

                if (sharedResult) {
                    shareResults.push({
                        resourceId,
                        institutionId: targetInstId,
                        sharedId: sharedResult.id,
                    });
                }
            } catch (err: any) {
                console.error(`Error sharing MockTest ${resourceId} for institution ${targetInstId}:`, err.message);
                res.status(400).json({ success: false, message: err.message });
                return;
            }
        }
    }

    res.status(201).json({
        success: true,
        message: "Mock Tests shared successfully",
        data: shareResults,
    });
});

// Share Test to Institution
export const shareTest = asyncHandler(async (req: Request, res: Response) => {
    const user = (req as any).user;
    const { resourceIds, sourceInstitutionId, targetInstitutionIds } = req.body;

    if (!resourceIds || !Array.isArray(resourceIds) || resourceIds.length === 0) {
        res.status(400).json({ success: false, message: "resourceIds is required" });
        return;
    }

    if (!sourceInstitutionId) {
        res.status(400).json({ success: false, message: "sourceInstitutionId is required" });
        return;
    }

    if (!targetInstitutionIds || !Array.isArray(targetInstitutionIds) || targetInstitutionIds.length === 0) {
        res.status(400).json({ success: false, message: "targetInstitutionIds array is required" });
        return;
    }

    if (targetInstitutionIds.length > 1) {
        res.status(400).json({ success: false, message: "Only one institution can be selected per sharing request" });
        return;
    }

    const shareResults: Array<{ resourceId: string; institutionId: string; sharedId: string }> = [];

    const sourceInstRecord = await prisma.institution.findFirst({
        where: { userId: sourceInstitutionId },
        select: { id: true },
    });
    const resolvedSourceInstId = sourceInstRecord?.id ?? sourceInstitutionId;

    const resolvedTargetInstIds: string[] = [];
    for (const userId of targetInstitutionIds) {
        const rec = await prisma.institution.findFirst({
            where: { userId },
            select: { id: true },
        });
        if (rec?.id) resolvedTargetInstIds.push(rec.id);
    }

    for (const resourceId of resourceIds) {
        for (const targetInstId of resolvedTargetInstIds) {
            if (targetInstId === resolvedSourceInstId) continue;

            try {
                const sharedResult = await prisma.$transaction(async (tx) => {
                    return await shareTestToInstitution(tx, resourceId, resolvedSourceInstId, targetInstId, user);
                });

                if (sharedResult) {
                    shareResults.push({
                        resourceId,
                        institutionId: targetInstId,
                        sharedId: sharedResult.id,
                    });
                }
            } catch (err: any) {
                console.error(`Error sharing TEST ${resourceId} for institution ${targetInstId}:`, err.message);
                res.status(400).json({ success: false, message: err.message });
                return;
            }
        }
    }

    res.status(201).json({
        success: true,
        message: "Tests shared successfully",
        data: shareResults,
    });
});

// Share PYQs to Institution
export const sharePYQ = asyncHandler(async (req: Request, res: Response) => {
    const user = (req as any).user;
    const { resourceIds, sourceInstitutionId, targetInstitutionIds } = req.body;

    if (!resourceIds || !Array.isArray(resourceIds) || resourceIds.length === 0) {
        res.status(400).json({ success: false, message: "resourceIds is required" });
        return;
    }

    if (!sourceInstitutionId) {
        res.status(400).json({ success: false, message: "sourceInstitutionId is required" });
        return;
    }

    if (!targetInstitutionIds || !Array.isArray(targetInstitutionIds) || targetInstitutionIds.length === 0) {
        res.status(400).json({ success: false, message: "targetInstitutionIds array is required" });
        return;
    }

    if (targetInstitutionIds.length > 1) {
        res.status(400).json({ success: false, message: "Only one institution can be selected per sharing request" });
        return;
    }

    const shareResults: Array<{ resourceId: string; institutionId: string; sharedId: string }> = [];

    const sourceInstRecord = await prisma.institution.findFirst({
        where: { userId: sourceInstitutionId },
        select: { id: true },
    });
    const resolvedSourceInstId = sourceInstRecord?.id ?? sourceInstitutionId;

    const resolvedTargetInstIds: string[] = [];
    for (const userId of targetInstitutionIds) {
        const rec = await prisma.institution.findFirst({
            where: { userId },
            select: { id: true },
        });
        if (rec?.id) resolvedTargetInstIds.push(rec.id);
    }

    for (const resourceId of resourceIds) {
        for (const targetInstId of resolvedTargetInstIds) {
            if (targetInstId === resolvedSourceInstId) continue;

            try {
                const sharedResult = await prisma.$transaction(async (tx) => {
                    return await sharePYQToInstitution(tx, resourceId, resolvedSourceInstId, targetInstId, user);
                });

                if (sharedResult) {
                    shareResults.push({
                        resourceId,
                        institutionId: targetInstId,
                        sharedId: sharedResult.id,
                    });
                }
            } catch (err: any) {
                console.error(`Error sharing PYQ ${resourceId} for institution ${targetInstId}:`, err.message);
                res.status(400).json({ success: false, message: err.message });
                return;
            }
        }
    }

    res.status(201).json({
        success: true,
        message: "PYQs shared successfully",
        data: shareResults,
    });
});

// Remove shared resource share
export const removeSharedResource = asyncHandler(async (req: Request, res: Response) => {
    const { resourceType, sharedId } = req.body;

    if (!resourceType || !["TEST", "PYQ", "MOCK_TEST"].includes(resourceType)) {
        res.status(400).json({ success: false, message: "Valid resourceType ('TEST', 'PYQ', or 'MOCK_TEST') is required" });
        return;
    }

    if (!sharedId) {
        res.status(400).json({ success: false, message: "Missing required fields" });
        return;
    }

    let record;
    if (resourceType === "TEST") {
        record = await prisma.test.findUnique({ where: { id: sharedId } });
    } else if (resourceType === "PYQ") {
        record = await prisma.oldQuestionPaper.findUnique({ where: { id: sharedId } });
    } else if (resourceType === "MOCK_TEST") {
        record = await prisma.mockTest.findUnique({ where: { id: sharedId } });
    } else {
        record = await prisma.questionBank.findUnique({ where: { id: sharedId } });
    }

    if (!record || !record.referenceSourceId) {
        res.status(404).json({ success: false, message: "Resource not found" });
        return;
    }

    if (resourceType === "TEST") {
        const sharedTest = await prisma.test.findUnique({
            where: { id: sharedId },
            select: { subjectId: true, testQuestions: { select: { questionId: true } } },
        });

        if (!sharedTest) {
            res.status(404).json({ success: false, message: "Resource not found" });
            return;
        }

        const practiceTests = await prisma.practiceTest.findMany({ where: { testId: sharedId }, select: { id: true } });
        const practiceTestIds = practiceTests.map((pt) => pt.id);

        await prisma.$transaction(async (tx) => {
            if (practiceTestIds.length > 0) {
                await tx.examResult.deleteMany({ where: { practiceTestId: { in: practiceTestIds } } });
                await tx.practiceTest.deleteMany({ where: { id: { in: practiceTestIds } } });
            }

            await tx.testQuestion.deleteMany({ where: { testId: sharedId } });
            await tx.test.delete({ where: { id: sharedId } });

            const subjectUsage = await tx.subject.count({
                where: {
                    id: sharedTest.subjectId,
                    OR: [
                        { tests: { some: {} } },
                        { questions: { some: {} } },
                        { mockTestQuestions: { some: {} } },
                    ],
                },
            });

            if (subjectUsage === 0) {
                await tx.subject.delete({ where: { id: sharedTest.subjectId } });
            }
        });
    } else if (resourceType === "PYQ") {
        const sharedPYQ = await prisma.oldQuestionPaper.findUnique({
            where: { id: sharedId },
            select: { examId: true }
        });

        await prisma.$transaction(async (tx) => {
            await tx.oldQuestionPaper.update({ where: { id: sharedId }, data: { questions: { set: [] } } });
            await tx.examResult.deleteMany({ where: { oldQuestionPaperId: sharedId } });
            await tx.oldQuestionPaper.delete({ where: { id: sharedId } });

            if (sharedPYQ && sharedPYQ.examId) {
                const examUsage = await tx.exam.count({
                    where: {
                        id: sharedPYQ.examId,
                        OR: [
                            { students: { some: {} } },
                            { oldQuestions: { some: {} } },
                            { practiceTests: { some: {} } },
                            { oldQuestionPapers: { some: {} } },
                            { mockTests: { some: {} } },
                            { syllabuses: { some: {} } },
                            { subjectsNotesToExam: { some: {} } },
                        ]
                    }
                });
                if (examUsage === 0) {
                    await tx.exam.delete({ where: { id: sharedPYQ.examId } });
                }
            }
        });
    } else if (resourceType === "MOCK_TEST") {
        const sharedMock = await prisma.mockTest.findUnique({
            where: { id: sharedId },
            select: { examId: true, institutionId: true }
        });

        await prisma.$transaction(async (tx) => {
            const results = await tx.mockTestResult.findMany({ where: { mockTestId: sharedId }, select: { id: true } });
            const resultIds = results.map((r: any) => r.id);
            if (resultIds.length > 0) {
                await tx.mockTestResultDetail.deleteMany({ where: { mockTestResultId: { in: resultIds } } });
                await tx.mockTestResult.deleteMany({ where: { id: { in: resultIds } } });
            }
            await tx.mockTestQuestion.deleteMany({ where: { mockTestId: sharedId } });
            await tx.mockTest.delete({ where: { id: sharedId } });

            if (sharedMock && sharedMock.examId && sharedMock.institutionId) {
                const examUsage = await tx.exam.count({
                    where: {
                        id: sharedMock.examId,
                        OR: [
                            { students: { some: {} } },
                            { oldQuestions: { some: {} } },
                            { practiceTests: { some: {} } },
                            { oldQuestionPapers: { some: {} } },
                            { mockTests: { some: {} } },
                            { syllabuses: { some: {} } },
                            { subjectsNotesToExam: { some: {} } },
                        ]
                    }
                });
                if (examUsage === 0) {
                    await tx.exam.delete({ where: { id: sharedMock.examId } });
                }
            }
        });
    } else {
        await prisma.$transaction(async (tx) => {
            await tx.questionBank.update({ where: { id: sharedId }, data: { practiceTests: { set: [] } } });
            await tx.mockTestResultDetail.deleteMany({ where: { questionId: sharedId } });
            await tx.mockTestQuestion.deleteMany({ where: { questionId: sharedId } });
            await tx.testQuestion.deleteMany({ where: { questionId: sharedId } });
            await tx.questionBank.delete({ where: { id: sharedId } });
        });
    }

    res.status(200).json({ success: true, message: "Resource removed successfully" });
});

// Get Shared History
export const getSharedHistory = asyncHandler(async (req: Request, res: Response) => {
    const { fromInstitutionId, toInstitutionId, resourceType, subjectId, examId, search, year, page = "1", limit = "10" } = req.query;

    const pageNum = parseInt(page as string) || 1;
    const limitNum = parseInt(limit as string) || 10;
    const skip = (pageNum - 1) * limitNum;

    let resolvedFromId: string | undefined;
    let resolvedToId: string | undefined;

    if (fromInstitutionId) {
        const fromRec = await prisma.institution.findFirst({
            where: { userId: fromInstitutionId as string },
            select: { id: true }
        });
        resolvedFromId = fromRec?.id ?? (fromInstitutionId as string);
    }

    if (toInstitutionId) {
        const toRec = await prisma.institution.findFirst({
            where: { userId: toInstitutionId as string },
            select: { id: true }
        });
        resolvedToId = toRec?.id ?? (toInstitutionId as string);
    }



    let combinedHistory: any[] = [];

    const institutionInclude = {
        select: {
            user: {
                select: {
                    institutionName: true,
                },
            },
        },
    };

    const fetchTests = async () => {
        const tests = await prisma.test.findMany({
            where: {
                referenceSourceId: { not: null },
                ...(resolvedToId ? { institutionId: resolvedToId } : {}),
                ...(resolvedFromId ? { referenceSource: { institutionId: resolvedFromId } } : {}),
                ...(subjectId ? { subjectId: subjectId as string } : {}),
                ...(search ? {
                    OR: [
                        { title: { contains: search as string } },
                        { referenceSource: { title: { contains: search as string } } }
                    ]
                } : {}),
            },
            include: {
                institution: institutionInclude,
                subject: { select: { subjectName: true } },
                referenceSource: {
                    include: {
                        institution: institutionInclude,
                        subject: { select: { subjectName: true } },
                    },
                },
                referenceInstitution: institutionInclude,
            },
            orderBy: { createdAt: "desc" },
        });

        return tests.map((t: any) => ({
            id: t.id,
            resourceName: t.referenceSource?.title || t.title,
            subjectName: (t.referenceSource?.subject?.subjectName || t.subject?.subjectName) ?? null,
            type: "TEST",
            fromInstitution: t.referenceSource?.institution?.user?.institutionName || t.referenceInstitution?.user?.institutionName || "Unknown",
            toInstitution: t.institution?.user?.institutionName || "Unknown",
            targetInstitutionId: t.institutionId,
            sharedDate: t.createdAt,
        }));
    };

    const fetchPYQs = async () => {
        const pyqs = await prisma.oldQuestionPaper.findMany({
            where: {
                referenceSourceId: { not: null },
                ...(resolvedToId ? { institutionId: resolvedToId } : {}),
                ...(resolvedFromId ? { referenceSource: { institutionId: resolvedFromId } } : {}),
                ...(examId ? {
                    OR: [
                        { examId: examId as string },
                        { referenceSource: { examId: examId as string } }
                    ]
                } : {}),
                ...(year ? {
                    OR: [
                        { year: year as string },
                        { referenceSource: { year: year as string } }
                    ]
                } : {}),
                ...(search ? {
                    OR: [
                        { title: { contains: search as string } },
                        { referenceSource: { title: { contains: search as string } } }
                    ]
                } : {}),
            },
            include: {
                institution: institutionInclude,
                exam: { select: { examName: true } },
                referenceSource: {
                    include: {
                        institution: institutionInclude,
                        exam: { select: { examName: true } },
                    },
                },
                referenceInstitution: institutionInclude,
            },
            orderBy: { createdAt: "desc" },
        });

        return pyqs.map((p: any) => ({
            id: p.id,
            resourceName: p.referenceSource?.title || p.title,
            examName: (p.referenceSource?.exam?.examName || p.exam?.examName) ?? null,
            type: "PYQ",
            year: p.referenceSource?.year || p.year,
            fromInstitution: p.referenceSource?.institution?.user?.institutionName || p.referenceInstitution?.user?.institutionName || "Unknown",
            toInstitution: p.institution?.user?.institutionName || "Unknown",
            targetInstitutionId: p.institutionId,
            sharedDate: p.createdAt,
        }));
    };

    const fetchMockTests = async () => {
        const mocks = await prisma.mockTest.findMany({
            where: {
                referenceSourceId: { not: null },
                ...(resolvedToId ? { institutionId: resolvedToId } : {}),
                ...(resolvedFromId ? { referenceSource: { institutionId: resolvedFromId } } : {}),
                ...(examId ? {
                    OR: [
                        { examId: examId as string },
                        { referenceSource: { examId: examId as string } }
                    ]
                } : {}),
                ...(search ? {
                    OR: [
                        { title: { contains: search as string } },
                        { referenceSource: { title: { contains: search as string } } }
                    ]
                } : {}),
            },
            include: {
                institution: institutionInclude,
                exam: { select: { examName: true } },
                referenceSource: {
                    include: {
                        institution: institutionInclude,
                        exam: { select: { examName: true } },
                    },
                },
                referenceInstitution: institutionInclude,
            },
            orderBy: { createdAt: "desc" },
        });

        return mocks.map((m: any) => ({
            id: m.id,
            resourceName: m.referenceSource?.title || m.title,
            examName: (m.referenceSource?.exam?.examName || m.exam?.examName) ?? null,
            type: "MOCK_TEST",
            fromInstitution: m.referenceSource?.institution?.user?.institutionName || m.referenceInstitution?.user?.institutionName || "Unknown",
            toInstitution: m.institution?.user?.institutionName || "Unknown",
            targetInstitutionId: m.institutionId,
            sharedDate: m.createdAt,
        }));
    };

    if (!resourceType || resourceType === "TEST") {
        combinedHistory = [...combinedHistory, ...(await fetchTests())];
    }

    if (!resourceType || resourceType === "PYQ") {
        combinedHistory = [...combinedHistory, ...(await fetchPYQs())];
    }

    if (!resourceType || resourceType === "MOCK_TEST") {
        combinedHistory = [...combinedHistory, ...(await fetchMockTests())];
    }
    combinedHistory.sort((a, b) => new Date(b.sharedDate).getTime() - new Date(a.sharedDate).getTime());

    const total = combinedHistory.length;
    const paginatedData = combinedHistory.slice(skip, skip + limitNum);

    const processedHistory = [];
    for (const item of paginatedData) {
        let isRemovable = false;
        if (item.type === "TEST") {
            const mappedPracticeTests = await prisma.practiceTest.findMany({ where: { testId: item.id, institutionId: item.targetInstitutionId }, select: { id: true } });
            if (mappedPracticeTests.length === 0) {
                isRemovable = true;
            } else {
                const practiceIds = mappedPracticeTests.map(p => p.id);
                const resultsCount = await prisma.examResult.count({ where: { practiceTestId: { in: practiceIds } } });
                if (resultsCount === 0) isRemovable = true;
            }
        } else if (item.type === "PYQ") {
            const resultsCount = await prisma.examResult.count({ where: { oldQuestionPaperId: item.id, institutionId: item.targetInstitutionId } });
            isRemovable = resultsCount === 0;
        } else if (item.type === "MOCK_TEST") {
            const resultsCount = await prisma.mockTestResult.count({ where: { mockTestId: item.id } });
            isRemovable = resultsCount === 0;
        }
        processedHistory.push({ ...item, isRemovable });
    }

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