"""
Bankgiro Normalizer

Handles normalization and validation of Swedish Bankgiro numbers.
"""

import re

from shared.utils.validators import FieldValidators

from .base import BaseNormalizer, NormalizationResult


class BankgiroNormalizer(BaseNormalizer):
    """
    Normalizes Swedish Bankgiro numbers.

    Bankgiro rules:
    - 7 or 8 digits only
    - Last digit is Luhn (Mod10) check digit
    - Display format: XXX-XXXX (7 digits) or XXXX-XXXX (8 digits)

    Display pattern: ^\\d{3,4}-\\d{4}$
    Normalized pattern: ^\\d{7,8}$

    Note: Text may contain both BG and PG numbers. We specifically look for
    BG display format (XXX-XXXX or XXXX-XXXX) to extract the correct one.
    """

    @property
    def field_name(self) -> str:
        return "Bankgiro"

    def normalize(self, text: str) -> NormalizationResult:
        text = text.strip()
        if not text:
            return NormalizationResult.failure("Empty text")

        # Look for BG display format pattern: 3-4 digits, dash, 4 digits
        # This distinguishes BG from PG which uses X-X format (digits-single digit)
        bg_matches = re.findall(r"(\d{3,4})-(\d{4})", text)

        if bg_matches:
            # Try each match and find one with valid Luhn
            for match in bg_matches:
                digits = match[0] + match[1]
                if len(digits) in (7, 8) and FieldValidators.luhn_checksum(digits):
                    # Valid BG found
                    formatted = self._format_bankgiro(digits)
                    return NormalizationResult.success(formatted)

            # No valid Luhn, use first match
            digits = bg_matches[0][0] + bg_matches[0][1]
            if len(digits) in (7, 8):
                formatted = self._format_bankgiro(digits)
                return NormalizationResult.success_with_warning(
                    formatted, "Luhn checksum failed (possible OCR error)"
                )

        # Fallback: try to find 7-8 consecutive digits
        # But first check if text contains PG format (XXXXXXX-X), if so don't use fallback
        # to avoid misinterpreting PG as BG
        pg_format_present = re.search(r"(?<![0-9])\d{1,7}-\d(?!\d)", text)
        if pg_format_present:
            return NormalizationResult.failure("No valid Bankgiro found in text")

        digit_match = re.search(r"\b(\d{7,8})\b", text)
        if digit_match:
            digits = digit_match.group(1)
            if len(digits) in (7, 8):
                formatted = self._format_bankgiro(digits)
                if FieldValidators.luhn_checksum(digits):
                    return NormalizationResult.success(formatted)
                else:
                    return NormalizationResult.success_with_warning(
                        formatted, "Luhn checksum failed (possible OCR error)"
                    )

        return NormalizationResult.failure("No valid Bankgiro found in text")

    @staticmethod
    def _format_bankgiro(digits: str) -> str:
        """Format Bankgiro number with dash."""
        if len(digits) == 8:
            return f"{digits[:4]}-{digits[4:]}"
        else:
            return f"{digits[:3]}-{digits[3:]}"
