export type ScanResult = {
  amount: number | null;
  label: string | null;
  date: string | null;
  confidence: number; // 0-100
  rawText: string;
};

const KNOWN_MERCHANTS = [
  "BILLA",
  "SPAR",
  "HOFER",
  "LIDL",
  "PENNY",
  "MERKUR",
  "REWE",
  "EDEKA",
  "ALDI",
  "DM",
  "MÜLLER",
  "ROSSMANN",
  "MCDONALD",
  "MCDONALDS",
  "BURGER KING",
  "STARBUCKS",
];

// Patterns tried in order to extract the total amount
const AMOUNT_PATTERNS: RegExp[] = [
  /(?:summe|gesamt|total|zu zahlen|zu pay|betrag|sum)[\s:]*(\d+[,.]?\d*[,.]\d{2})/gi,
];

function normaliseAmount(raw: string): number {
  // Replace comma decimal separator with dot, strip thousands separators
  // e.g. "1.234,56" → 1234.56, "12,34" → 12.34, "12.34" → 12.34
  const cleaned = raw.replace(/\./g, "").replace(",", ".");
  return parseFloat(cleaned);
}

function extractAmount(text: string): number | null {
  // Pattern 1: keyword-based
  for (const pattern of AMOUNT_PATTERNS) {
    pattern.lastIndex = 0;
    const match = pattern.exec(text);
    if (match) {
      const val = normaliseAmount(match[1]);
      if (!isNaN(val)) return val;
    }
  }

  // Pattern 2: highest "digits€" match
  const withSuffix = /(\d+[,.]\d{2})\s*€/g;
  let highest: number | null = null;
  let m: RegExpExecArray | null;
  while ((m = withSuffix.exec(text)) !== null) {
    const val = normaliseAmount(m[1]);
    if (!isNaN(val) && (highest === null || val > highest)) {
      highest = val;
    }
  }
  if (highest !== null) return highest;

  // Pattern 3: "€ digits" match
  const withPrefix = /€\s*(\d+[,.]\d{2})/g;
  while ((m = withPrefix.exec(text)) !== null) {
    const val = normaliseAmount(m[1]);
    if (!isNaN(val) && (highest === null || val > highest)) {
      highest = val;
    }
  }
  return highest;
}

function extractLabel(text: string): { label: string | null; isKnown: boolean } {
  const upper = text.toUpperCase();

  for (const merchant of KNOWN_MERCHANTS) {
    if (upper.includes(merchant)) {
      return { label: merchant.charAt(0) + merchant.slice(1).toLowerCase(), isKnown: true };
    }
  }

  // Take first non-empty line that is not digits-only and not a date/time/address line
  const lines = text.split("\n");
  for (const raw of lines) {
    const line = raw.trim();
    if (!line) continue;
    if (/^\d+$/.test(line)) continue; // digits-only
    if (/\d{2}[.:/]\d{2}/.test(line)) continue; // date/time pattern
    return { label: line, isKnown: false };
  }

  return { label: null, isKnown: false };
}

function extractDate(text: string): string | null {
  // DD.MM.YYYY
  const dmyFull = /\b(\d{2})\.(\d{2})\.(\d{4})\b/;
  let m = dmyFull.exec(text);
  if (m) {
    return `${m[3]}-${m[2]}-${m[1]}`;
  }

  // DD.MM.YY
  const dmyShort = /\b(\d{2})\.(\d{2})\.(\d{2})\b/;
  m = dmyShort.exec(text);
  if (m) {
    const year = parseInt(m[3], 10) >= 50 ? `19${m[3]}` : `20${m[3]}`;
    return `${year}-${m[2]}-${m[1]}`;
  }

  // YYYY-MM-DD
  const iso = /\b(\d{4})-(\d{2})-(\d{2})\b/;
  m = iso.exec(text);
  if (m) {
    return `${m[1]}-${m[2]}-${m[3]}`;
  }

  return null;
}

export function parseReceiptText(text: string): ScanResult {
  const amount = extractAmount(text);
  const { label, isKnown } = extractLabel(text);
  const date = extractDate(text);

  let confidence = 0;
  if (amount !== null) confidence += 50;
  if (label !== null) confidence += isKnown ? 30 : 10;
  if (date !== null) confidence += 20;
  confidence = Math.min(confidence, 100);

  return { amount, label, date, confidence, rawText: text };
}
