import pdfplumber
import re
import sys
from typing import Optional


def extract_number_from_region(pdf_path: str, page_num: int, x0: float, y0: float, x1: float, y1: float) -> Optional[str]:
    """
    Extrae un número de una región específica de un PDF.

    Args:
        pdf_path: Ruta al archivo PDF
        page_num: Número de página (0-indexed)
        x0: Coordenada izquierda
        y0: Coordenada superior
        x1: Coordenada derecha
        y1: Coordenada inferior

    Returns:
        El número encontrado en la región o None si no se encuentra
    """
    with pdfplumber.open(pdf_path) as pdf:
        if page_num >= len(pdf.pages):
            raise ValueError(f"La página {page_num} no existe. El PDF tiene {len(pdf.pages)} páginas.")

        page = pdf.pages[page_num]
        bbox = (x0, y0, x1, y1)
        cropped = page.crop(bbox)
        text = cropped.extract_text()

        if text:
            text = text.strip()
            # Buscar números (incluyendo decimales con coma o punto)
            numbers = re.findall(r'-?[\d.]+,\d+|-?\d+[.,]?\d*', text)
            if numbers:
                return numbers[0]

        return None


def extract_text_from_region(pdf_path: str, page_num: int, x0: float, y0: float, x1: float, y1: float) -> Optional[str]:
    """
    Extrae todo el texto de una región específica de un PDF.
    """
    with pdfplumber.open(pdf_path) as pdf:
        if page_num >= len(pdf.pages):
            raise ValueError(f"La página {page_num} no existe.")

        page = pdf.pages[page_num]
        cropped = page.crop((x0, y0, x1, y1))
        return cropped.extract_text()


def get_page_dimensions(pdf_path: str, page_num: int = 0) -> dict:
    """
    Obtiene las dimensiones de una página del PDF.
    """
    with pdfplumber.open(pdf_path) as pdf:
        page = pdf.pages[page_num]
        return {
            "width": page.width,
            "height": page.height,
            "total_pages": len(pdf.pages)
        }


def find_text_coordinates(pdf_path: str, search_text: str, page_num: int = 0) -> list:
    """
    Busca un texto en el PDF y devuelve las coordenadas donde se encuentra.
    Útil para identificar las coordenadas de campos específicos.
    """
    results = []
    with pdfplumber.open(pdf_path) as pdf:
        if page_num >= len(pdf.pages):
            return results

        page = pdf.pages[page_num]
        words = page.extract_words()

        for word in words:
            if search_text.lower() in word['text'].lower():
                results.append({
                    "text": word['text'],
                    "x0": round(word['x0'], 2),
                    "y0": round(word['top'], 2),
                    "x1": round(word['x1'], 2),
                    "y1": round(word['bottom'], 2)
                })

    return results


def extract_all_words_with_coords(pdf_path: str, page_num: int = 0) -> list:
    """
    Extrae todas las palabras de una página con sus coordenadas.
    Útil para mapear el PDF y encontrar las regiones correctas.
    """
    with pdfplumber.open(pdf_path) as pdf:
        if page_num >= len(pdf.pages):
            return []

        page = pdf.pages[page_num]
        words = page.extract_words()

        return [
            {
                "text": w['text'],
                "x0": round(w['x0'], 2),
                "y0": round(w['top'], 2),
                "x1": round(w['x1'], 2),
                "y1": round(w['bottom'], 2)
            }
            for w in words
        ]


if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Uso:")
        print("  Extraer número de región:")
        print("    python extract_region.py extract <pdf> <page> <x0> <y0> <x1> <y1>")
        print()
        print("  Buscar coordenadas de un texto:")
        print("    python extract_region.py find <pdf> <texto> [page]")
        print()
        print("  Ver dimensiones del PDF:")
        print("    python extract_region.py dims <pdf>")
        print()
        print("  Listar todas las palabras con coordenadas:")
        print("    python extract_region.py words <pdf> [page]")
        sys.exit(1)

    command = sys.argv[1]

    if command == "extract":
        if len(sys.argv) < 8:
            print("Uso: python extract_region.py extract <pdf> <page> <x0> <y0> <x1> <y1>")
            sys.exit(1)

        pdf_path = sys.argv[2]
        page_num = int(sys.argv[3])
        x0, y0, x1, y1 = map(float, sys.argv[4:8])

        result = extract_number_from_region(pdf_path, page_num, x0, y0, x1, y1)
        if result:
            print(f"Número: {result}")
        else:
            text = extract_text_from_region(pdf_path, page_num, x0, y0, x1, y1)
            print(f"No se encontró número. Texto en región: '{text}'")

    elif command == "find":
        if len(sys.argv) < 4:
            print("Uso: python extract_region.py find <pdf> <texto> [page]")
            sys.exit(1)

        pdf_path = sys.argv[2]
        search_text = sys.argv[3]
        page_num = int(sys.argv[4]) if len(sys.argv) > 4 else 0

        results = find_text_coordinates(pdf_path, search_text, page_num)
        if results:
            print(f"Encontrado '{search_text}' en {len(results)} ubicaciones:")
            for r in results:
                print(f"  '{r['text']}' -> bbox: ({r['x0']}, {r['y0']}, {r['x1']}, {r['y1']})")
        else:
            print(f"No se encontró '{search_text}'")

    elif command == "dims":
        if len(sys.argv) < 3:
            print("Uso: python extract_region.py dims <pdf>")
            sys.exit(1)

        pdf_path = sys.argv[2]
        dims = get_page_dimensions(pdf_path)
        print(f"Dimensiones: {dims['width']} x {dims['height']} puntos")
        print(f"Total páginas: {dims['total_pages']}")

    elif command == "words":
        if len(sys.argv) < 3:
            print("Uso: python extract_region.py words <pdf> [page]")
            sys.exit(1)

        pdf_path = sys.argv[2]
        page_num = int(sys.argv[3]) if len(sys.argv) > 3 else 0

        words = extract_all_words_with_coords(pdf_path, page_num)
        for w in words:
            print(f"'{w['text']}' -> ({w['x0']}, {w['y0']}, {w['x1']}, {w['y1']})")

    else:
        print(f"Comando desconocido: {command}")
        sys.exit(1)
