import { calculateShoringRatio, type ShoringAssignment } from "@capakraken/engine/allocation";
import type { WeekdayAvailability } from "@capakraken/shared";
import { TRPCError } from "@trpc/server";
import {
  calculateEffectiveBookedHours,
  loadResourceDailyAvailabilityContexts,
} from "../lib/resource-capacity.js";
import type { TRPCContext } from "../trpc.js";

type ProjectShoringRatioProjectRecord = {
  id: string;
  name: string;
  shoringThreshold: number | null;
  onshoreCountryCode: string | null;
};

type ProjectShoringRatioAssignmentRecord = {
  resourceId: string;
  startDate: Date;
  endDate: Date;
  hoursPerDay: number;
  resource: {
    id: string;
    countryId: string | null;
    federalState: string | null;
    metroCityId: string | null;
    availability: unknown;
    country: { id: string; code: string } | null;
    metroCity: { id: string; name: string } | null;
  };
};

export async function getProjectShoringRatio(
  db: TRPCContext["db"],
  projectId: string,
) {
  const project = await db.project.findUnique({
    where: { id: projectId },
    select: {
      id: true,
      name: true,
      shoringThreshold: true,
      onshoreCountryCode: true,
    },
  }) as ProjectShoringRatioProjectRecord | null;

  if (!project) {
    throw new TRPCError({ code: "NOT_FOUND", message: "Project not found" });
  }

  const assignments = await db.assignment.findMany({
    where: { projectId, status: { not: "CANCELLED" } },
    include: {
      resource: {
        include: {
          country: { select: { id: true, code: true } },
          metroCity: { select: { id: true, name: true } },
        },
      },
    },
  }) as ProjectShoringRatioAssignmentRecord[];

  const periodStart = assignments.length > 0
    ? new Date(Math.min(...assignments.map((assignment) => assignment.startDate.getTime())))
    : new Date();
  const periodEnd = assignments.length > 0
    ? new Date(Math.max(...assignments.map((assignment) => assignment.endDate.getTime())))
    : new Date();

  const contexts = await loadResourceDailyAvailabilityContexts(
    db,
    assignments.map((assignment) => ({
      id: assignment.resource.id,
      availability: assignment.resource.availability as WeekdayAvailability,
      countryId: assignment.resource.country?.id ?? assignment.resource.countryId,
      countryCode: assignment.resource.country?.code,
      federalState: assignment.resource.federalState,
      metroCityId: assignment.resource.metroCity?.id ?? assignment.resource.metroCityId,
      metroCityName: assignment.resource.metroCity?.name,
    })),
    periodStart,
    periodEnd,
  );

  const mapped: ShoringAssignment[] = assignments.map((assignment) => {
    const workingDays = assignment.hoursPerDay > 0
      ? calculateEffectiveBookedHours({
        availability: assignment.resource.availability as WeekdayAvailability,
        startDate: assignment.startDate,
        endDate: assignment.endDate,
        hoursPerDay: assignment.hoursPerDay,
        periodStart,
        periodEnd,
        context: contexts.get(assignment.resourceId ?? assignment.resource.id),
      }) / assignment.hoursPerDay
      : 0;

    return {
      resourceId: assignment.resourceId,
      countryCode: assignment.resource.country?.code ?? null,
      hoursPerDay: assignment.hoursPerDay,
      workingDays: Math.max(0, workingDays),
    };
  });

  return calculateShoringRatio(
    mapped,
    project.shoringThreshold ?? 55,
    project.onshoreCountryCode ?? "DE",
  );
}
