"""
PDF Type Detection Module

Automatically distinguishes between:
- Text-based PDFs (digitally generated)
- Scanned image PDFs
"""

from pathlib import Path
from typing import Literal
import fitz  # PyMuPDF


PDFType = Literal["text", "scanned", "mixed"]


def extract_text_first_page(pdf_path: str | Path) -> str:
    """Extract text from the first page of a PDF."""
    doc = fitz.open(pdf_path)
    if len(doc) == 0:
        return ""

    first_page = doc[0]
    text = first_page.get_text()
    doc.close()
    return text


def is_text_pdf(pdf_path: str | Path, min_chars: int = 30) -> bool:
    """
    Check if PDF has extractable AND READABLE text layer.

    Some PDFs have custom font encodings that produce garbled text.
    This function checks both the presence and readability of text.

    Args:
        pdf_path: Path to the PDF file
        min_chars: Minimum characters to consider it a text PDF

    Returns:
        True if PDF has readable text layer, False if scanned or garbled
    """
    text = extract_text_first_page(pdf_path)
    stripped_text = text.strip()

    # First check: enough characters (basic minimum)
    if len(stripped_text) <= min_chars:
        return False

    # Second check: text readability
    # PDFs with custom font encoding often produce garbled text
    # Check if common invoice-related keywords are present
    text_lower = stripped_text.lower()
    invoice_keywords = [
        'faktura', 'invoice', 'datum', 'date', 'belopp', 'amount',
        'moms', 'vat', 'bankgiro', 'plusgiro', 'ocr', 'betala',
        'summa', 'total', 'pris', 'price', 'kr', 'sek'
    ]
    found_keywords = sum(1 for kw in invoice_keywords if kw in text_lower)

    # If at least 2 keywords found, likely readable text
    if found_keywords >= 2:
        return True

    # Third check: minimum content threshold
    # A real text PDF invoice should have at least 200 chars of content
    # PDFs with only headers/footers (like "Brandsign") should use OCR
    if len(stripped_text) < 200:
        return False

    # Fourth check: character readability ratio
    # Count printable ASCII and common Swedish/European characters
    readable_chars = 0
    total_chars = len(stripped_text)

    for c in stripped_text:
        # Printable ASCII (32-126) or common Swedish/European chars
        if 32 <= ord(c) <= 126 or c in 'åäöÅÄÖéèêëÉÈÊËüÜ':
            readable_chars += 1

    # If less than 70% readable, treat as garbled/scanned
    readable_ratio = readable_chars / total_chars if total_chars > 0 else 0
    if readable_ratio < 0.70:
        return False

    # Fifth check: if no keywords found but passes basic readability,
    # require higher readability threshold (85%) or at least 1 keyword
    # This catches garbled PDFs that have high ASCII ratio but unreadable content
    # (e.g., custom font encoding that maps to different characters)
    if found_keywords == 0 and readable_ratio < 0.85:
        return False

    return True


def get_pdf_type(pdf_path: str | Path) -> PDFType:
    """
    Determine the PDF type.

    Returns:
        'text' - Has extractable text layer
        'scanned' - Image-based, needs OCR
        'mixed' - Some pages have text, some don't
    """
    doc = fitz.open(pdf_path)

    if len(doc) == 0:
        doc.close()
        return "scanned"

    text_pages = 0
    total_pages = len(doc)
    for page in doc:
        text = page.get_text().strip()
        if len(text) > 30:
            text_pages += 1

    doc.close()

    if text_pages == total_pages:
        return "text"
    elif text_pages == 0:
        return "scanned"
    else:
        return "mixed"


def get_page_info(pdf_path: str | Path) -> list[dict]:
    """
    Get information about each page in the PDF.

    Returns:
        List of dicts with page info (number, width, height, has_text)
    """
    doc = fitz.open(pdf_path)
    pages = []

    for i, page in enumerate(doc):
        text = page.get_text().strip()
        rect = page.rect
        pages.append({
            "page_no": i,
            "width": rect.width,
            "height": rect.height,
            "has_text": len(text) > 30,
            "char_count": len(text)
        })

    doc.close()
    return pages
