import { anonymizeResource, getAnonymizationDirectory } from "../lib/anonymization.js";
import { fmtDate, type TimelineEntriesFilters } from "./timeline-read-shared.js";

type TimelineAnonymizationDirectory = Awaited<ReturnType<typeof getAnonymizationDirectory>>;

export function anonymizeResourceOnEntry<T extends { resource?: { id: string } | null }>(
  entry: T,
  directory: TimelineAnonymizationDirectory,
): T {
  if (!entry.resource) {
    return entry;
  }
  return {
    ...entry,
    resource: anonymizeResource(entry.resource, directory),
  };
}

export function buildTimelineEntriesViewResponse<
  TReadModel extends {
    allocations: Array<{ resource?: { id: string } | null }>;
    assignments: Array<{ resource?: { id: string } | null }>;
  },
>(
  readModel: TReadModel,
  directory: TimelineAnonymizationDirectory,
): TReadModel {
  return {
    ...readModel,
    allocations: readModel.allocations.map((allocation) =>
      anonymizeResourceOnEntry(allocation, directory),
    ),
    assignments: readModel.assignments.map((assignment) =>
      anonymizeResourceOnEntry(assignment, directory),
    ),
  };
}

export function summarizeTimelineEntries(readModel: {
  allocations: Array<{ projectId: string | null; resourceId: string | null }>;
  demands: Array<{ projectId: string | null }>;
  assignments: Array<{ projectId: string | null; resourceId: string | null }>;
}) {
  const projectIds = new Set<string>();
  const resourceIds = new Set<string>();

  for (const entry of [...readModel.allocations, ...readModel.demands, ...readModel.assignments]) {
    if (entry.projectId) {
      projectIds.add(entry.projectId);
    }
  }

  for (const assignment of [...readModel.allocations, ...readModel.assignments]) {
    if (assignment.resourceId) {
      resourceIds.add(assignment.resourceId);
    }
  }

  return {
    allocationCount: readModel.allocations.length,
    demandCount: readModel.demands.length,
    assignmentCount: readModel.assignments.length,
    projectCount: projectIds.size,
    resourceCount: resourceIds.size,
  };
}

export function buildTimelineEntriesDetailResponse<
  TReadModel extends {
    allocations: Array<{
      projectId: string | null;
      resourceId: string | null;
      resource?: { id: string } | null;
    }>;
    demands: Array<{ projectId: string | null }>;
    assignments: Array<{
      projectId: string | null;
      resourceId: string | null;
      resource?: { id: string } | null;
    }>;
  },
  THolidayOverlay,
>(input: {
  period: { startDate: Date; endDate: Date };
  filters: Omit<TimelineEntriesFilters, "startDate" | "endDate">;
  readModel: TReadModel;
  directory: TimelineAnonymizationDirectory;
  holidayOverlays: THolidayOverlay[];
  holidaySummary: {
    overlayCount: number;
    holidayResourceCount: number;
    byScope: Array<{ scope: string; count: number }>;
  };
}) {
  const view = buildTimelineEntriesViewResponse(input.readModel, input.directory);

  return {
    period: {
      startDate: fmtDate(input.period.startDate),
      endDate: fmtDate(input.period.endDate),
    },
    filters: input.filters,
    summary: {
      ...summarizeTimelineEntries(input.readModel),
      ...input.holidaySummary,
    },
    allocations: view.allocations,
    demands: input.readModel.demands,
    assignments: view.assignments,
    holidayOverlays: input.holidayOverlays,
  };
}
