import { type BudgetForecastRow, getDashboardProjectHealth } from "@capakraken/application";
import { fmtEur } from "../lib/format-utils.js";

type DashboardBudgetForecastCalendarLocation = {
  countryCode: string | null;
  countryName: string | null;
  federalState: string | null;
  metroCityName: string | null;
  activeAssignmentCount: number;
  burnRateCents: number;
};

type DashboardBudgetForecastDerivation = {
  periodStart: string;
  periodEnd: string;
  calendarContextCount: number;
  holidayAwareAssignmentCount: number;
  fallbackAssignmentCount: number;
  baseBurnRateCents: number;
  adjustedBurnRateCents: number;
  publicHolidayDayEquivalent: number;
  publicHolidayCostDeductionCents: number;
  absenceDayEquivalent: number;
  absenceCostDeductionCents: number;
};

export type DashboardBudgetForecastDetail = {
  forecasts: Array<{
    projectId: string | null;
    projectName: string;
    shortCode: string;
    clientId: string | null;
    clientName: string | null;
    budget: string;
    budgetCents: number;
    spent: string;
    spentCents: number;
    remaining: string;
    remainingCents: number;
    projected: string;
    projectedCents: number;
    burnRate: string;
    burnRateCents: number;
    utilization: string;
    estimatedExhaustionDate: string | null;
    activeAssignmentCount: number | null;
    calendarLocations: DashboardBudgetForecastCalendarLocation[];
    derivation: DashboardBudgetForecastDerivation | null;
    burnStatus: "ahead" | "on_track" | "not_started";
  }>;
};

type DashboardProjectHealthCalendarLocation = {
  countryCode: string | null;
  countryName: string | null;
  federalState: string | null;
  metroCityName: string | null;
  assignmentCount: number;
  spentCents: number;
};

type DashboardProjectHealthDerivation = {
  periodStart: string;
  periodEnd: string;
  calendarContextCount: number;
  holidayAwareAssignmentCount: number;
  fallbackAssignmentCount: number;
  baseSpentCents: number;
  adjustedSpentCents: number;
  publicHolidayDayEquivalent: number;
  publicHolidayCostDeductionCents: number;
  absenceDayEquivalent: number;
  absenceCostDeductionCents: number;
};

export type DashboardProjectHealthDetail = {
  projects: Array<{
    projectId: string;
    projectName: string;
    shortCode: string;
    status: string;
    overall: number;
    budget: number;
    staffing: number;
    timeline: number;
    rating: "healthy" | "at_risk" | "critical";
    budgetBasis: {
      budgetCents: number | null;
      spentCents: number;
      remainingBudgetCents: number | null;
      budgetUtilizationPercent: number | null;
      calendarLocations: DashboardProjectHealthCalendarLocation[];
      derivation: DashboardProjectHealthDerivation | null;
    };
    staffingBasis: {
      demandHeadcountTotal: number;
      demandHeadcountFilled: number;
      demandHeadcountOpen: number;
      demandRequirementCount: number;
    };
    timelineBasis: {
      plannedEndDate: string | null;
      daysUntilEndDate: number | null;
      timelineStatus: "ON_TRACK" | "DUE_SOON" | "OVERDUE" | "UNSCHEDULED";
    };
    context: {
      clientId: string | null;
      clientName: string | null;
    };
  }>;
  summary: {
    healthy: number;
    atRisk: number;
    critical: number;
  };
};

export function mapProjectHealthDetailRows(
  rows: Awaited<ReturnType<typeof getDashboardProjectHealth>>,
): DashboardProjectHealthDetail {
  const projects: DashboardProjectHealthDetail["projects"] = rows
    .map((project): DashboardProjectHealthDetail["projects"][number] => {
      const overall = project.compositeScore;
      const rating: DashboardProjectHealthDetail["projects"][number]["rating"] = overall >= 80
        ? "healthy"
        : overall >= 50
          ? "at_risk"
          : "critical";

      return {
        projectId: project.id,
        projectName: project.projectName,
        shortCode: project.shortCode,
        status: project.status,
        overall,
        budget: project.budgetHealth,
        staffing: project.staffingHealth,
        timeline: project.timelineHealth,
        rating,
        budgetBasis: {
          budgetCents: project.budgetCents ?? null,
          spentCents: project.spentCents ?? 0,
          remainingBudgetCents: project.remainingBudgetCents ?? null,
          budgetUtilizationPercent: project.budgetUtilizationPercent ?? null,
          calendarLocations: project.calendarLocations ?? [],
          derivation: project.derivation ?? null,
        },
        staffingBasis: {
          demandHeadcountTotal: project.demandHeadcountTotal ?? 0,
          demandHeadcountFilled: project.demandHeadcountFilled ?? 0,
          demandHeadcountOpen: project.demandHeadcountOpen ?? 0,
          demandRequirementCount: project.demandRequirementCount ?? 0,
        },
        timelineBasis: {
          plannedEndDate: project.plannedEndDate?.toISOString() ?? null,
          daysUntilEndDate: project.daysUntilEndDate ?? null,
          timelineStatus: project.timelineStatus ?? "UNSCHEDULED",
        },
        context: {
          clientId: project.clientId ?? null,
          clientName: project.clientName ?? null,
        },
      };
    })
    .sort((left, right) => left.overall - right.overall);

  return {
    projects,
    summary: {
      healthy: projects.filter((project) => project.rating === "healthy").length,
      atRisk: projects.filter((project) => project.rating === "at_risk").length,
      critical: projects.filter((project) => project.rating === "critical").length,
    },
  };
}

export function mapBudgetForecastDetailRows(
  rows: BudgetForecastRow[],
): DashboardBudgetForecastDetail {
  return {
    forecasts: rows.map((forecast) => ({
      projectId: forecast.projectId ?? null,
      projectName: forecast.projectName,
      shortCode: forecast.shortCode,
      clientId: forecast.clientId,
      clientName: forecast.clientName,
      budget: fmtEur(forecast.budgetCents),
      budgetCents: forecast.budgetCents,
      spent: fmtEur(forecast.spentCents),
      spentCents: forecast.spentCents,
      remaining: fmtEur(forecast.remainingCents ?? (forecast.budgetCents - forecast.spentCents)),
      remainingCents: forecast.remainingCents ?? (forecast.budgetCents - forecast.spentCents),
      projected: forecast.burnRate > 0
        ? fmtEur(forecast.spentCents + Math.max(0, forecast.budgetCents - forecast.spentCents))
        : fmtEur(forecast.spentCents),
      projectedCents: forecast.burnRate > 0
        ? Math.max(forecast.spentCents, forecast.budgetCents)
        : forecast.spentCents,
      burnRate: fmtEur(forecast.burnRate),
      burnRateCents: forecast.burnRate,
      utilization: `${forecast.pctUsed}%`,
      estimatedExhaustionDate: forecast.estimatedExhaustionDate,
      activeAssignmentCount: forecast.activeAssignmentCount ?? null,
      calendarLocations: forecast.calendarLocations ?? [],
      derivation: forecast.derivation ?? null,
      burnStatus: forecast.pctUsed >= 100
        ? "ahead"
        : forecast.burnRate > 0
          ? "on_track"
          : "not_started",
    })),
  };
}
