import { ok, err, type ReadonlyDB } from "@tailor-platform/erp-kit/module";
import type { DB } from "../generated/kysely-tailordb";
import { AccountingPeriodNotFoundError } from "../lib/errors.generated";

export interface GetSubledgerTransferStatusInput {
  accountingPeriodId: string;
}

interface ModuleStatus {
  module: string;
  journalType: string;
  totalExpected: number;
  acknowledged: number;
  outstanding: number;
}

const SUBLEDGER_MODULES = [
  { module: "purchase", journalType: "PURCHASE" as const },
  { module: "sales", journalType: "SALES" as const },
  { module: "inventory", journalType: "INVENTORY" as const },
  { module: "manufacturing", journalType: "MANUFACTURING" as const },
];

/**
 * Function: getSubledgerTransferStatus
 *
 * Returns transfer completeness status for all subledger modules for a given
 * accounting period. Per-module status includes: totalExpected, acknowledged,
 * outstanding. Registered modules: purchase, sales, inventory, manufacturing.
 * Returns status for all modules even if zero expected events.
 */
export async function run(db: ReadonlyDB<DB>, input: GetSubledgerTransferStatusInput) {
  // Validate that the accounting period exists
  const period = await db
    .selectFrom("AccountingPeriod")
    .selectAll()
    .where("id", "=", input.accountingPeriodId)
    .executeTakeFirst();

  if (!period) {
    return err(new AccountingPeriodNotFoundError(input.accountingPeriodId));
  }

  const statuses: ModuleStatus[] = [];

  for (const subledger of SUBLEDGER_MODULES) {
    // Count all entries of this type for the period
    const allEntries = await db
      .selectFrom("JournalEntry")
      .selectAll()
      .where("accountingPeriodId", "=", input.accountingPeriodId)
      .where("journalType", "=", subledger.journalType)
      .execute();

    const totalExpected = allEntries.length;
    const acknowledged = allEntries.filter((e) => e.status === "POSTED").length;

    statuses.push({
      module: subledger.module,
      journalType: subledger.journalType,
      totalExpected,
      acknowledged,
      outstanding: totalExpected - acknowledged,
    });
  }

  return ok({ statuses });
}
