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 str = typeof value === 'string' ? value.trim() : String(value);

  if (str === '' || !NUMERIC_REGEX.test(str)) {
    return { corrected: str, changed: false };
  }

  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}`;
    return { corrected, changed: corrected !== str };
  }

  if (str.length === 13) {
    const body = str.slice(0, 12);
    const check = calculateEanCheckDigit(body);
    const corrected = `${body}${check}`;
    return { corrected, changed: corrected !== str };
  }

  return { corrected: str, changed: false };
}
