from __future__ import annotations

from .idfc import IDFCFirstParser
from .axis import AxisParser
from .hdfc import HDFCParser
from .hsbc import HSBCParser
from .indian_bank import IndianBankModernParser, IndianBankLegacyParser
from .indusind import IndusIndParser
from .kotak import KotakParser
from .sbi import SBIModernParser, SBIOtherParser
from .base import extract_text

PARSERS = [
    IDFCFirstParser,
    AxisParser,
    HDFCParser,
    HSBCParser,
    IndianBankModernParser,
    IndianBankLegacyParser,
    IndusIndParser,
    KotakParser,
    SBIOtherParser,
    SBIModernParser,
]

BANK_OPTIONS = [
    ("auto", "Auto Detect"),
    ("axis", "Axis Bank"),
    ("hdfc", "HDFC Bank"),
    ("hsbc", "HSBC Bank"),
    ("idfc", "IDFC FIRST Bank"),
    ("indian_bank", "Indian Bank"),
    ("indusind", "IndusInd Bank"),
    ("kotak", "Kotak Mahindra Bank"),
    ("sbi", "State Bank of India"),
]

BANK_PARSERS = {
    "axis": [AxisParser],
    "hdfc": [HDFCParser],
    "hsbc": [HSBCParser],
    "idfc": [IDFCFirstParser],
    "indian_bank": [IndianBankModernParser, IndianBankLegacyParser],
    "indusind": [IndusIndParser],
    "kotak": [KotakParser],
    "sbi": [SBIOtherParser, SBIModernParser],
}


def detect_parser(text):
    scored = sorted(((parser.detect(text), parser) for parser in PARSERS), key=lambda item: item[0], reverse=True)
    if not scored or scored[0][0] <= 0:
        return None, 0
    return scored[0][1](), scored[0][0]


def _selected_parser(bank_key: str, text: str):
    candidates = BANK_PARSERS.get(bank_key, [])
    if not candidates:
        return None, 0
    scored = sorted(((parser.detect(text), parser) for parser in candidates), key=lambda item: item[0], reverse=True)
    if scored and scored[0][0] > 0:
        return scored[0][1](), scored[0][0]
    return None, 0


def parse_pdf(path, bank_hint: str | None = None):
    hint = (bank_hint or "auto").strip().lower()
    if hint == "hsbc":
        return HSBCParser().parse(path, "")
    text = extract_text(path)
    if hint and hint != "auto":
        parser, score = _selected_parser(hint, text)
        if parser is None:
            label = dict(BANK_OPTIONS).get(hint, "the selected bank")
            raise ValueError(
                f"The uploaded statement does not match the selected {label} format. "
                "Please verify the selected bank or choose Auto Detect."
            )
        return parser.parse(path, text)
    parser, score = detect_parser(text)
    if parser is None and not (text or "").strip():
        # Image-only statements cannot be identified by pdftotext.  HSBCParser
        # performs its own OCR identification and raises a precise mismatch error.
        try:
            return HSBCParser().parse(path, text)
        except ValueError:
            pass
    if parser is None:
        raise ValueError(
            "Unsupported statement format. Select the bank manually or add a bank-specific parser for this statement layout."
        )
    return parser.parse(path, text)
