"""
ocr_cleaner
===========

Utilities for cleaning and extracting GSTINs from raw, messy text blobs
(like full page OCR output).

This module focuses on:
- Pattern scanning (Finding potential GSTINs in a wall of text).
- Heuristic repair (Fixing common OCR confusion: 'O' vs '0', 'B' vs '8').

:copyright: (c) 2026
:license: GPL-3.0-only
"""

import re
from typing import List

# Import our precise repair logic from gstin.py
from .gstin import repair_gstin, validate as validate_gstin

# A "Loose" Regex to capture things that *look* like GSTINs but might have errors.
# We look for:
# - Start word boundary
# - 2 digits (or things that look like digits)
# - 5 letters (or things that look like letters)
# - 4 digits
# - 1 letter
# - 1 number/letter
# - 1 Z (default)
# - 1 Check digit
# - End word boundary
# We allow specific OCR-confused chars in the regex to catch "dirty" candidates.
_LOOSE_GSTIN_PATTERN = re.compile(
    r"\b[0-9OIZS]{2}[A-Z0-9]{5}[0-9OIZS]{4}[A-Z0-9]{1}[1-9A-Z]{1}Z[0-9A-Z]{1}\b",
    re.IGNORECASE
)

def clean_ocr_gstin(text: str) -> str:
    """
    Cleans a single potential GSTIN string using OCR correction maps.
    
    This function wraps the context-aware 'repair_gstin' logic 
    but adds pre-processing for whitespace and noise.

    Parameters
    ----------
    text : str
        A dirty string like "27AABC0123401Z5 " or "27AABC O1234..."

    Returns
    -------
    str
        Cleaned, uppercase string (15 chars).
    """
    if not text:
        return ""
    
    # 1. Remove all whitespace (spaces, tabs, newlines)
    cleaned = re.sub(r"\s+", "", text)
    
    # 2. Force Uppercase
    cleaned = cleaned.upper()
    
    # 3. Apply the context-aware repair from our core module
    # This fixes 0 <-> O, 8 <-> B based on position (State code vs PAN).
    return repair_gstin(cleaned)


def extract_gstin_from_text(text: str) -> List[str]:
    """
    Scans a large blob of text (e.g., full invoice content) and extracts
    all valid or repairable GSTINs.

    This is useful when you don't know WHERE the GSTIN is on the page.

    Parameters
    ----------
    text : str
        The full raw text of the document.

    Returns
    -------
    list
        A list of unique, valid GSTIN strings found in the text.
    """
    if not text:
        return []

    candidates = set()
    
    # 1. Regex Scan using the "Loose" pattern
    # This finds strings that *resemble* GSTINs, even if they have typos.
    matches = _LOOSE_GSTIN_PATTERN.findall(text)
    
    for match in matches:
        # 2. Clean and Repair the match
        clean_candidate = clean_ocr_gstin(match)
        
        # 3. Verify validity
        # We only return it if we successfully repaired it into a valid GSTIN.
        # This prevents returning junk.
        if validate_gstin(clean_candidate):
            candidates.add(clean_candidate)
            
    return list(candidates)