import { listAssignmentBookings } from "@capakraken/application";
import { computeBudgetStatus } from "@capakraken/engine";
import { getAnonymizationDirectory } from "../lib/anonymization.js";
import {
  loadTimelineProjectContextDetailArtifacts,
} from "./timeline-project-context-support.js";
import {
  buildTimelineProjectContextDetailResponse,
  buildTimelineProjectContextResponse,
} from "./timeline-project-context-response-support.js";
import {
  loadTimelineProjectContext,
  previewTimelineProjectShift,
} from "./timeline-project-load-support.js";
import {
  buildTimelineBudgetStatusAllocations,
  buildTimelineBudgetStatusResponse,
  buildTimelineShiftPreviewDetailResponse,
} from "./timeline-project-read-support.js";
import {
  findTimelineProjectOrThrow,
  timelineBudgetStatusProjectSelect,
  timelineShiftPreviewProjectSelect,
} from "./timeline-project-query-support.js";

type TimelineProjectProcedureDb =
  & Parameters<typeof getAnonymizationDirectory>[0]
  & Parameters<typeof loadTimelineProjectContext>[0]
  & Parameters<typeof loadTimelineProjectContextDetailArtifacts>[0]
  & Parameters<typeof findTimelineProjectOrThrow>[0]
  & Parameters<typeof listAssignmentBookings>[0];

export async function readTimelineProjectContextResponse(
  db: TimelineProjectProcedureDb,
  projectId: string,
) {
  const {
    project,
    allocations,
    demands,
    assignments,
    allResourceAllocations,
    resourceIds,
  } = await loadTimelineProjectContext(db, projectId);
  const directory = await getAnonymizationDirectory(db);

  return buildTimelineProjectContextResponse({
    project,
    allocations,
    demands,
    assignments,
    allResourceAllocations,
    resourceIds,
    directory,
  });
}

export async function readTimelineProjectContextDetailResponse(
  db: TimelineProjectProcedureDb,
  input: {
    projectId: string;
    startDate?: string | undefined;
    endDate?: string | undefined;
    durationDays?: number | undefined;
  },
) {
  const projectContext = await loadTimelineProjectContext(db, input.projectId);
  const directory = await getAnonymizationDirectory(db);
  const { period, holidayOverlays, assignmentConflicts } =
    await loadTimelineProjectContextDetailArtifacts(db, {
      projectId: input.projectId,
      requestedStartDate: input.startDate,
      requestedEndDate: input.endDate,
      durationDays: input.durationDays,
      projectStartDate: projectContext.project.startDate,
      projectEndDate: projectContext.project.endDate,
      firstAssignmentStartDate: projectContext.assignments[0]?.startDate,
      firstDemandStartDate: projectContext.demands[0]?.startDate,
      assignments: projectContext.assignments,
      allResourceAllocations: projectContext.allResourceAllocations,
      resourceIds: projectContext.resourceIds,
    });

  return buildTimelineProjectContextDetailResponse({
    project: projectContext.project,
    period,
    allocations: projectContext.allocations,
    demands: projectContext.demands,
    assignments: projectContext.assignments,
    allResourceAllocations: projectContext.allResourceAllocations,
    resourceIds: projectContext.resourceIds,
    assignmentConflicts,
    holidayOverlays,
    directory,
  });
}

export async function readTimelineProjectShiftPreviewDetail(
  db: TimelineProjectProcedureDb,
  input: {
    projectId: string;
    newStartDate: Date;
    newEndDate: Date;
  },
) {
  const [project, preview] = await Promise.all([
    findTimelineProjectOrThrow(db, {
      projectId: input.projectId,
      select: timelineShiftPreviewProjectSelect,
    }),
    previewTimelineProjectShift(db, input),
  ]);

  return buildTimelineShiftPreviewDetailResponse({
    project,
    requestedShift: {
      newStartDate: input.newStartDate,
      newEndDate: input.newEndDate,
    },
    preview,
  });
}

export async function readTimelineProjectBudgetStatusResponse(
  db: TimelineProjectProcedureDb,
  projectId: string,
) {
  const project = await findTimelineProjectOrThrow(db, {
    projectId,
    select: timelineBudgetStatusProjectSelect,
  });

  const bookings = await listAssignmentBookings(db, {
    projectIds: [project.id],
  });

  const budgetStatus = computeBudgetStatus(
    project.budgetCents,
    project.winProbability,
    buildTimelineBudgetStatusAllocations(bookings),
    project.startDate,
    project.endDate,
  );

  return buildTimelineBudgetStatusResponse({
    project,
    budgetStatus,
    totalAllocations: bookings.length,
  });
}
