import { db } from "@/lib/db"

import { PayrollInput } from "./schema"
import { Payroll, PayrollListItem } from "./types"

function calculatePayroll(data: PayrollInput): {
  totalAdditions: number
  totalDeductions: number
  netPayable: number
} {
  const totalAdditions = data.items
    .filter((i) => i.type === "ADDITION")
    .reduce((sum, i) => sum + i.amount, 0)

  const totalDeductions = data.items
    .filter((i) => i.type === "DEDUCTION")
    .reduce((sum, i) => sum + i.amount, 0)

  // Calculate pro-rated basic salary based on days worked
  const dailyRate = data.basicSalary / data.workingDays
  const proratedBasic = dailyRate * data.daysWorked

  const netPayable = proratedBasic + totalAdditions - totalDeductions

  return {
    totalAdditions,
    totalDeductions,
    netPayable,
  }
}

export async function listPayrolls(
  month?: number,
  year?: number
): Promise<PayrollListItem[]> {
  const where: { month?: number; year?: number } = {}
  if (month !== undefined) where.month = month
  if (year !== undefined) where.year = year

  const payrolls = await db.payroll.findMany({
    where,
    orderBy: [{ year: "desc" }, { month: "desc" }, { createdAt: "desc" }],
    include: {
      employee: {
        select: { id: true, fullName: true },
      },
    },
  })

  return payrolls.map((p) => ({
    id: p.id,
    employeeId: p.employeeId,
    employeeName: p.employee?.fullName ?? "Unknown",
    month: p.month,
    year: p.year,
    workingDays: p.workingDays,
    daysWorked: p.daysWorked,
    basicSalary: p.basicSalary,
    netPayable: p.netPayable,
    status: p.status as PayrollListItem["status"],
    createdAt: p.createdAt,
  }))
}

export async function getPayrollById(id: string): Promise<Payroll | null> {
  const payroll = await db.payroll.findUnique({
    where: { id },
    include: {
      employee: {
        select: { id: true, fullName: true, email: true },
      },
      approvedBy: {
        select: { id: true, name: true },
      },
      items: true,
    },
  })

  if (!payroll) return null

  return {
    ...payroll,
    status: payroll.status as Payroll["status"],
    items: payroll.items.map((i) => ({
      id: i.id,
      type: i.type as Payroll["items"][0]["type"],
      description: i.description,
      amount: i.amount,
    })),
  }
}

export async function createPayroll(data: PayrollInput): Promise<Payroll> {
  // Check if payroll already exists for this employee/month/year
  const existing = await db.payroll.findUnique({
    where: {
      employeeId_month_year: {
        employeeId: data.employeeId,
        month: data.month,
        year: data.year,
      },
    },
  })

  if (existing) {
    throw new Error("Payroll already exists for this employee and month")
  }

  // Calculate payroll values
  const calculated = calculatePayroll(data)

  const payroll = await db.payroll.create({
    data: {
      employeeId: data.employeeId,
      month: data.month,
      year: data.year,
      workingDays: data.workingDays,
      daysWorked: data.daysWorked,
      basicSalary: data.basicSalary,
      totalAdditions: calculated.totalAdditions,
      totalDeductions: calculated.totalDeductions,
      netPayable: calculated.netPayable,
      items: {
        create: data.items.map((i) => ({
          type: i.type,
          description: i.description,
          amount: i.amount,
        })),
      },
      notes: data.notes,
      status: data.status,
    },
    include: {
      employee: {
        select: { id: true, fullName: true, email: true },
      },
      items: true,
    },
  })

  return {
    ...payroll,
    status: payroll.status as Payroll["status"],
    items: payroll.items.map((i) => ({
      id: i.id,
      type: i.type as Payroll["items"][0]["type"],
      description: i.description,
      amount: i.amount,
    })),
    approvedBy: null,
  }
}

export async function updatePayroll(id: string, data: PayrollInput): Promise<Payroll> {
  const existing = await db.payroll.findUnique({
    where: { id },
    include: { items: true },
  })

  if (!existing) {
    throw new Error("Payroll not found")
  }

  if (existing.status === "PAID") {
    throw new Error("Cannot edit a paid payroll")
  }

  // Calculate payroll values
  const calculated = calculatePayroll(data)

  // Delete existing items
  await db.payrollItem.deleteMany({
    where: { payrollId: id },
  })

  // Update payroll with new data
  const payroll = await db.payroll.update({
    where: { id },
    data: {
      employeeId: data.employeeId,
      month: data.month,
      year: data.year,
      workingDays: data.workingDays,
      daysWorked: data.daysWorked,
      basicSalary: data.basicSalary,
      totalAdditions: calculated.totalAdditions,
      totalDeductions: calculated.totalDeductions,
      netPayable: calculated.netPayable,
      items: {
        create: data.items.map((i) => ({
          type: i.type,
          description: i.description,
          amount: i.amount,
        })),
      },
      notes: data.notes,
      status: data.status,
    },
    include: {
      employee: {
        select: { id: true, fullName: true, email: true },
      },
      approvedBy: { select: { id: true, name: true } },
      items: true,
    },
  })

  return {
    ...payroll,
    status: payroll.status as Payroll["status"],
    items: payroll.items.map((i) => ({
      id: i.id,
      type: i.type as Payroll["items"][0]["type"],
      description: i.description,
      amount: i.amount,
    })),
  }
}

export async function deletePayroll(id: string): Promise<void> {
  const existing = await db.payroll.findUnique({
    where: { id },
  })

  if (!existing) {
    throw new Error("Payroll not found")
  }

  if (existing.status === "PAID") {
    throw new Error("Cannot delete a paid payroll")
  }

  await db.payroll.delete({
    where: { id },
  })
}

export async function processPayroll(
  id: string,
  userId: string,
  status: "APPROVED" | "PAID"
): Promise<Payroll> {
  const existing = await db.payroll.findUnique({
    where: { id },
  })

  if (!existing) {
    throw new Error("Payroll not found")
  }

  const updateData: { status?: string; approvedById?: string; approvedAt?: Date } = {}

  if (status === "APPROVED" && existing.status === "DRAFT") {
    updateData.status = "APPROVED"
    updateData.approvedById = userId
    updateData.approvedAt = new Date()
  } else if (status === "PAID" && existing.status !== "PAID") {
    updateData.status = "PAID"
    if (existing.status === "DRAFT") {
      // Auto-approve if going directly to paid
      updateData.approvedById = userId
      updateData.approvedAt = new Date()
    }
  } else {
    throw new Error(`Invalid status transition from ${existing.status} to ${status}`)
  }

  const payroll = await db.payroll.update({
    where: { id },
    data: updateData,
    include: {
      employee: {
        select: { id: true, fullName: true, email: true },
      },
      approvedBy: { select: { id: true, name: true } },
      items: true,
    },
  })

  return {
    ...payroll,
    status: payroll.status as Payroll["status"],
    items: payroll.items.map((i) => ({
      id: i.id,
      type: i.type as Payroll["items"][0]["type"],
      description: i.description,
      amount: i.amount,
    })),
  }
}

export async function listEmployeesForPayroll(): Promise<
  { id: string; fullName: string; email: string | null; branchId: string | null; departmentId: string | null }[]
> {
  return db.employee.findMany({
    select: { 
      id: true, 
      fullName: true, 
      email: true,
      branchId: true,       
      departmentId: true,   
    },
    orderBy: { fullName: "asc" },
  })
}

export async function getEmployeeSalaryComponents(employeeId: string): Promise<
  { category: string; amount: number }[]
> {
  const employee = await db.employee.findUnique({
    where: { id: employeeId },
    include: { salaryComponents: true },
  })

  return employee?.salaryComponents.map((c) => ({
    category: c.category,
    amount: c.amount,
  })) ?? []
}
