"""
Plusgiro Normalizer

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

import re

from shared.utils.validators import FieldValidators

from .base import BaseNormalizer, NormalizationResult


class PlusgiroNormalizer(BaseNormalizer):
    """
    Normalizes Swedish Plusgiro numbers.

    Plusgiro rules:
    - 2 to 8 digits
    - Last digit is Luhn (Mod10) check digit
    - Display format: XXXXXXX-X (all digits except last, dash, last digit)

    Display pattern: ^\\d{1,7}-\\d$
    Normalized pattern: ^\\d{2,8}$

    Note: Text may contain both BG and PG numbers. We specifically look for
    PG display format (X-X, XX-X, ..., XXXXXXX-X) to extract the correct one.
    """

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

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

        # First look for PG display format: 1-7 digits (possibly with spaces), dash, 1 digit
        # This is distinct from BG format which has 4 digits after the dash
        # Pattern allows spaces within the number like "486 98 63-6"
        # (?<![0-9]) ensures we don't start from within another number (like BG)
        pg_matches = re.findall(r"(?<![0-9])(\d[\d\s]{0,10})-(\d)(?!\d)", text)

        if pg_matches:
            # Try each match and find one with valid Luhn
            for match in pg_matches:
                # Remove spaces from the first part
                digits = re.sub(r"\s", "", match[0]) + match[1]
                if 2 <= len(digits) <= 8 and FieldValidators.luhn_checksum(digits):
                    # Valid PG found
                    formatted = f"{digits[:-1]}-{digits[-1]}"
                    return NormalizationResult.success(formatted)

            # No valid Luhn, use first match with most digits
            best_match = max(pg_matches, key=lambda m: len(re.sub(r"\s", "", m[0])))
            digits = re.sub(r"\s", "", best_match[0]) + best_match[1]
            if 2 <= len(digits) <= 8:
                formatted = f"{digits[:-1]}-{digits[-1]}"
                return NormalizationResult.success_with_warning(
                    formatted, "Luhn checksum failed (possible OCR error)"
                )

        # If no PG format found, extract all digits and format as PG
        # This handles cases where the number might be in BG format or raw digits
        all_digits = re.sub(r"\D", "", text)

        # Try to find a valid 2-8 digit sequence
        if 2 <= len(all_digits) <= 8:
            formatted = f"{all_digits[:-1]}-{all_digits[-1]}"
            if FieldValidators.luhn_checksum(all_digits):
                return NormalizationResult.success(formatted)
            else:
                return NormalizationResult.success_with_warning(
                    formatted, "Luhn checksum failed (possible OCR error)"
                )

        # Try to find any 2-8 digit sequence in text
        digit_match = re.search(r"\b(\d{2,8})\b", text)
        if digit_match:
            digits = digit_match.group(1)
            formatted = f"{digits[:-1]}-{digits[-1]}"
            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 Plusgiro found in text")
