import type { CommitDbClient } from "./commit-dispo-batch-types.js";
import { StagedRecordStatus } from "@capakraken/db";

function asObject(value: unknown): Record<string, unknown> {
  return value && typeof value === "object" && !Array.isArray(value)
    ? (value as Record<string, unknown>)
    : {};
}

function isAllowedUnresolvedRecord(
  record: Awaited<ReturnType<CommitDbClient["stagedUnresolvedRecord"]["findMany"]>>[number],
): boolean {
  const message = record.message.toLowerCase();
  const hint = (record.resolutionHint ?? "").toLowerCase();
  const rawToken = String(asObject(record.normalizedData).rawToken ?? "").toLowerCase();

  return record.recordType === "PROJECT" && (
    message.includes("[tbd]") ||
    hint.includes("[tbd]") ||
    rawToken.includes("[tbd]")
  );
}

export interface BatchValidationResult {
  batchId: string;
  batchSummary: unknown;
  blockingUnresolved: number;
  skippedTbdUnresolved: number;
}

export async function validateDispoBatch(
  db: CommitDbClient,
  input: {
    allowTbdUnresolved?: boolean;
    importBatchId: string;
    importTbdProjects?: boolean;
  },
): Promise<BatchValidationResult> {
  const batch = await db.importBatch.findUnique({
    where: { id: input.importBatchId },
    select: { id: true, status: true, summary: true },
  });

  if (!batch) {
    throw new Error(`Import batch "${input.importBatchId}" not found`);
  }

  if (!["STAGED", "REVIEW_READY", "APPROVED"].includes(batch.status)) {
    throw new Error(`Import batch "${batch.id}" is not ready to commit from status "${batch.status}"`);
  }

  const unresolved = await db.stagedUnresolvedRecord.findMany({
    where: {
      importBatchId: batch.id,
      status: StagedRecordStatus.UNRESOLVED,
    },
  });
  const stagedPublicHolidayCount = await db.stagedVacation.count({
    where: {
      importBatchId: batch.id,
      vacationType: "PUBLIC_HOLIDAY",
    },
  });
  const blockingUnresolved = unresolved.filter(
    (record) =>
      !(
        (input.allowTbdUnresolved ?? true) ||
        (input.importTbdProjects && isAllowedUnresolvedRecord(record))
      ) || !isAllowedUnresolvedRecord(record),
  );
  const skippedTbdUnresolved = unresolved.length - blockingUnresolved.length;

  if (blockingUnresolved.length > 0) {
    throw new Error(
      `Import batch "${batch.id}" still has ${blockingUnresolved.length} blocking unresolved staged record(s)`,
    );
  }

  if (stagedPublicHolidayCount > 0) {
    throw new Error(
      `Import batch "${batch.id}" still contains ${stagedPublicHolidayCount} staged PUBLIC_HOLIDAY row(s). Public holidays must be synchronized through holiday calendars before commit.`,
    );
  }

  return {
    batchId: batch.id,
    batchSummary: batch.summary,
    blockingUnresolved: blockingUnresolved.length,
    skippedTbdUnresolved,
  };
}
