import type { TFunction } from "i18next";
import type { MasterDataIssue } from "@/app/api/masterDataIssues";
import {
  bomLabelForCode,
  formatBomLabel,
  formatItemLabel,
  type MasterDataIssueGroup,
} from "./groupMasterDataIssues";

export interface MasterDataDetailRow {
  key: string;
  bomLabel: string | null;
  problem: string;
  expected: string | null;
  actual: string | null;
}

const MISSING_UNIT_CODES = [
  "MISSING_BASE_UOM",
  "MISSING_SALES_UOM",
  "MISSING_STOCK_UOM",
  "MISSING_PICKING_UOM",
  "MISSING_PURCHASE_UOM",
] as const;

function unitShortName(issueCode: string, t: TFunction): string {
  const map: Record<string, string> = {
    MISSING_BASE_UOM: t("masterDataIssue_unit_base"),
    MISSING_SALES_UOM: t("masterDataIssue_unit_sales"),
    MISSING_STOCK_UOM: t("masterDataIssue_unit_stock"),
    MISSING_PICKING_UOM: t("masterDataIssue_unit_picking"),
    MISSING_PURCHASE_UOM: t("masterDataIssue_unit_purchase"),
    MISSING_BASE_UOM_CONVERSION: t("masterDataIssue_unit_base"),
    MISSING_SALES_UOM_CONVERSION: t("masterDataIssue_unit_sales"),
    MISSING_STOCK_UOM_CONVERSION: t("masterDataIssue_unit_stock"),
    MISSING_PICKING_UOM_CONVERSION: t("masterDataIssue_unit_picking"),
    MISSING_PURCHASE_UOM_CONVERSION: t("masterDataIssue_unit_purchase"),
    MULTIPLE_BASE_UOM: t("masterDataIssue_unit_base"),
    MULTIPLE_SALES_UOM: t("masterDataIssue_unit_sales"),
    MULTIPLE_STOCK_UOM: t("masterDataIssue_unit_stock"),
    MULTIPLE_PICKING_UOM: t("masterDataIssue_unit_picking"),
    MULTIPLE_PURCHASE_UOM: t("masterDataIssue_unit_purchase"),
  };
  return map[issueCode] ?? issueCode;
}

function groupIssuesByBom(issues: MasterDataIssue[]): Map<string, MasterDataIssue[]> {
  const map = new Map<string, MasterDataIssue[]>();
  for (const row of issues) {
    const bom = row.bomCode?.trim() || (row.bomId != null ? `BOM#${row.bomId}` : "-");
    const list = map.get(bom) ?? [];
    list.push(row);
    map.set(bom, list);
  }
  return map;
}

/** UOM mismatch lines without BOM prefix (for material groups). */
function uomPairLines(
  rows: MasterDataIssue[],
  t: TFunction,
): string[] {
  const lines: string[] = [];
  const sales = rows.find((r) => r.issueCode === "BOM_MATERIAL_SALES_UOM_MISMATCH");
  const stock = rows.find((r) => r.issueCode === "BOM_MATERIAL_STOCK_UOM_MISMATCH");
  const base = rows.find((r) => r.issueCode === "BOM_MATERIAL_BASE_UOM_MISMATCH");

  if (
    sales &&
    stock &&
    sales.expectedValue === stock.expectedValue &&
    sales.actualValue === stock.actualValue
  ) {
    lines.push(
      t("masterDataIssue_line_pairBoth", {
        expected: sales.expectedValue ?? "-",
        actual: sales.actualValue ?? "-",
      }),
    );
  } else {
    if (sales) {
      lines.push(
        t("masterDataIssue_line_pairSales", {
          expected: sales.expectedValue ?? "-",
          actual: sales.actualValue ?? "-",
        }),
      );
    }
    if (stock) {
      lines.push(
        t("masterDataIssue_line_pairStock", {
          expected: stock.expectedValue ?? "-",
          actual: stock.actualValue ?? "-",
        }),
      );
    }
  }

  if (base) {
    lines.push(
      t("masterDataIssue_line_pairBase", {
        expected: base.expectedValue ?? "-",
        actual: base.actualValue ?? "-",
      }),
    );
  }

  return lines;
}

function linesForBomHeaderRows(
  bomCode: string,
  rows: MasterDataIssue[],
  t: TFunction,
  issueMessage: (code: string) => string,
): string[] {
  const lines: string[] = [];
  const used = new Set<MasterDataIssue>();

  const output = rows.find((r) => r.issueCode === "BOM_OUTPUT_UOM_MISMATCH_SALES");
  if (output) {
    lines.push(
      t("masterDataIssue_line_outputUom", {
        bom: bomCode,
        expected: output.expectedValue ?? "-",
        actual: output.actualValue ?? "-",
      }),
    );
    used.add(output);
  }

  const drift = rows.find((r) => r.issueCode === "BOM_OUTPUT_UOM_TEXT_DRIFT");
  if (drift) {
    lines.push(
      t("masterDataIssue_line_outputText", {
        bom: bomCode,
        expected: drift.expectedValue ?? "-",
        actual: drift.actualValue ?? "-",
      }),
    );
    used.add(drift);
  }

  const missing = rows.filter((r) =>
    MISSING_UNIT_CODES.includes(r.issueCode as (typeof MISSING_UNIT_CODES)[number]),
  );
  if (missing.length > 0) {
    const names = Array.from(new Set(missing.map((r) => unitShortName(r.issueCode, t))));
    lines.push(t("masterDataIssue_line_missingUnits", { bom: bomCode, units: names.join("、") }));
    missing.forEach((r) => used.add(r));
  }

  for (const row of rows) {
    if (used.has(row)) continue;
    const short = issueMessage(row.issueCode);
    if (row.expectedValue != null || row.actualValue != null) {
      lines.push(
        t("masterDataIssue_line_generic", {
          bom: bomCode,
          problem: short,
          expected: row.expectedValue ?? "-",
          actual: row.actualValue ?? "-",
        }),
      );
    } else {
      lines.push(t("masterDataIssue_line_problemOnly", { bom: bomCode, problem: short }));
    }
    used.add(row);
  }

  return lines;
}

/** One or more human-readable lines for the main list. */
export function buildDisplayLines(
  group: MasterDataIssueGroup,
  t: TFunction,
  issueMessage: (code: string) => string,
): string[] {
  if (group.groupType === "item") {
    const missing = group.issues.filter((r) =>
      MISSING_UNIT_CODES.includes(r.issueCode as (typeof MISSING_UNIT_CODES)[number]),
    );
    const lines: string[] = [];
    if (missing.length > 0) {
      const names = Array.from(
        new Set(missing.map((r) => unitShortName(r.issueCode, t))),
      );
      lines.push(t("masterDataIssue_line_itemMissing", { units: names.join("、") }));
    }
    const rest = group.issues.filter((r) => !missing.includes(r));
    for (const row of rest) {
      const short = issueMessage(row.issueCode);
      if (row.expectedValue != null || row.actualValue != null) {
        lines.push(
          t("masterDataIssue_line_itemGeneric", {
            problem: short,
            expected: row.expectedValue ?? "-",
            actual: row.actualValue ?? "-",
          }),
        );
      } else {
        lines.push(short);
      }
    }
    return lines.length > 0 ? lines : [issueMessage(group.issues[0]?.issueCode ?? "")];
  }

  if (group.groupType === "bom_header") {
    const bom = group.bomCode?.trim() || formatBomLabel(group);
    return linesForBomHeaderRows(bom, group.issues, t, issueMessage);
  }

  // BOM material: one row per (material + 应为/实际); right side = pair only, BOM list on left
  const lines = uomPairLines(group.issues, t);
  const used = new Set(
    group.issues.filter((r) =>
      [
        "BOM_MATERIAL_SALES_UOM_MISMATCH",
        "BOM_MATERIAL_STOCK_UOM_MISMATCH",
        "BOM_MATERIAL_BASE_UOM_MISMATCH",
      ].includes(r.issueCode),
    ),
  );

  for (const row of group.issues) {
    if (used.has(row)) continue;
    lines.push(issueMessage(row.issueCode));
  }

  return lines.length > 0 ? lines : [issueMessage(group.issues[0]?.issueCode ?? "")];
}

/** Subtitle under material title: BOM codes sharing this problem. */
export function materialBomSubtitle(
  group: MasterDataIssueGroup,
  t: TFunction,
): string | null {
  if (group.groupType !== "bom_material" || group.relatedBomLabels.length === 0) {
    return null;
  }
  return t("masterDataIssue_materialUsedInBom", {
    codes: group.relatedBomLabels.join("、"),
  });
}

/** Merged rows for the detail dialog (4 columns). */
export function buildDetailRows(
  group: MasterDataIssueGroup,
  t: TFunction,
  issueMessage: (code: string) => string,
): MasterDataDetailRow[] {
  if (group.groupType === "item") {
    const lines = buildDisplayLines(group, t, issueMessage);
    return lines.map((text, i) => ({
      key: `item-${i}`,
      bomLabel: null,
      problem: text,
      expected: null,
      actual: null,
    }));
  }

  const rows: MasterDataDetailRow[] = [];
  const byBom = groupIssuesByBom(group.issues);

  for (const [bomCode, bomIssues] of Array.from(byBom.entries())) {
    const bomLabel = bomLabelForCode(group.issues, bomCode);
    const used = new Set<MasterDataIssue>();
    const sales = bomIssues.find((r: MasterDataIssue) => r.issueCode === "BOM_MATERIAL_SALES_UOM_MISMATCH");
    const stock = bomIssues.find((r: MasterDataIssue) => r.issueCode === "BOM_MATERIAL_STOCK_UOM_MISMATCH");
    const base = bomIssues.find((r: MasterDataIssue) => r.issueCode === "BOM_MATERIAL_BASE_UOM_MISMATCH");

    if (
      sales &&
      stock &&
      sales.expectedValue === stock.expectedValue &&
      sales.actualValue === stock.actualValue
    ) {
      rows.push({
        key: `${bomCode}-uom-both`,
        bomLabel,
        problem: t("masterDataIssue_detail_uomBoth"),
        expected: sales.expectedValue,
        actual: sales.actualValue,
      });
      used.add(sales);
      used.add(stock);
    } else {
      if (sales) {
        rows.push({
          key: `${bomCode}-sales`,
          bomLabel,
          problem: t("masterDataIssue_detail_uomSales"),
          expected: sales.expectedValue,
          actual: sales.actualValue,
        });
        used.add(sales);
      }
      if (stock) {
        rows.push({
          key: `${bomCode}-stock`,
          bomLabel,
          problem: t("masterDataIssue_detail_uomStock"),
          expected: stock.expectedValue,
          actual: stock.actualValue,
        });
        used.add(stock);
      }
    }

    if (base) {
      rows.push({
        key: `${bomCode}-base`,
        bomLabel,
        problem: t("masterDataIssue_detail_uomBase"),
        expected: base.expectedValue,
        actual: base.actualValue,
      });
      used.add(base);
    }

    const output = bomIssues.find((r) => r.issueCode === "BOM_OUTPUT_UOM_MISMATCH_SALES");
    if (output) {
      rows.push({
        key: `${bomCode}-output`,
        bomLabel,
        problem: issueMessage(output.issueCode),
        expected: output.expectedValue,
        actual: output.actualValue,
      });
      used.add(output);
    }

    for (const row of bomIssues) {
      if (used.has(row)) continue;
      rows.push({
        key: `${bomCode}-${row.issueCode}-${row.bomMaterialId}`,
        bomLabel,
        problem: issueMessage(row.issueCode),
        expected: row.expectedValue,
        actual: row.actualValue,
      });
    }
  }

  if (rows.length > 0) return rows;

  const lines = buildDisplayLines(group, t, issueMessage);
  return lines.map((text, i) => ({
    key: `fallback-${i}`,
    bomLabel: null,
    problem: text,
    expected: null,
    actual: null,
  }));
}

export function needsDetailButton(
  group: MasterDataIssueGroup,
  displayLines: string[],
): boolean {
  if (group.groupType === "bom_material") {
    return true;
  }
  if (group.groupType === "bom_header") {
    if (displayLines.length > 1) return true;
    if (group.issues.length > 2) return true;
    return false;
  }
  if (displayLines.length > 1) return true;
  if (group.issues.length > 2) return true;
  return false;
}

export function primaryTitle(group: MasterDataIssueGroup): string {
  if (group.groupType === "bom_header") return formatBomLabel(group);
  const code = group.itemCode?.trim();
  const name = group.itemName?.trim();
  if (code && name) return `${code} · ${name}`;
  return formatItemLabel(group);
}
