function normalizeSpace(value) {
  return String(value ?? "")
    .replace(/\u00a0/g, " ")
    .replace(/\s+/g, " ")
    .trim();
}

function normalizePhoneValue(value) {
  const rawValue = normalizeSpace(value);
  if (!rawValue) {
    return "";
  }

  const digitsOnly = rawValue.replace(/[^\d]/g, "");
  if (!digitsOnly) {
    return rawValue;
  }

  const withoutCountryCode = stripChinaCountryCode(digitsOnly);

  if (/^1[3-9]\d{9}$/.test(withoutCountryCode)) {
    return withoutCountryCode;
  }

  if (/^0\d{9,11}$/.test(withoutCountryCode)) {
    const areaCodeLength = /^(010|020|021|022)/.test(withoutCountryCode) ? 3 : 4;
    const areaCode = withoutCountryCode.slice(0, areaCodeLength);
    const subscriberNumber = withoutCountryCode.slice(areaCodeLength);

    if (subscriberNumber.length >= 7) {
      return `${areaCode}-${subscriberNumber}`;
    }
  }

  return rawValue;
}

function stripChinaCountryCode(digitsOnly) {
  if (digitsOnly.startsWith("0086") && digitsOnly.length > 4) {
    return digitsOnly.slice(4);
  }

  if (digitsOnly.startsWith("86") && digitsOnly.length > 2) {
    return digitsOnly.slice(2);
  }

  return digitsOnly;
}

const CONTACT_PAGE_SPM_VALUES = [
  "a2615.7691456.wp_pc_common_topnav.0",
  "a2615.2177701.wp_pc_common_topnav.0",
];

function extract1688ShopHost(value) {
  const normalizedValue = normalizeSpace(value);
  if (!normalizedValue) {
    return "";
  }

  try {
    const url = new URL(normalizedValue);
    return /\.1688\.com$/i.test(url.hostname) ? url.hostname.toLowerCase() : "";
  } catch {
    const matched = normalizedValue.match(/(?:https?:\/\/)?([^/?#]+\.1688\.com)(?:[/?#]|$)/i);
    return matched?.[1]?.toLowerCase() ?? "";
  }
}

export function build1688ContactPageUrls(merchantUrl) {
  const host = extract1688ShopHost(merchantUrl);
  if (!host) {
    return [];
  }

  const baseUrl = `https://${host}/page/contactinfo.htm`;
  return [...new Set([
    ...CONTACT_PAGE_SPM_VALUES.map((spm) => `${baseUrl}?spm=${spm}`),
    baseUrl,
  ])];
}

function pickContextSnippet(text, matchValue) {
  const sourceText = normalizeSpace(text);
  const normalizedMatch = normalizeSpace(matchValue);

  if (!sourceText || !normalizedMatch) {
    return "";
  }

  const index = sourceText.toLowerCase().indexOf(normalizedMatch.toLowerCase());
  if (index < 0) {
    return sourceText.slice(0, 120);
  }

  const start = Math.max(0, index - 24);
  const end = Math.min(sourceText.length, index + normalizedMatch.length + 24);
  return sourceText.slice(start, end);
}

export function pushDetectedContact(target, seen, type, value, source, context) {
  const normalizedValue = normalizeSpace(value);
  if (!normalizedValue) {
    return;
  }

  const key = `${type}:${normalizedValue.toLowerCase()}`;
  if (seen.has(key)) {
    return;
  }

  seen.add(key);
  target.push({
    type,
    value: normalizedValue,
    source,
    context: normalizeSpace(context),
  });
}

export function mergeDetectedContacts(...groups) {
  const merged = [];
  const seen = new Set();

  for (const group of groups) {
    for (const contact of group ?? []) {
      if (!contact || typeof contact !== "object") {
        continue;
      }

      pushDetectedContact(
        merged,
        seen,
        contact.type,
        contact.value,
        contact.source,
        contact.context,
      );
    }
  }

  return merged;
}

function isPlaceholderValue(value) {
  return /^(?:暂无|无|空|--|-|保密|未填写|未公开|暂无信息|暂未填写|n\/?a|none|null)$/i.test(normalizeSpace(value));
}

function hasCompleteMobileNumber(value) {
  const digitsOnly = normalizeSpace(value).replace(/[^\d]/g, "");
  const withoutCountryCode = stripChinaCountryCode(digitsOnly);
  return /^1[3-9]\d{9}$/.test(withoutCountryCode);
}

function hasCompleteLandlineNumber(value) {
  const digitsOnly = normalizeSpace(value).replace(/[^\d]/g, "");
  const withoutCountryCode = stripChinaCountryCode(digitsOnly);

  if (!/^0\d{9,11}$/.test(withoutCountryCode)) {
    return false;
  }

  const areaCodeLength = /^(010|020|021|022|023|024|025|027|028|029)/.test(withoutCountryCode) ? 3 : 4;
  const subscriberNumber = withoutCountryCode.slice(areaCodeLength);
  const areaCode = withoutCountryCode.slice(0, areaCodeLength);
  if (/^0+$/.test(areaCode) || /^0+$/.test(subscriberNumber)) {
    return false;
  }

  return subscriberNumber.length >= 7;
}

export function isCompletePhoneContactValue(type, value) {
  const normalizedType = normalizeSpace(type).toLowerCase();
  const normalizedValue = normalizeSpace(value);

  if (!normalizedValue || isPlaceholderValue(normalizedValue)) {
    return false;
  }

  if (normalizedType === "mobile") {
    return hasCompleteMobileNumber(normalizedValue);
  }

  if (normalizedType === "phone") {
    return hasCompleteMobileNumber(normalizedValue) || hasCompleteLandlineNumber(normalizedValue);
  }

  return false;
}

function extractLabeledValue(sourceText, labels, stopLabels) {
  const pattern = new RegExp(
    `(?:${labels.join("|")})\\s*[：:]\\s*(.*?)(?=(?:${stopLabels.join("|")})\\s*[：:]|$)`,
    "i",
  );
  const match = sourceText.match(pattern);
  if (!match?.[1]) {
    return "";
  }

  const value = normalizeSpace(match[1]);
  return isPlaceholderValue(value) ? "" : value;
}

function extractLabeledContacts(sourceText, source, contacts, seen) {
  const labelConfigs = [
    {
      type: "phone",
      labels: ["电话", "联系电话", "固定电话"],
      stopLabels: ["手机(?:号)?", "传真", "地址", "联系人", "邮箱", "QQ", "微信", "旺旺", "邮编"],
    },
    {
      type: "mobile",
      labels: ["手机(?:号)?", "联系手机"],
      stopLabels: ["电话", "传真", "地址", "联系人", "邮箱", "QQ", "微信", "旺旺", "邮编"],
    },
  ];

  for (const config of labelConfigs) {
    const rawValue = extractLabeledValue(sourceText, config.labels, config.stopLabels);
    if (!rawValue) {
      continue;
    }

    pushDetectedContact(
      contacts,
      seen,
      config.type,
      normalizePhoneValue(rawValue),
      source,
      pickContextSnippet(sourceText, rawValue),
    );
  }
}

export function extractDetectedContacts(text, source) {
  const contacts = [];
  const seen = new Set();
  const sourceText = normalizeSpace(text);

  if (!sourceText) {
    return contacts;
  }

  extractLabeledContacts(sourceText, source, contacts, seen);

  const patterns = [
    {
      type: "email",
      regex: /[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/gi,
      normalize: (value) => value.toLowerCase(),
    },
    {
      type: "mobile",
      regex: /(?<!\d)(?:\+?86[-\s]?)?(1[3-9]\d{9})(?!\d)/g,
      normalize: (value) => normalizePhoneValue(value),
    },
    {
      type: "phone",
      regex: /(?<!\d)(?:\+?86[-\s]?)?(0\d{2,3}[-\s]?\d{7,8})(?!\d)/g,
      normalize: (value) => normalizePhoneValue(value),
    },
    {
      type: "wechat",
      regex: /(?:微信|wechat|vx|v信|微\s*信)[:：\s]*([a-zA-Z][-_a-zA-Z0-9]{5,19})/gi,
      normalize: (_value, group) => group,
    },
    {
      type: "qq",
      regex: /(?:QQ|qq)[:：\s]*([1-9][0-9]{4,11})/g,
      normalize: (_value, group) => group,
    },
  ];

  for (const pattern of patterns) {
    for (const match of sourceText.matchAll(pattern.regex)) {
      const captured = pattern.normalize(match[0], match[1]);
      pushDetectedContact(contacts, seen, pattern.type, captured, source, pickContextSnippet(sourceText, match[0]));
    }
  }

  return contacts;
}

export function hasDetectedPhoneContact(contacts) {
  return (Array.isArray(contacts) ? contacts : []).some((contact) => {
    if (!contact || typeof contact !== "object") {
      return false;
    }

    const type = normalizeSpace(contact.type).toLowerCase();
    const value = normalizeSpace(contact.value);
    return isCompletePhoneContactValue(type, value);
  });
}
