import type { MasterDataIssue } from "@/app/api/masterDataIssues";

export type MasterDataIssueGroupType = "item" | "bom_header" | "bom_material";

export interface MasterDataIssueGroup {
  groupKey: string;
  groupType: MasterDataIssueGroupType;
  itemId: number | null;
  itemCode: string | null;
  itemName: string | null;
  bomId: number | null;
  bomCode: string | null;
  bomName: string | null;
  /** BOM codes that reference this material (bom_material groups only). */
  relatedBomCodes: string[];
  /** Formatted BOM labels (code · name) for bom_material groups. */
  relatedBomLabels: string[];
  issues: MasterDataIssue[];
}

export function formatItemLabel(row: {
  itemCode?: string | null;
  itemName?: string | null;
  itemId?: number | null;
}): string {
  const code = row.itemCode?.trim();
  const name = row.itemName?.trim();
  if (code && name) return `${code} · ${name}`;
  if (code) return code;
  if (name) return name;
  if (row.itemId != null) return `item#${row.itemId}`;
  return "-";
}

export function formatBomLabel(row: {
  bomCode?: string | null;
  bomName?: string | null;
  bomId?: number | null;
}): string {
  const code = row.bomCode?.trim();
  const name = row.bomName?.trim();
  if (code && name) return `${code} · ${name}`;
  if (code) return code;
  if (name) return name;
  if (row.bomId != null) return `BOM#${row.bomId}`;
  return "-";
}

function pickItemFields(issues: MasterDataIssue[]) {
  const first = issues[0];
  let itemCode: string | null = null;
  let itemName: string | null = null;
  for (const row of issues) {
    const code = row.itemCode?.trim();
    const name = row.itemName?.trim();
    if (code && !itemCode) itemCode = code;
    if (name) {
      if (!itemName || name.length > itemName.length) itemName = name;
    }
  }
  return {
    itemId: first.itemId,
    itemCode: itemCode ?? first.itemCode,
    itemName: itemName ?? first.itemName,
  };
}

function uniqueBomCodes(issues: MasterDataIssue[]): string[] {
  const codes = new Set<string>();
  for (const row of issues) {
    const c = row.bomCode?.trim();
    if (c) codes.add(c);
  }
  return Array.from(codes).sort((a, b) => a.localeCompare(b));
}

/** Best bomName per bomCode from issue rows. */
function bomNameByCode(issues: MasterDataIssue[]): Map<string, string | null> {
  const map = new Map<string, string | null>();
  for (const row of issues) {
    const code = row.bomCode?.trim();
    if (!code) continue;
    const name = row.bomName?.trim() || null;
    if (!map.has(code)) {
      map.set(code, name);
      continue;
    }
    const prev = map.get(code);
    if (name && (!prev || name.length > prev.length)) {
      map.set(code, name);
    }
  }
  return map;
}

function uniqueBomLabels(issues: MasterDataIssue[]): string[] {
  const names = bomNameByCode(issues);
  return uniqueBomCodes(issues).map((code) =>
    formatBomLabel({ bomCode: code, bomName: names.get(code) }),
  );
}

/** Label for one BOM code within a group's issues. */
export function bomLabelForCode(
  issues: MasterDataIssue[],
  bomCode: string,
): string {
  const code = bomCode.trim();
  const names = bomNameByCode(issues);
  return formatBomLabel({ bomCode: code, bomName: names.get(code) });
}

/** Group BOM material rows by item + same 应为/实际 (sales+stock with same pair share one key). */
function materialPatternKey(row: MasterDataIssue): string {
  const exp = row.expectedValue ?? "";
  const act = row.actualValue ?? "";
  if (
    row.issueCode === "BOM_MATERIAL_SALES_UOM_MISMATCH" ||
    row.issueCode === "BOM_MATERIAL_STOCK_UOM_MISMATCH"
  ) {
    return `uom:${exp}|${act}`;
  }
  if (row.issueCode === "BOM_MATERIAL_BASE_UOM_MISMATCH") {
    return `base:${exp}|${act}`;
  }
  return `${row.issueCode}|${exp}|${act}`;
}

function materialItemKey(row: MasterDataIssue): string {
  if (row.itemId != null) return `i:${row.itemId}`;
  return `ic:${row.itemCode?.trim() || row.bomMaterialId || "unknown"}`;
}

export function groupItemTabIssues(issues: MasterDataIssue[]): MasterDataIssueGroup[] {
  const map = new Map<string, MasterDataIssue[]>();
  for (const row of issues) {
    const key =
      row.itemId != null
        ? `item:${row.itemId}`
        : `code:${row.itemCode?.trim() || "unknown"}`;
    const list = map.get(key) ?? [];
    list.push(row);
    map.set(key, list);
  }
  return Array.from(map.entries())
    .map(([, rows]) => {
      const item = pickItemFields(rows);
      return {
        groupKey: `item:${item.itemId ?? rows[0].itemCode}`,
        groupType: "item" as const,
        ...item,
        bomId: null,
        bomCode: null,
        bomName: null,
        relatedBomCodes: [],
        relatedBomLabels: [],
        issues: rows,
      };
    })
    .sort((a, b) =>
      formatItemLabel(a).localeCompare(formatItemLabel(b), undefined, {
        sensitivity: "base",
      }),
    );
}

export function groupBomTabIssues(issues: MasterDataIssue[]): MasterDataIssueGroup[] {
  const headerMap = new Map<string, MasterDataIssue[]>();
  const materialMap = new Map<string, MasterDataIssue[]>();

  for (const row of issues) {
    if (row.scope === "BOM_MATERIAL") {
      const key = `${materialItemKey(row)}|${materialPatternKey(row)}`;
      const list = materialMap.get(key) ?? [];
      list.push(row);
      materialMap.set(key, list);
    } else {
      const key = row.bomId != null ? `bom:${row.bomId}` : `bomcode:${row.bomCode}`;
      const list = headerMap.get(key) ?? [];
      list.push(row);
      headerMap.set(key, list);
    }
  }

  const headers: MasterDataIssueGroup[] = Array.from(headerMap.entries()).map(
    ([, rows]) => {
      const first = rows[0];
      const item = pickItemFields(rows);
      return {
        groupKey: `bom:${first.bomId}`,
        groupType: "bom_header" as const,
        ...item,
        bomId: first.bomId,
        bomCode: first.bomCode,
        bomName: first.bomName,
        relatedBomCodes: [],
        relatedBomLabels: [],
        issues: rows,
      };
    },
  );

  const materials: MasterDataIssueGroup[] = Array.from(materialMap.entries()).map(
    ([key, rows]) => {
      const item = pickItemFields(rows);
      return {
        groupKey: key,
        groupType: "bom_material" as const,
        ...item,
        bomId: null,
        bomCode: null,
        bomName: null,
        relatedBomCodes: uniqueBomCodes(rows),
        relatedBomLabels: uniqueBomLabels(rows),
        issues: rows,
      };
    },
  );

  return [...headers, ...materials].sort((a, b) => {
    if (a.groupType !== b.groupType) {
      return a.groupType === "bom_header" ? -1 : 1;
    }
    if (a.groupType === "bom_material" && b.groupType === "bom_material") {
      const itemCmp = formatItemLabel(a).localeCompare(formatItemLabel(b), undefined, {
        sensitivity: "base",
      });
      if (itemCmp !== 0) return itemCmp;
      return a.groupKey.localeCompare(b.groupKey);
    }
    const labelA = formatBomLabel(a);
    const labelB = formatBomLabel(b);
    return labelA.localeCompare(labelB, undefined, { sensitivity: "base" });
  });
}

