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

// Self update user details
export const updateUserDetails = asyncHandler(async (req, res) => {
    const userId = (req as any).user.id;
    const { firstName, lastName, phone, contactPerson, institutionName, institutionAddress, gstNumber, state, pincode, mediumOfExam, language } = req.body;
    const actualMediumOfExam = mediumOfExam !== undefined ? mediumOfExam : language;

    const updateData: any = {};
    if (firstName && firstName.trim() !== "") updateData.firstName = firstName.trim();
    if (lastName && lastName.trim() !== "") updateData.lastName = lastName.trim();
    if (phone && phone.trim() !== "") updateData.phone = phone.trim();
    if (contactPerson && contactPerson.trim() !== "") updateData.contactPerson = contactPerson.trim();
    if (institutionName && institutionName.trim() !== "") updateData.institutionName = institutionName.trim();
    if (institutionAddress && institutionAddress.trim() !== "") updateData.institutionAddress = institutionAddress.trim();
    if (state && state.trim() !== "") updateData.state = state.trim();
    if (pincode && pincode.trim() !== "") updateData.pincode = pincode.trim();

    const currentUser = await prisma.user.findUnique({ where: { id: userId }, select: { details: true, role: true } });
    let updatedDetails: any = currentUser?.details || {};
    let detailsChanged = false;

    if (actualMediumOfExam !== undefined && currentUser?.role === "STUDENT") {
        const studentInstitutionId = (req as any).user?.studentInstitutionId;
        if (studentInstitutionId) {
            await prisma.studentInstitution.update({
                where: { id: studentInstitutionId },
                data: { language: actualMediumOfExam }
            });
        }
    } else if (actualMediumOfExam !== undefined) {
        if (typeof updatedDetails !== 'object' || updatedDetails === null) updatedDetails = {};
        updatedDetails.mediumOfExam = actualMediumOfExam;
        detailsChanged = true;
    }

    if (detailsChanged) {
        updateData.details = updatedDetails;
    }

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

    let returnedMediumOfExam = (updatedUser.details as any)?.mediumOfExam || null;
    let returnedLanguage = "";
    if (updatedUser.role === "STUDENT") {
        const studentInstitutionId = (req as any).user?.studentInstitutionId;
        if (studentInstitutionId) {
            const studentInst = await prisma.studentInstitution.findUnique({ where: { id: studentInstitutionId }, include: { student: true } });
            returnedMediumOfExam = studentInst?.student?.language ? (studentInst?.language || "English") : "English";
            returnedLanguage = studentInst?.student?.language || studentInst?.language || "";
        }
    }

    let response: any = {
        language: returnedLanguage,
        mediumOfExam: returnedMediumOfExam,
        id: updatedUser.id,
        email: updatedUser.email,
        firstName: updatedUser.firstName,
        lastName: updatedUser.lastName,
        phone: updatedUser.phone,
        role: updatedUser.role,
        state: updatedUser.state,
        pincode: updatedUser.pincode,
        isVerified: updatedUser.isVerified,
        contactPerson: updatedUser.contactPerson ?? "",
        institutionName: updatedUser.institutionName,
        institutionAddress: updatedUser.institutionAddress,
        logoPic: updatedUser.logoPic ? `${getHost()}${updatedUser.logoPic}` : "",
        profilePic: updatedUser.profilePic ? `${getHost()}${updatedUser.profilePic}` : "",
        createdAt: toIST(updatedUser.createdAt),
        updatedAt: toIST(updatedUser.updatedAt),
    };

    if (updatedUser.role === "STAFF") {
        const institution = await prisma.user.findUnique({ where: { id: updatedUser.createdById } });
        response.institutionName = institution?.institutionName;
        response.institutionAddress = institution?.institutionAddress;
        response.logoPic = institution?.logoPic ? `${getHost()}${institution?.logoPic}` : "";
    }

    if (updatedUser.role === "INSTITUTION" || updatedUser.role === "ADMIN") {
        if (gstNumber && gstNumber.trim() !== "") {
            await prisma.user.update({
                where: { id: updatedUser.id },
                data: { gstNumber: gstNumber.trim() }
            });
            response.gstNumber = gstNumber.trim();
        }
    }

    res.status(200).json({
        message: "Updated successfully",
        data: response
    });
});

export const listUsers = asyncHandler(async (req: Request, res: Response) => {
    const currentUserId = (req as any).user?.id;
    const roleFilter = (req.query.role as string)?.trim();
    const search = (req.query.search as string)?.trim();
    const isVerified = (req.query.isVerified as string)?.trim();
    const page = parseInt(req.query.page as string) || 1;
    const limit = parseInt(req.query.limit as string) || 10;
    const skip = (page - 1) * limit;

    const where: any = {
        id: { not: currentUserId },
        isDeleted: false,
    };

    if (roleFilter && roleFilter.toUpperCase() !== "ALL") {
        where.role = roleFilter.toUpperCase();
    }

    if (isVerified) {
        where.isVerified = isVerified === "true";
    }

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

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

    const [total, users] = await Promise.all([
        prisma.user.count({ where }),
        prisma.user.findMany({
            where,
            select: {
                id: true,
                email: true,
                firstName: true,
                lastName: true,
                phone: true,
                role: true,
                state: true,
                pincode: true,
                isVerified: true,
                institutionName: true,
                institutionAddress: true,
                contactPerson: true,
                profilePic: true,
                logoPic: true,
                gstNumber: true,
                createdAt: true,
            },
            orderBy: { institutionName: 'asc' },
            skip,
            take: limit
        })
    ]);

    const formattedUsers = users.map(async (u) => {
        if (u.role === "INSTITUTION") {
            const [studentCount, staffCount] = await Promise.all([
                prisma.user.count({ where: { role: "STUDENT", createdById: u.id, isDeleted: false } }),
                prisma.user.count({ where: { role: "STAFF", createdById: u.id, isDeleted: false } })
            ]);
            return {
                ...u,
                createdAt: toIST(u.createdAt),
                studentCount,
                staffCount
            };
        }
        return {
            ...u,
            createdAt: toIST(u.createdAt)
        };
    });

    const finalUsers = await Promise.all(formattedUsers);

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

export const getUserProfile = asyncHandler(async (req: Request, res: Response) => {
    const userId = req.params.id;
    const user = await prisma.user.findUnique({ 
        where: { id: userId, isDeleted: false }, 
        select: { 
            id: true, email: true, firstName: true, lastName: true, phone: true, 
            role: true, isVerified: true, institutionName: true, institutionAddress: true, 
            contactPerson: true, profilePic: true, logoPic: true, state: true, pincode: true,
            details: true,
            student: { 
                select: { 
                    id: true, 
                    referral: true,
                    language: true,
                    institutions: {
                        where: { deletedAt: null },
                        select: { id: true, language: true, isPrimary: true }
                    }
                } 
            }
        } 
    });
    
    if (!user) {
        res.status(404).json({ message: "User not found" });
        return;
    }
    
    const { student, details, ...userData } = user as any;
    
    const activeInstitutionId = (req as any).user?.studentInstitutionId;
    let targetInst = user.student?.institutions?.find((i: any) => i.id === activeInstitutionId);
    if (!targetInst) targetInst = user.student?.institutions?.find((i: any) => i.isPrimary);
    if (!targetInst) targetInst = user.student?.institutions?.[0];

    res.status(200).json({
        message: "Successfully fetched.",
        data: {
            ...userData,
            language: user.student?.language || targetInst?.language || "",
            mediumOfExam: user.student?.language ? (targetInst?.language || "English") : "English"
        }
    });
});

export const deleteUser = asyncHandler(async (req: Request, res: Response) => {
    res.status(402).send({ message: "Under maintanence" });
    return;
    const userId = req.params.id;
    // await prisma.user.delete({ where: { id: userId } });
    res.status(200).json({
        message: "User deleted successfully",
        deletedId: userId
    });
});

export const checkEmail = asyncHandler(async (req: Request, res: Response) => {
    const { email } = req.query;
    if (!email) {
        res.status(400).json({ message: "Email is required" });
        return;
    }
    const user = await prisma.user.findFirst({
        where: { email: email as string }
    });
    res.status(200).json({ exists: !!user });
});

export const uploadUserImage = asyncHandler(async (req: Request, res: Response) => {
    const user = req.user;

    const existing = await prisma.user.findFirst({
        where: { id: user.id },
    });

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

    const filesMap = req.files as {
        logoPic?: Express.Multer.File[];
        profilePic?: Express.Multer.File[];
    };

    const logoPicFile = filesMap?.logoPic?.[0];
    const profilePicFile = filesMap?.profilePic?.[0];

    const updates: any = {};

    if (logoPicFile) {
        updates.logoPic = toPublicPath(logoPicFile.path);
    }

    if (profilePicFile) {
        updates.profilePic = toPublicPath(profilePicFile.path);
    }

    if (Object.keys(updates).length === 0) {
        res.status(400).json({ message: "No files uploaded" });
        return;
    }

    await prisma.user.update({
        where: { id: user.id },
        data: updates,
    });

    res.status(200).json({
        message: "Image uploaded successfully",
        data: { logoPic: updates.logoPic ? `${getHost()}${updates.logoPic}` : existing.logoPic, profilePic: updates.profilePic ? `${getHost()}${updates.profilePic}` : existing.profilePic },
    });
});
