import { Prisma } from "@capakraken/db";
import {
  PROJECT_PLANNING_DEMAND_INCLUDE,
  TIMELINE_ASSIGNMENT_INCLUDE,
} from "./project-planning-read-model.js";
import type { TimelineEntriesDbClient, TimelineEntriesFilters } from "./timeline-read-shared.js";

export async function resolveTimelineEntryResourceIds(
  db: TimelineEntriesDbClient,
  input: Pick<TimelineEntriesFilters, "resourceIds" | "chapters" | "eids" | "countryCodes">,
): Promise<string[] | undefined> {
  if (input.resourceIds && input.resourceIds.length > 0) {
    return input.resourceIds;
  }

  const hasChapters = !!input.chapters?.length;
  const hasEids = !!input.eids?.length;
  const hasCountry = !!input.countryCodes?.length;
  if (!hasChapters && !hasEids && !hasCountry) {
    return undefined;
  }

  const andConditions: Record<string, unknown>[] = [];
  if (hasChapters) {
    andConditions.push({ chapter: { in: input.chapters } });
  }
  if (hasEids) {
    andConditions.push({ eid: { in: input.eids } });
  }
  if (hasCountry) {
    andConditions.push({ country: { code: { in: input.countryCodes } } });
  }

  const matching = await db.resource.findMany({
    where: (andConditions.length === 1 ? andConditions[0]! : { AND: andConditions }) as Prisma.ResourceWhereInput,
    select: { id: true },
  });

  return matching.map((resource) => resource.id);
}

export async function resolveTimelineEntryProjectIds(
  db: TimelineEntriesDbClient,
  input: Pick<TimelineEntriesFilters, "projectIds" | "clientIds">,
): Promise<string[] | undefined> {
  if (!input.clientIds?.length) {
    return input.projectIds;
  }

  const matchingProjects = await db.project.findMany({
    where: { clientId: { in: input.clientIds } },
    select: { id: true },
  });
  const clientProjectIds = matchingProjects.map((project) => project.id);

  if (!input.projectIds?.length) {
    return clientProjectIds;
  }

  const allowedIds = new Set(clientProjectIds);
  return input.projectIds.filter((projectId) => allowedIds.has(projectId));
}

export async function loadTimelineEntryRecords(
  db: TimelineEntriesDbClient,
  input: TimelineEntriesFilters,
) {
  const effectiveResourceIds = await resolveTimelineEntryResourceIds(db, input);
  const effectiveProjectIds = await resolveTimelineEntryProjectIds(db, input);
  const excludeDemands = effectiveResourceIds !== undefined;

  const [demandRequirements, assignments] = await Promise.all([
    excludeDemands
      ? Promise.resolve([])
      : db.demandRequirement.findMany({
          where: {
            status: { not: "CANCELLED" },
            startDate: { lte: input.endDate },
            endDate: { gte: input.startDate },
            ...(effectiveProjectIds ? { projectId: { in: effectiveProjectIds } } : {}),
          },
          include: PROJECT_PLANNING_DEMAND_INCLUDE,
          orderBy: [{ startDate: "asc" }, { projectId: "asc" }],
        }),
    db.assignment.findMany({
      where: {
        status: { not: "CANCELLED" },
        startDate: { lte: input.endDate },
        endDate: { gte: input.startDate },
        ...(effectiveResourceIds ? { resourceId: { in: effectiveResourceIds } } : {}),
        ...(effectiveProjectIds ? { projectId: { in: effectiveProjectIds } } : {}),
      },
      include: TIMELINE_ASSIGNMENT_INCLUDE,
      orderBy: [{ startDate: "asc" }, { resourceId: "asc" }],
    }),
  ]);

  return { demandRequirements, assignments };
}
