import { NextRequest, NextResponse } from "next/server";
import { prisma } from "@/lib/prisma";
import { parseDateUTC } from "@/lib/timeslot-utils";
import { getStudent } from "@/lib/studentAuth";
import { sendMail } from "@/lib/mailer";
import {
    vacationRequestSubmittedStudentEmailTemplate,
    vacationRequestSubmittedAdminEmailTemplate,
} from "@/lib/email-templates";

interface CreateVacationBody {
    start_date: string;
    end_date: string;
    reason?: string;
}

export async function GET() {
    const student = await getStudent();
    if (!student) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });

    const vacations = await prisma.student_vacations.findMany({
        where: { student_id: student.id as number },
        orderBy: { created_at: "desc" },
    });

    return NextResponse.json({ data: vacations });
}

export async function POST(req: NextRequest) {
    const student = await getStudent();
    if (!student) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });

    // Explicit casts here in case StudentTokenPayload still carries an index
    // signature ([key: string]: unknown) rather than typed fields.
    const studentId = student.id as number;
    const studentName = String(student.name ?? "A student");
    const studentEmailOrId = String(student.student_id ?? student.email ?? "");
    const studentEmail = String(student.email ?? "");

    const body: CreateVacationBody = await req.json();
    const { start_date, end_date, reason } = body;

    if (!start_date || !end_date) {
        return NextResponse.json({ error: "start_date and end_date are required" }, { status: 400 });
    }
    if (!reason || !reason.trim()) {
        return NextResponse.json({ error: "A reason is required" }, { status: 400 });
    }
    if (end_date < start_date) {
        return NextResponse.json({ error: "End date can't be before start date" }, { status: 400 });
    }

    const todayKey = new Date().toISOString().slice(0, 10);
    if (start_date < todayKey) {
        return NextResponse.json({ error: "You can't request a vacation starting in the past." }, { status: 400 });
    }

    const startDate = parseDateUTC(start_date);
    const endDate = parseDateUTC(end_date);
    const trimmedReason = reason.trim();

    const overlapping = await prisma.student_vacations.findFirst({
        where: {
            student_id: studentId,
            status: { in: ["pending", "approved"] },
            start_date: { lte: endDate },
            end_date: { gte: startDate },
        },
        select: { id: true, start_date: true, end_date: true, status: true },
    });

    if (overlapping) {
        const overlapStart = overlapping.start_date.toISOString().slice(0, 10);
        const overlapEnd = overlapping.end_date.toISOString().slice(0, 10);

        const message =
            overlapping.status === "approved"
                ? `You already have an approved vacation covering ${overlapStart} to ${overlapEnd}. Please choose different dates.`
                : `You already have a ${overlapping.status} vacation request covering ${overlapStart} to ${overlapEnd}. Please cancel it first or choose different dates.`;

        return NextResponse.json({ error: message }, { status: 409 });
    }

    const created = await prisma.student_vacations.create({
        data: {
            student_id: studentId,
            start_date: startDate,
            end_date: endDate,
            reason: trimmedReason,
        },
    });

    // Notify the student (confirmation) and all active admins. Never let a
    // mail failure fail the request itself.
    try {
        if (studentEmail) {
            await sendMail({
                to: studentEmail,
                subject: "Your RKDA vacation request has been submitted",
                html: vacationRequestSubmittedStudentEmailTemplate(
                    studentName,
                    { startLabel: start_date, endLabel: end_date },
                    trimmedReason
                ),
            });
        }

        const admins = await prisma.master_admin_users.findMany({
            where: {
                active_status: true,
                delete_status: false,
                deleted_at: null,
            },
            select: { user_email: true },
        });

        const adminEmails = admins.map((a) => a.user_email).filter(Boolean);

        if (adminEmails.length > 0) {
            const html = vacationRequestSubmittedAdminEmailTemplate(
                studentName,
                studentEmailOrId,
                { startLabel: start_date, endLabel: end_date },
                trimmedReason,
                `${process.env.NEXT_PUBLIC_APP_URL}/admin/vacation-requests`
            );

            // Send individually so one bad address doesn't silently drop the rest,
            // and so sendMail's `to` type (string) is satisfied either way.
            await Promise.allSettled(
                adminEmails.map((email) =>
                    sendMail({
                        to: email,
                        subject: `Vacation request from ${studentName}`,
                        html,
                    })
                )
            );
        } else {
            console.warn("No active admin recipients found for vacation request notification.");
        }
    } catch (mailErr) {
        console.error("Vacation Request Email Error:", mailErr);
    }

    return NextResponse.json({ data: created }, { status: 201 });
}