import { ok, err, type CommandContext } from "@tailor-platform/erp-kit/module";
import type { Transaction } from "../generated/kysely-tailordb";
import {
  PeriodCloseNotFoundError,
  InvalidStatusTransitionError,
  PendingSubledgerTransactionsError,
} from "../lib/errors.generated";

export interface VerifySubledgerTransfersInput {
  id: string;
}

interface SubledgerVerificationResult {
  module: string;
  journalType: string;
  pendingCount: number;
  reconciled: boolean;
}

const SUBLEDGER_MODULES: { module: string; journalType: string }[] = [
  { module: "purchase", journalType: "PURCHASE" },
  { module: "sales", journalType: "SALES" },
  { module: "inventory", journalType: "MISCELLANEOUS" },
  { module: "manufacturing", journalType: "MISCELLANEOUS" },
];

const SUBLEDGERS_VERIFIED_COMPLETION_PERCENTAGE = 25;

/**
 * Function: verifySubledgerTransfers
 *
 * Checks that all registered subledger modules have completed their
 * transaction transfers to the general ledger for the closing period.
 * If all subledgers are reconciled, the PeriodClose transitions from
 * IN_PROGRESS to SUBLEDGERS_VERIFIED.
 */
export async function run(
  db: Transaction,
  input: VerifySubledgerTransfersInput,
  ctx: CommandContext,
) {
  const { id } = input;

  // 1. Find PeriodClose record
  const periodClose = await db
    .selectFrom("PeriodClose")
    .selectAll()
    .where("id", "=", id)
    .forUpdate()
    .executeTakeFirst();

  if (!periodClose) {
    return err(new PeriodCloseNotFoundError(id));
  }

  // 2. Validate PeriodClose is in IN_PROGRESS status
  if (periodClose.status !== "IN_PROGRESS") {
    return err(new InvalidStatusTransitionError(id));
  }

  // 3. Check all registered subledger modules for pending unposted transactions
  const verificationResults: SubledgerVerificationResult[] = [];

  for (const subledger of SUBLEDGER_MODULES) {
    const pendingEntries = await db
      .selectFrom("JournalEntry")
      .selectAll()
      .where("accountingPeriodId", "=", periodClose.accountingPeriodId)
      .where("journalType", "=", subledger.journalType as "PURCHASE" | "SALES" | "MISCELLANEOUS")
      .where("status", "=", "DRAFT")
      .execute();

    verificationResults.push({
      module: subledger.module,
      journalType: subledger.journalType,
      pendingCount: pendingEntries.length,
      reconciled: pendingEntries.length === 0,
    });
  }

  // 4. If any subledger has pending transactions, fail
  const pendingModules = verificationResults.filter((r) => !r.reconciled);
  if (pendingModules.length > 0) {
    return err(new PendingSubledgerTransactionsError(id));
  }

  // 5. Transition PeriodClose to SUBLEDGERS_VERIFIED and update completionPercentage
  const now = new Date();
  const updatedPeriodClose = await db
    .updateTable("PeriodClose")
    .set({
      status: "SUBLEDGERS_VERIFIED",
      completionPercentage: SUBLEDGERS_VERIFIED_COMPLETION_PERCENTAGE,
      subledgerVerificationDetails: JSON.stringify(verificationResults),
      updatedAt: now,
    })
    .where("id", "=", id)
    .returningAll()
    .executeTakeFirst();

  // 6. Emit audit event
  const auditEvent = {
    type: "SUBLEDGER_VERIFICATION_COMPLETED",
    actorId: ctx.actorId,
    timestamp: now,
    periodCloseId: id,
    from: "IN_PROGRESS",
    to: "SUBLEDGERS_VERIFIED",
    verificationResults,
  };

  return ok({ periodClose: updatedPeriodClose!, auditEvent });
}
