import { TRPCError } from "@trpc/server";
import {
  buildTimelineProjectAssignmentConflicts,
} from "./timeline-project-conflict-support.js";
import {
  formatHolidayOverlays,
  loadTimelineHolidayOverlays,
} from "./timeline-holiday-read.js";
import {
  createTimelineDateRange,
  fmtDate,
  toDate,
} from "./timeline-read-shared.js";

export interface ResolveTimelineProjectContextPeriodInput {
  requestedStartDate?: string | undefined;
  requestedEndDate?: string | undefined;
  durationDays?: number | undefined;
  projectStartDate?: Date | null | undefined;
  projectEndDate?: Date | null | undefined;
  firstAssignmentStartDate?: Date | string | null | undefined;
  firstDemandStartDate?: Date | string | null | undefined;
}

export function resolveTimelineProjectContextPeriod(
  input: ResolveTimelineProjectContextPeriodInput,
) {
  const startDate = input.requestedStartDate
    ? createTimelineDateRange({
        startDate: input.requestedStartDate,
        durationDays: 1,
      }).startDate
    : input.projectStartDate
      ?? (input.firstAssignmentStartDate ? toDate(input.firstAssignmentStartDate) : null)
      ?? (input.firstDemandStartDate ? toDate(input.firstDemandStartDate) : null)
      ?? createTimelineDateRange({ durationDays: 1 }).startDate;

  const endDate = input.requestedEndDate
    ? createTimelineDateRange({
        startDate: fmtDate(startDate) ?? undefined,
        endDate: input.requestedEndDate,
      }).endDate
    : input.projectEndDate
      ?? createTimelineDateRange({
          startDate: fmtDate(startDate) ?? undefined,
          durationDays: input.durationDays ?? 21,
        }).endDate;

  if (endDate < startDate) {
    throw new TRPCError({
      code: "BAD_REQUEST",
      message: "endDate must be on or after startDate.",
    });
  }

  return { startDate, endDate };
}

export async function loadTimelineProjectContextDetailArtifacts(
  db: Parameters<typeof loadTimelineHolidayOverlays>[0],
  input: {
    projectId: string;
    requestedStartDate?: string | undefined;
    requestedEndDate?: string | undefined;
    durationDays?: number | undefined;
    projectStartDate?: Date | null | undefined;
    projectEndDate?: Date | null | undefined;
    firstAssignmentStartDate?: Date | string | null | undefined;
    firstDemandStartDate?: Date | string | null | undefined;
    assignments: Array<{
      id: string;
      resourceId: string | null;
      resource?: { displayName?: string | null } | null;
      startDate: Date | string;
      endDate: Date | string;
      hoursPerDay: number;
    }>;
    allResourceAllocations: Array<{
      id: string;
      resourceId: string | null;
      projectId: string | null;
      project?: { name?: string | null; shortCode?: string | null } | null;
      startDate: Date | string;
      endDate: Date | string;
      hoursPerDay: number;
      status: string;
    }>;
    resourceIds: string[];
  },
) {
  const period = resolveTimelineProjectContextPeriod({
    requestedStartDate: input.requestedStartDate,
    requestedEndDate: input.requestedEndDate,
    durationDays: input.durationDays,
    projectStartDate: input.projectStartDate,
    projectEndDate: input.projectEndDate,
    firstAssignmentStartDate: input.firstAssignmentStartDate,
    firstDemandStartDate: input.firstDemandStartDate,
  });

  const holidayOverlays = input.resourceIds.length > 0
    ? formatHolidayOverlays(await loadTimelineHolidayOverlays(db, {
        startDate: period.startDate,
        endDate: period.endDate,
        resourceIds: input.resourceIds,
        projectIds: [input.projectId],
      }))
    : [];

  const assignmentConflicts = buildTimelineProjectAssignmentConflicts({
    projectId: input.projectId,
    assignments: input.assignments,
    allResourceAllocations: input.allResourceAllocations,
  });

  return {
    period,
    holidayOverlays,
    assignmentConflicts,
  };
}
