import type { Prisma } from "@capakraken/db";
import { DispoImportSourceKind, StagedRecordStatus } from "@capakraken/db";
import { parseDispoRosterWorkbook } from "./parse-dispo-roster-workbook.js";
import {
  ensureImportBatch,
  finalizeImportBatchStage,
  getWorkbookFileName,
  type DispoImportDbClient,
  type DispoRosterImportInput,
} from "./shared.js";

export interface StageDispoRosterResourcesResult {
  batchId: string;
  counts: {
    excludedResources: number;
    ignoredPseudoDemandRows: number;
    stagedResources: number;
    unresolved: number;
    warnings: number;
  };
  excludedCanonicalExternalIds: string[];
}

export async function stageDispoRosterResources(
  db: DispoImportDbClient,
  input: DispoRosterImportInput,
): Promise<StageDispoRosterResourcesResult> {
  const batchInput: {
    importBatchId?: string;
    notes?: string | null;
  } = {};
  if (input.importBatchId !== undefined) {
    batchInput.importBatchId = input.importBatchId;
  }
  if (input.notes !== undefined) {
    batchInput.notes = input.notes;
  }

  const batch = await ensureImportBatch(db, batchInput);
  const parsed = await parseDispoRosterWorkbook(input.rosterWorkbookPath, {
    ...(input.costWorkbookPath ? { costWorkbookPath: input.costWorkbookPath } : {}),
  });
  const sourceWorkbook = getWorkbookFileName(input.rosterWorkbookPath);

  await db.stagedResource.deleteMany({
    where: {
      importBatchId: batch.id,
      sourceKind: DispoImportSourceKind.ROSTER,
    },
  });

  if (parsed.resources.length > 0) {
    await db.stagedResource.createMany({
      data: parsed.resources.map((resource) => ({
        importBatchId: batch.id,
        status: resource.warnings.length > 0
          ? StagedRecordStatus.PARSED
          : StagedRecordStatus.NORMALIZED,
        sourceKind: DispoImportSourceKind.ROSTER,
        sourceWorkbook,
        sourceSheet: resource.sourceSheet,
        sourceRow: resource.sourceRow,
        canonicalExternalId: resource.canonicalExternalId,
        enterpriseId: resource.enterpriseId,
        eid: resource.eid,
        displayName: resource.displayName,
        email: resource.email,
        chapter: resource.chapter,
        chapterCode: resource.chapterCode,
        managementLevelGroupName: resource.managementLevelGroupName,
        managementLevelName: resource.managementLevelName,
        countryCode: resource.countryCode,
        metroCityName: resource.metroCityName,
        clientUnitName: resource.clientUnitName,
        resourceType: resource.resourceType,
        chargeabilityTarget: null,
        fte: resource.fte,
        lcrCents: resource.lcrCents,
        ucrCents: resource.ucrCents,
        availability: resource.availability,
        roleTokens: resource.roleTokens,
        warnings: resource.warnings,
        rawPayload: {
          dailyWorkingHoursPerFte: resource.dailyWorkingHoursPerFte,
          department: resource.department,
          firstDayInDispo: resource.firstDayInDispo?.toISOString() ?? null,
          lastDayInDispo: resource.lastDayInDispo?.toISOString() ?? null,
          mainSkillset: resource.mainSkillset,
          rawResourceType: resource.rawResourceType,
          resourceHoursPerWeek: resource.resourceHoursPerWeek,
          rateResolution: resource.rateResolution,
          rateResolutionLevel: resource.rateResolutionLevel,
          sapEmployeeName: resource.sapEmployeeName,
          sapOrgUnitLevelFive: resource.sapOrgUnitLevelFive,
          sapOrgUnitLevelSix: resource.sapOrgUnitLevelSix,
          sapOrgUnitLevelSeven: resource.sapOrgUnitLevelSeven,
          vacationDaysPerYear: resource.vacationDaysPerYear,
        } as Prisma.InputJsonValue,
        normalizedData: {
          chapter: resource.chapter,
          chapterCode: resource.chapterCode,
          clientUnitName: resource.clientUnitName,
          countryCode: resource.countryCode,
          department: resource.department,
          email: resource.email,
          fte: resource.fte,
          managementLevelGroupName: resource.managementLevelGroupName,
          managementLevelName: resource.managementLevelName,
          metroCityName: resource.metroCityName,
          roleTokens: resource.roleTokens,
          lcrCents: resource.lcrCents,
          ucrCents: resource.ucrCents,
          rateResolution: resource.rateResolution,
          rateResolutionLevel: resource.rateResolutionLevel,
        } as Prisma.InputJsonValue,
      })),
    });
  }

  await db.stagedUnresolvedRecord.deleteMany({
    where: {
      importBatchId: batch.id,
      sourceKind: DispoImportSourceKind.ROSTER,
    },
  });

  if (parsed.unresolved.length > 0) {
    await db.stagedUnresolvedRecord.createMany({
      data: parsed.unresolved.map((record) => ({
        importBatchId: batch.id,
        status: StagedRecordStatus.UNRESOLVED,
        sourceKind: DispoImportSourceKind.ROSTER,
        sourceWorkbook,
        sourceSheet: record.sourceRow >= 3 && record.sourceColumn === "C" ? "SAP_data" : "DispoRoster",
        sourceRow: record.sourceRow,
        sourceColumn: record.sourceColumn ?? null,
        recordType: record.recordType,
        resourceExternalId: record.resourceExternalId ?? null,
        projectKey: record.projectKey ?? null,
        message: record.message,
        resolutionHint: record.resolutionHint ?? null,
        warnings: record.warnings,
        rawPayload: {} as Prisma.InputJsonValue,
        normalizedData: record.normalizedData as Prisma.InputJsonValue,
      })),
    });
  }

  const warningCount =
    parsed.warnings.length +
    parsed.resources.reduce((count, resource) => count + resource.warnings.length, 0);
  const summary = {
    stagedResources: parsed.resources.length,
    unresolved: parsed.unresolved.length,
    warnings: warningCount,
    excludedResources: parsed.excludedCanonicalExternalIds.length,
    ignoredPseudoDemandRows: parsed.ignoredPseudoDemandRows,
  };

  await finalizeImportBatchStage(db, {
    batchId: batch.id,
    existingSummary: batch.summary,
    key: "roster",
    summary,
  });

  return {
    batchId: batch.id,
    counts: summary,
    excludedCanonicalExternalIds: parsed.excludedCanonicalExternalIds,
  };
}
