export const ACCOUNTING_SOURCE_INVENTORY_POLICY = Object.freeze([
  { source_file: "Diamond-Lot-Costs.xlsx", source_sheet: "Prepared Lots", data_path: ["lots"], role: "lots", classification: "Canonical input", owner: "Accounting", status: "Prepared" },
  { source_file: "Diamond-Lot-Costs.xlsx", source_sheet: "Cost Lines", data_path: ["costLines"], role: "costs", classification: "Support input", owner: "Cost Accounting", status: "Prepared" },
  { source_file: "Diamond-Lot-Costs.xlsx", source_sheet: "Document Register", data_path: ["documentRegister"], role: "documents", classification: "Support input", owner: "Accounting Control", status: "Prepared" },
  { source_file: "Sales-and-AR.xlsx", source_sheet: "Invoices", data_path: ["invoices"], role: "invoices", classification: "Canonical input", owner: "Accounts Receivable", status: "Prepared" },
  { source_file: "Sales-and-AR.xlsx", source_sheet: "Payments", data_path: ["payments"], role: "payments", classification: "Canonical input", owner: "Treasury Training", status: "Prepared" },
  { source_file: "Accounting-KPI-Definitions.xlsx", source_sheet: "Data Dictionary", data_path: ["kpiDefinitions", "fields"], role: "dictionary", classification: "Configuration", owner: "Accounting Data Owner", status: "Prepared" },
  { source_file: "Accounting-KPI-Definitions.xlsx", source_sheet: "Mapping", data_path: ["mappings"], role: "mapping", classification: "Configuration", owner: "Accounting Data Owner", status: "Prepared" },
  { source_file: "Accounting-KPI-Definitions.xlsx", source_sheet: "Metrics", data_path: ["metricDefinitions"], role: "definitions", classification: "Configuration", owner: "Finance", status: "Prepared" },
  { source_file: "Accounting-KPI-Definitions.xlsx", source_sheet: "Controls", data_path: ["kpiDefinitions", "control_rows"], role: "controls", classification: "Configuration", owner: "Accounting Data Owner", status: "Prepared" },
].map((entry) => Object.freeze({ ...entry, data_path: Object.freeze([...entry.data_path]) })));

function inventoryKey(sourceFile, sourceSheet) {
  return `${String(sourceFile ?? "")}\u0000${String(sourceSheet ?? "")}`;
}

function inventoryCount(value, sourceFile, sourceSheet) {
  const count = Number(value);
  if (!Number.isInteger(count) || count < 0) {
    throw new TypeError(`Invalid row count for ${sourceFile}|${sourceSheet}`);
  }
  return count;
}

function publicInventoryRow(policy, rows) {
  const fields = { ...policy };
  delete fields.data_path;
  return { ...fields, rows };
}

export function applyAccountingInventoryPolicy(rows) {
  if (!Array.isArray(rows)) throw new TypeError("inventory rows must be an array");
  const policyKeys = new Set(ACCOUNTING_SOURCE_INVENTORY_POLICY.map((policy) => inventoryKey(policy.source_file, policy.source_sheet)));
  const bySource = new Map();
  const unlisted = [];
  const seenUnlisted = new Set();
  for (const row of rows) {
    const sourceFile = row?.source_file ?? row?.file;
    const sourceSheet = row?.source_sheet ?? row?.sheet;
    if (String(sourceSheet ?? "").trim().toLowerCase() === "source inventory") continue;
    const key = inventoryKey(sourceFile, sourceSheet);
    if (policyKeys.has(key)) {
      if (!bySource.has(key)) bySource.set(key, row);
      continue;
    }
    if (seenUnlisted.has(key)) continue;
    seenUnlisted.add(key);
    const count = inventoryCount(row?.rows ?? row?.row_count, sourceFile, sourceSheet);
    const fields = { ...(row ?? {}) };
    delete fields.file;
    delete fields.sheet;
    delete fields.row_count;
    unlisted.push({ ...fields, source_file: String(sourceFile ?? ""), source_sheet: String(sourceSheet ?? ""), rows: count });
  }
  const canonical = ACCOUNTING_SOURCE_INVENTORY_POLICY.flatMap((policy) => {
    const row = bySource.get(inventoryKey(policy.source_file, policy.source_sheet));
    if (!row) return [];
    const count = inventoryCount(row.rows ?? row.row_count, policy.source_file, policy.source_sheet);
    return [publicInventoryRow(policy, count)];
  });
  return [...canonical, ...unlisted];
}

export function buildAccountingSourceInventory(data) {
  if (!data || typeof data !== "object") throw new TypeError("accounting data must be an object");
  return ACCOUNTING_SOURCE_INVENTORY_POLICY.map((policy) => {
    let sourceRows = data;
    for (const field of policy.data_path) sourceRows = sourceRows?.[field];
    if (!Array.isArray(sourceRows)) {
      throw new TypeError(`Missing row source for ${policy.source_file}|${policy.source_sheet}`);
    }
    return publicInventoryRow(policy, sourceRows.length);
  });
}
