import type { Prisma, PrismaClient } from "@capakraken/db";
import { buildSplitAllocationReadModel } from "./build-split-allocation-read-model.js";

type DbClient =
  | Pick<PrismaClient, "demandRequirement" | "assignment">
  | Pick<Prisma.TransactionClient, "demandRequirement" | "assignment">;

export interface CountPlanningEntriesInput {
  projectIds?: string[];
  roleIds?: string[];
}

export interface CountPlanningEntriesResult {
  countsByProjectId: Map<string, number>;
  countsByRoleId: Map<string, number>;
  totalCount: number;
}

function normalizeIds(ids?: string[]): string[] | undefined {
  if (!ids) {
    return undefined;
  }

  const normalized = [...new Set(ids.filter(Boolean))];
  return normalized.length > 0 ? normalized : undefined;
}

function buildScopedWhere(input: CountPlanningEntriesInput) {
  const projectIds = normalizeIds(input.projectIds);
  const roleIds = normalizeIds(input.roleIds);

  if (input.projectIds && !projectIds) {
    return null;
  }

  if (input.roleIds && !roleIds) {
    return null;
  }

  return {
    ...(projectIds ? { projectId: { in: projectIds } } : {}),
    ...(roleIds ? { roleId: { in: roleIds } } : {}),
  };
}

export async function countPlanningEntries(
  db: DbClient,
  input: CountPlanningEntriesInput = {},
): Promise<CountPlanningEntriesResult> {
  const scopedWhere = buildScopedWhere(input);
  if (scopedWhere === null) {
    return {
      countsByProjectId: new Map(),
      countsByRoleId: new Map(),
      totalCount: 0,
    };
  }

  const [demandRequirements, assignments] = await Promise.all([
    db.demandRequirement.findMany({
      where: scopedWhere,
      select: {
        id: true,

        projectId: true,
        startDate: true,
        endDate: true,
        hoursPerDay: true,
        percentage: true,
        role: true,
        roleId: true,
        headcount: true,
        status: true,
        metadata: true,
        createdAt: true,
        updatedAt: true,
      },
    }),
    db.assignment.findMany({
      where: scopedWhere,
      select: {
        id: true,

        demandRequirementId: true,
        resourceId: true,
        projectId: true,
        startDate: true,
        endDate: true,
        hoursPerDay: true,
        percentage: true,
        role: true,
        roleId: true,
        dailyCostCents: true,
        status: true,
        metadata: true,
        createdAt: true,
        updatedAt: true,
      },
    }),
  ]);

  const readModel = buildSplitAllocationReadModel({
    demandRequirements,
    assignments,
  });

  const countsByProjectId = new Map<string, number>();
  const countsByRoleId = new Map<string, number>();

  for (const allocation of readModel.allocations) {
    countsByProjectId.set(
      allocation.projectId,
      (countsByProjectId.get(allocation.projectId) ?? 0) + 1,
    );

    if (allocation.roleId) {
      countsByRoleId.set(
        allocation.roleId,
        (countsByRoleId.get(allocation.roleId) ?? 0) + 1,
      );
    }
  }

  return {
    countsByProjectId,
    countsByRoleId,
    totalCount: readModel.allocations.length,
  };
}
