const NUMERIC_REGEX = /^\d+$/;

export function calculateUpcCheckDigit(upcBody: string): number {
  if (!NUMERIC_REGEX.test(upcBody) || upcBody.length !== 11) {
    throw new Error('UPC body must be 11 numeric characters');
  }

  const digits = upcBody.split('').map((d) => Number.parseInt(d, 10));
  let sum = 0;

  for (let i = 0; i < digits.length; i += 1) {
    sum += (i % 2 === 0 ? digits[i] * 3 : digits[i]);
  }

  const mod = sum % 10;
  return mod === 0 ? 0 : 10 - mod;
}

export function calculateEanCheckDigit(eanBody: string): number {
  if (!NUMERIC_REGEX.test(eanBody) || eanBody.length !== 12) {
    throw new Error('EAN body must be 12 numeric characters');
  }

  const digits = eanBody.split('').map((d) => Number.parseInt(d, 10));
  let sum = 0;

  for (let i = 0; i < digits.length; i += 1) {
    sum += (i % 2 === 0 ? digits[i] : digits[i] * 3);
  }

  const mod = sum % 10;
  return mod === 0 ? 0 : 10 - mod;
}

export function correctUpcValue(rawValue: unknown): { corrected: string; changed: boolean } {
  const value = rawValue ?? '';
  const originalStr = typeof value === 'string' ? value : String(value);
  // Strip ALL whitespace (spaces, tabs, etc.) from UPC values - not just leading/trailing
  const str = originalStr.replace(/\s+/g, '');

  // Track if whitespace was stripped (this alone means we changed the value)
  const whitespaceStripped = str !== originalStr;

  if (str === '' || !NUMERIC_REGEX.test(str)) {
    // Return stripped version even if not numeric (so non-numeric values still get spaces removed)
    return { corrected: str, changed: whitespaceStripped };
  }

  if (str.length === 11) {
    const check = calculateUpcCheckDigit(str);
    return { corrected: `${str}${check}`, changed: true };
  }

  if (str.length === 12) {
    const body = str.slice(0, 11);
    const check = calculateUpcCheckDigit(body);
    const corrected = `${body}${check}`;
    // Changed if whitespace was stripped OR if check digit was corrected
    return { corrected, changed: whitespaceStripped || corrected !== str };
  }

  if (str.length === 13) {
    const body = str.slice(0, 12);
    const check = calculateEanCheckDigit(body);
    const corrected = `${body}${check}`;
    // Changed if whitespace was stripped OR if check digit was corrected
    return { corrected, changed: whitespaceStripped || corrected !== str };
  }

  // For other lengths, return stripped value
  return { corrected: str, changed: whitespaceStripped };
}
