type HintCategory = {
  key: string;
  title: string;
  matcher: RegExp;
  detail: string;
  defaultBullet: string;
};

const HUMAN_FIX_HINT_HEADER = "请补充以下关键信息，便于准确识别采购对象并完成询价：";
const EXCLUDED_FIELD_MATCHER = /(品牌|质保|保修|交货|交期|货期)/;
const LOW_VALUE_HINT_PATTERNS = [
  /^请人工补充明确的[\s\S]*$/,
  /^请补充决定采购对象的[\s\S]*$/,
  /^请补充关键采购字段[:：][\s\S]*$/,
];

const HINT_CATEGORIES: HintCategory[] = [
  {
    key: "material",
    title: "材质/成分",
    matcher: /(材质|成分|原料|胶种|皮质|面料|布料|纱线|基材|涂层|镀层|牌号|钢种|合金|材种|母材|芯材)/,
    detail: "并补充主体材质、成分、牌号、基材或表面处理要求。",
    defaultBullet: "请明确主体材质、成分、牌号、基材或表面处理要求，如不锈钢304、丁腈、乳胶、棉纱、牛皮、镀锌等。",
  },
  {
    key: "spec",
    title: "规格/尺寸",
    matcher: /(规格|尺寸|尺码|长度|宽度|高度|厚度|壁厚|口径|直径|外径|内径|容量|重量|净重|体积|边长|孔距|跨度|宽幅|线径|目数|粒径|管径|螺距|牙距)/,
    detail: "并补充能影响搜索和报价的核心规格参数，如尺寸、厚度、容量、重量、长度、宽度或口径。",
    defaultBullet: "请明确规格型号、尺寸、厚度、容量、重量、长度、宽度、口径等核心参数。",
  },
  {
    key: "model",
    title: "型号/等级",
    matcher: /(型号|货号|型式|款式|等级|级别|强度|精度|执行标准|标准号|国标|非标|版本|系列)/,
    detail: "并补充具体型号、货号、等级、执行标准、精度或强度等级。",
    defaultBullet: "请明确型号、货号、等级、执行标准、精度等级或强度等级。",
  },
  {
    key: "electrical",
    title: "电气/动力参数",
    matcher: /(功率|电压|电流|频率|相数|功耗|压力|流量|扬程|转速|扭矩|气压|水压|载荷|承载)/,
    detail: "并补充功率、电压、电流、频率、压力、流量、转速或扭矩等运行参数。",
    defaultBullet: "请明确功率、电压、电流、频率、压力、流量、转速、扭矩等运行参数。",
  },
  {
    key: "function",
    title: "功能/性能",
    matcher: /(功能|用途|性能|防护|防滑|防切割|耐磨|耐温|耐高温|耐低温|耐压|耐腐|耐腐蚀|阻燃|绝缘|导电|防爆|防水|防尘|密封|硬度|韧性|效率|寿命|灵敏度)/,
    detail: "并补充用途、功能要求、防护等级、耐温耐压、绝缘、防滑、防切割、精度或寿命等性能指标。",
    defaultBullet: "请明确用途、功能要求及关键性能指标，如防滑、防切割、耐磨、防油、耐高温、耐压、绝缘、精度或寿命要求。",
  },
  {
    key: "structure",
    title: "结构/接口/安装方式",
    matcher: /(结构|接口|接头|连接|螺纹|法兰|安装|固定|装配|组合|总成|左右|方向|开孔|孔位|层数|附件|配件|连接方式|安装方式|结构类型|形状)/,
    detail: "并补充结构形式、连接接口、螺纹或法兰标准、安装方式、左右件及是否含附件。",
    defaultBullet: "请明确结构形式、连接接口、螺纹或法兰标准、安装方式、左右件及是否含附件。",
  },
  {
    key: "compatibility",
    title: "适配对象/使用场景",
    matcher: /(适配|适用|配套|兼容|机型|设备|部位|工况|场景|介质|对象|工位|位置|系统|平台|车型|适用范围|施工部位)/,
    detail: "并补充适配设备、使用部位、施工场景、适用介质或兼容对象。",
    defaultBullet: "请明确适配设备、使用部位、施工场景、适用介质或兼容对象。",
  },
  {
    key: "quantity",
    title: "数量/包装/计量信息",
    matcher: /(数量|单位|包装|箱规|每箱|每包|每袋|每卷|每盘|每套|成套|打包|卷数|支数|片数|只数|套数|最小采购单位|计量|净含量|单重)/,
    detail: "并补充采购数量、计量单位、单包或单箱规格、最小采购单位或成套关系。",
    defaultBullet: "请明确采购数量、计量单位、单包或单箱规格、最小采购单位或成套关系。",
  },
];

const OTHER_CATEGORY: HintCategory = {
  key: "other",
  title: "其他关键参数",
  matcher: /.*/,
  detail: "并补充能唯一指向采购对象且会影响搜索、选型或报价的其他关键属性。",
  defaultBullet: "请补充能唯一指向采购对象且会影响搜索、选型或报价的其他关键属性。",
};

function normalizeFieldKey(value: string): string {
  return value
    .replace(/[\s:：,，;；。.!！？、/\\()（）[\]【】"'“”·-]/g, "")
    .toLowerCase();
}

function joinFields(fields: string[]): string {
  return fields.join("、");
}

function matchesCategory(field: string, category: HintCategory): boolean {
  return category.matcher.test(normalizeFieldKey(field));
}

function renderCategory(category: HintCategory, fields: string[]): string[] {
  const bullet = fields.length > 0
    ? `请明确${joinFields(fields)}，${category.detail}`
    : category.defaultBullet;

  return [`【${category.title}】`, `- ${bullet}`];
}

function compactHintText(value: string): string {
  return value
    .split(/\r?\n/)
    .map((line) => line.trim())
    .filter(Boolean)
    .join(" ")
    .trim();
}

function stripHintPrefix(value: string): string {
  return value.replace(/^[\s\-•*\d.、:：]+/, "").trim();
}

function isLowValueGenericHint(value: string): boolean {
  const compactedValue = value.replace(/\s+/g, "");

  return LOW_VALUE_HINT_PATTERNS.some((pattern) => pattern.test(compactedValue))
    || (compactedValue.startsWith("请补充")
      && compactedValue.length <= 20
      && !/[。；;！!?]/.test(compactedValue));
}

function isStructuredHumanFixHint(value: string): boolean {
  return (/【[^】]+】/.test(value) || /(?:^|\n)\d+\.\s*[^\n]+/m.test(value))
    && /^\s*[-•]/m.test(value);
}

export function sanitizeMissingRequiredFields(missingRequiredFields: string[]): string[] {
  const seen = new Set<string>();
  const results: string[] = [];

  for (const field of missingRequiredFields) {
    const trimmed = String(field ?? "").trim();
    if (!trimmed || EXCLUDED_FIELD_MATCHER.test(trimmed)) {
      continue;
    }

    const key = normalizeFieldKey(trimmed);
    if (!key || seen.has(key)) {
      continue;
    }

    seen.add(key);
    results.push(trimmed);
  }

  return results;
}

export function buildCategorizedHumanFixHint(missingRequiredFields: string[]): string {
  const fields = sanitizeMissingRequiredFields(missingRequiredFields);
  const lines = [HUMAN_FIX_HINT_HEADER];

  if (fields.length === 0) {
    for (const category of HINT_CATEGORIES) {
      lines.push(...renderCategory(category, []));
    }

    return lines.join("\n");
  }

  let remainingFields = [...fields];

  for (const category of HINT_CATEGORIES) {
    const matchedFields: string[] = [];
    const unmatchedFields: string[] = [];

    for (const field of remainingFields) {
      if (matchesCategory(field, category)) {
        matchedFields.push(field);
      } else {
        unmatchedFields.push(field);
      }
    }

    if (matchedFields.length > 0) {
      lines.push(...renderCategory(category, matchedFields));
    }

    remainingFields = unmatchedFields;
  }

  if (remainingFields.length > 0) {
    lines.push(...renderCategory(OTHER_CATEGORY, remainingFields));
  }

  return lines.join("\n");
}

export function normalizeHumanFixHint(
  existingHint: string | undefined,
  missingRequiredFields: string[],
): string {
  const fallbackHint = buildCategorizedHumanFixHint(missingRequiredFields);
  const trimmed = String(existingHint ?? "").trim();

  if (!trimmed) {
    return fallbackHint;
  }

  if (isStructuredHumanFixHint(trimmed)) {
    return trimmed;
  }

  const compacted = stripHintPrefix(compactHintText(trimmed));
  if (!compacted || isLowValueGenericHint(compacted) || fallbackHint.includes(compacted)) {
    return fallbackHint;
  }

  return `${fallbackHint}\n【补充说明】\n- ${compacted}`;
}
