import { NextResponse } from "next/server";
import { prisma } from "@/lib/prisma";
import { requireRole } from "@/lib/auth";
import { PAYMENT_METHODS } from "@/lib/constants";

function currentMonth(): string {
  return new Date().toISOString().slice(0, 7);
}

/** Payroll sheet for a month (?month=YYYY-MM) + recent payment history. */
export async function GET(req: Request) {
  const session = await requireRole("INSTITUTION_ADMIN");
  if (!session || !session.institutionId) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }

  const url = new URL(req.url);
  const monthParam = url.searchParams.get("month");
  const month = monthParam && /^\d{4}-\d{2}$/.test(monthParam) ? monthParam : currentMonth();

  const [staff, payments, history] = await Promise.all([
    prisma.staff.findMany({
      where: { institutionId: session.institutionId, status: "ACTIVE" },
      orderBy: { id: "asc" },
    }),
    prisma.salaryPayment.findMany({
      where: { institutionId: session.institutionId, month },
      include: { staff: { select: { name: true, employeeCode: true } } },
    }),
    prisma.salaryPayment.findMany({
      where: { institutionId: session.institutionId },
      orderBy: { paidAt: "desc" },
      take: 10,
      include: { staff: { select: { name: true, employeeCode: true } } },
    }),
  ]);

  const paidByStaff = new Map(payments.map((p) => [p.staffId, p]));

  const payroll = staff.reduce((sum, s) => sum + Number(s.monthlySalary), 0);
  const paid = payments.reduce((sum, p) => sum + Number(p.amount), 0);

  return NextResponse.json({
    month,
    rows: staff.map((s) => ({
      staffId: s.id,
      employeeCode: s.employeeCode,
      name: s.name,
      designation: s.designation,
      salary: Number(s.monthlySalary),
      paidAmount: paidByStaff.has(s.id) ? Number(paidByStaff.get(s.id)!.amount) : 0,
      paid: paidByStaff.has(s.id),
      method: paidByStaff.get(s.id)?.method ?? null,
      details: (paidByStaff.get(s.id)?.details as Record<string, string> | null) ?? null,
      paidAt: paidByStaff.get(s.id)?.paidAt ?? null,
    })),
    summary: { payroll, paid, due: Math.max(0, payroll - paid), paidCount: payments.length },
    history: history.map((p) => ({
      id: p.id,
      staffName: p.staff.name,
      employeeCode: p.staff.employeeCode,
      month: p.month,
      amount: Number(p.amount),
      method: p.method,
      details: (p.details as Record<string, string> | null) ?? null,
      paidAt: p.paidAt,
    })),
  });
}

/** Record a salary payment: { staffId, month, amount, method, details, note }. */
export async function POST(req: Request) {
  const session = await requireRole("INSTITUTION_ADMIN");
  if (!session || !session.institutionId) {
    return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
  }

  try {
    const body = await req.json();
    const staffId = Number(body.staffId);
    const month = String(body.month ?? "");
    if (!staffId || !/^\d{4}-\d{2}$/.test(month)) {
      return NextResponse.json({ error: "Missing fields" }, { status: 400 });
    }

    // method-specific transaction details (TrxID / bank+cheque / card …)
    const details: Record<string, string> = {};
    if (body.details && typeof body.details === "object") {
      for (const [key, value] of Object.entries(body.details as Record<string, unknown>)) {
        const k = key.replace(/[^a-zA-Z0-9]/g, "").slice(0, 20);
        const v = String(value ?? "").trim().slice(0, 60);
        if (k && v) details[k] = v;
      }
    }

    const staff = await prisma.staff.findFirst({
      where: { id: staffId, institutionId: session.institutionId, status: "ACTIVE" },
    });
    if (!staff) return NextResponse.json({ error: "Not found" }, { status: 404 });

    const amount = body.amount !== undefined && Number(body.amount) > 0 ? Number(body.amount) : Number(staff.monthlySalary);
    if (!(amount > 0)) {
      return NextResponse.json({ error: "Invalid amount" }, { status: 400 });
    }

    const existing = await prisma.salaryPayment.findUnique({
      where: { staffId_month: { staffId, month } },
    });
    if (existing) return NextResponse.json({ error: "ALREADY_PAID" }, { status: 409 });

    const payment = await prisma.salaryPayment.create({
      data: {
        institutionId: session.institutionId,
        staffId,
        month,
        amount,
        method: PAYMENT_METHODS.includes(body.method as never) ? body.method : "CASH",
        details: Object.keys(details).length > 0 ? details : undefined,
        note: String(body.note ?? "").trim() || null,
        paidById: session.userId,
      },
    });
    return NextResponse.json({ payment });
  } catch {
    return NextResponse.json({ error: "Could not record payment" }, { status: 500 });
  }
}
