import type { ExpenseKind, LaborPaymentBasis, LaborPaymentStatus, Prisma } from "@prisma/client";
import { currency, shortDate } from "./format";
import { toNumber, type ProjectDetail } from "./metrics";

export const expenseKindLabels: Record<ExpenseKind, string> = {
  STANDARD: "Standard Expense",
  LABOR_COST: "Labor Cost / Worker Payment"
};

export const laborPaymentBasisLabels: Record<LaborPaymentBasis, string> = {
  FIXED_FOR_PERIOD: "Fixed for period",
  DAILY: "Daily",
  HOURLY: "Hourly",
  ADVANCE: "Advance",
  ADJUSTMENT: "Adjustment"
};

export const laborPaymentStatusLabels: Record<LaborPaymentStatus, string> = {
  REGULAR_PAYMENT: "Regular payment",
  ADVANCE_PAYMENT: "Advance payment",
  PARTIAL_PAYMENT: "Partial payment",
  FINAL_PAYMENT: "Final payment",
  BONUS: "Bonus",
  CORRECTION_ADJUSTMENT: "Correction/adjustment"
};

export const laborPaymentBasisOptions = Object.entries(laborPaymentBasisLabels) as Array<[LaborPaymentBasis, string]>;
export const laborPaymentStatusOptions = Object.entries(laborPaymentStatusLabels) as Array<[LaborPaymentStatus, string]>;

export type LaborExpenseRecord = ProjectDetail["expenses"][number];
export type WorkerRecord = ProjectDetail["workers"][number];

export function laborAverage(finalCost: unknown, actualPaidWorkDays: unknown) {
  const days = toNumber(actualPaidWorkDays);
  if (!Number.isFinite(days) || days <= 0) return null;
  return toNumber(finalCost) / days;
}

export function formatLaborAverage(finalCost: unknown, actualPaidWorkDays: unknown) {
  const average = laborAverage(finalCost, actualPaidWorkDays);
  return average === null ? "-" : `${currency(average)}/day`;
}

export function laborDateRange(expense: Pick<LaborExpenseRecord, "workStartDate" | "workEndDate">) {
  if (!expense.workStartDate) return "-";
  if (!expense.workEndDate) return shortDate(expense.workStartDate);
  return `${shortDate(expense.workStartDate)} - ${shortDate(expense.workEndDate)}`;
}

export function laborExpenseMatches(expense: Pick<LaborExpenseRecord, "transactionKind">) {
  return expense.transactionKind === "LABOR_COST";
}

export function workerLaborExpenses(project: ProjectDetail, workerId: string) {
  return project.expenses.filter((expense) => (
    expense.transactionKind === "LABOR_COST" &&
    expense.workerId === workerId &&
    !expense.archived &&
    toNumber(expense.actualPaidWorkDays) > 0
  ));
}

export function workerLaborSummary(project: ProjectDetail, workerId: string) {
  const laborExpenses = workerLaborExpenses(project, workerId);
  const totalPaid = laborExpenses.reduce((sum, expense) => sum + toNumber(expense.finalCost), 0);
  const totalDays = laborExpenses.reduce((sum, expense) => sum + toNumber(expense.actualPaidWorkDays), 0);
  const averagePerDay = totalDays > 0 ? totalPaid / totalDays : null;
  const lastPaymentDate = laborExpenses
    .map((expense) => expense.date)
    .sort((a, b) => b.getTime() - a.getTime())[0] ?? null;
  return {
    totalPaid,
    totalDays,
    averagePerDay,
    paymentCount: laborExpenses.length,
    lastPaymentDate
  };
}

export function workerSummaryMap(project: ProjectDetail) {
  return Object.fromEntries(
    project.workers.map((worker) => [worker.id, workerLaborSummary(project, worker.id)])
  ) as Record<string, ReturnType<typeof workerLaborSummary>>;
}

export function decimalOrNull(value: Prisma.Decimal | number | string | null | undefined) {
  if (value === null || value === undefined || value === "") return null;
  const parsed = Number(value);
  return Number.isFinite(parsed) ? parsed : null;
}
