"""
Substring match strategy - finds value as substring within longer tokens.
"""

from .base import BaseMatchStrategy
from ..models import TokenLike, Match
from ..token_index import TokenIndex
from ..context import find_context_keywords, CONTEXT_KEYWORDS
from ..utils import normalize_dashes


class SubstringMatcher(BaseMatchStrategy):
    """
    Find value as a substring within longer tokens.

    Handles cases like:
    - 'Fakturadatum: 2026-01-09' where the date is embedded
    - 'Fakturanummer: 2465027205' where OCR/invoice number is embedded
    - 'OCR: 1234567890' where reference number is embedded

    Uses lower score (0.75-0.85) than exact match to prefer exact matches.
    Only matches if the value appears as a distinct segment (not part of a larger number).
    """

    def find_matches(
        self,
        tokens: list[TokenLike],
        value: str,
        field_name: str,
        token_index: TokenIndex | None = None
    ) -> list[Match]:
        """Find substring matches."""
        matches = []

        # Supported fields for substring matching
        supported_fields = (
            'InvoiceDate', 'InvoiceDueDate', 'InvoiceNumber', 'OCR',
            'Bankgiro', 'Plusgiro', 'Amount',
            'supplier_organisation_number', 'supplier_accounts', 'customer_number'
        )
        if field_name not in supported_fields:
            return matches

        # Fields where spaces/dashes should be ignored during matching
        # (e.g., org number "55 65 74-6624" should match "5565746624")
        ignore_spaces_fields = (
            'supplier_organisation_number', 'Bankgiro', 'Plusgiro', 'supplier_accounts'
        )

        for token in tokens:
            token_text = token.text.strip()
            # Normalize different dash types to hyphen-minus for matching
            token_text_normalized = normalize_dashes(token_text)

            # For certain fields, also try matching with spaces/dashes removed
            if field_name in ignore_spaces_fields:
                token_text_compact = token_text_normalized.replace(' ', '').replace('-', '')
                value_compact = value.replace(' ', '').replace('-', '')
            else:
                token_text_compact = None
                value_compact = None

            # Skip if token is the same length as value (would be exact match)
            if len(token_text_normalized) <= len(value):
                continue

            # Check if value appears as substring (using normalized text)
            # Try case-sensitive first, then case-insensitive
            idx = None
            case_sensitive_match = True
            used_compact = False

            if value in token_text_normalized:
                idx = token_text_normalized.find(value)
            elif value.lower() in token_text_normalized.lower():
                idx = token_text_normalized.lower().find(value.lower())
                case_sensitive_match = False
            elif token_text_compact and value_compact in token_text_compact:
                # Try compact matching (spaces/dashes removed)
                idx = token_text_compact.find(value_compact)
                used_compact = True
            elif token_text_compact and value_compact.lower() in token_text_compact.lower():
                idx = token_text_compact.lower().find(value_compact.lower())
                case_sensitive_match = False
                used_compact = True

            if idx is None:
                continue

            # For compact matching, boundary check is simpler (just check it's 10 consecutive digits)
            if used_compact:
                # Verify proper boundary in compact text
                if idx > 0 and token_text_compact[idx - 1].isdigit():
                    continue
                end_idx = idx + len(value_compact)
                if end_idx < len(token_text_compact) and token_text_compact[end_idx].isdigit():
                    continue
            else:
                # Verify it's a proper boundary match (not part of a larger number)
                # Check character before (if exists)
                if idx > 0:
                    char_before = token_text_normalized[idx - 1]
                    # Must be non-digit (allow : space - etc)
                    if char_before.isdigit():
                        continue

                # Check character after (if exists)
                end_idx = idx + len(value)
                if end_idx < len(token_text_normalized):
                    char_after = token_text_normalized[end_idx]
                    # Must be non-digit
                    if char_after.isdigit():
                        continue

            # Found valid substring match
            context_keywords, context_boost = find_context_keywords(
                tokens, token, field_name, self.context_radius, token_index
            )

            # Check if context keyword is in the same token (like "Fakturadatum:")
            token_lower = token_text.lower()
            inline_context = []
            for keyword in CONTEXT_KEYWORDS.get(field_name, []):
                if keyword in token_lower:
                    inline_context.append(keyword)

            # Boost score if keyword is inline
            inline_boost = 0.1 if inline_context else 0

            # Lower score for case-insensitive match
            base_score = 0.75 if case_sensitive_match else 0.70

            matches.append(Match(
                field=field_name,
                value=value,
                bbox=token.bbox,  # Use full token bbox
                page_no=token.page_no,
                score=min(1.0, base_score + context_boost + inline_boost),
                matched_text=token_text,
                context_keywords=context_keywords + inline_context
            ))

        return matches
