"""
Módulo converti2 - Procesamiento de archivos PDF y Excel

Funcionalidades:
- Extracción de datos de secciones izquierda/derecha de PDF
- Exportación a Excel
- Procesamiento de datos específicos
"""
import os
import re
import pdfplumber
import pandas as pd
import fitz  # PyMuPDF

# Función para extraer los datos de la sección derecha
def extract_right_section_data(pdf_path):
    """Extrae datos de la sección izquierda de un PDF.

    Args:
        pdf_path (str): Ruta al archivo PDF

    Returns:
        DataFrame: Datos extraídos en formato pandas
    """
    data = []
    with pdfplumber.open(pdf_path) as pdf:
        for page in pdf.pages:
            # Definir la región de la sección derecha (mitad derecha de la página)
            right_section = page.within_bbox((page.width / 2, 0, page.width, page.height))

            # Extraer tablas de la sección derecha
            tables = right_section.extract_tables()
            for table in tables:
                # Buscar la fila que contiene "Código" y "Valor"
                header_row = None
                for i, row in enumerate(table):
                    if "Código" in row and "Glosa" in row and "Valor" in row:
                        header_row = i
                        break

                # Si se encuentra la fila de encabezado, extraer los datos
                if header_row is not None:
                    # Obtener el índice de las columnas "Código", "Glosa" y "Valor"
                    header = table[header_row]
                    codigo_index = header.index("Código")
                    glosa_index = header.index("Glosa")
                    valor_index = header.index("Valor")

                    # Extraer los datos de las filas siguientes
                    for row in table[header_row + 1:]:
                        if len(row) > max(codigo_index, valor_index):
                            codigo = row[codigo_index].strip() if row[codigo_index] else None
                            glosa = row[glosa_index].strip() if row[glosa_index] else None
                            valor = row[valor_index].strip() if row[valor_index] else None
                            if codigo and glosa and valor:
                                data.append({"Código": codigo, "Glosa": glosa, "Valor": valor})
    return data

# Función para extraer datos de la sección izquierda
def extract_left_section_data(pdf_path):
    """Extrae datos de la sección izquierda de un PDF.

    Args:
        pdf_path (str): Ruta al archivo PDF

    Returns:
        DataFrame: Datos extraídos en formato pandas

    Raises:
        FileNotFoundError: Si el PDF no existe
        ValueError: Si el PDF no tiene el formato esperado
    """
    data = []
    with pdfplumber.open(pdf_path) as pdf:
        for page in pdf.pages:
            # Definir la región de la sección izquierda (mitad izquierda de la página)
            left_section = page.within_bbox((0, 0, page.width / 2, page.height))

            # Extraer tablas de la sección izquierda
            tables = left_section.extract_tables()
            for table in tables:
                # Buscar la fila que contiene "Código" y "Valor"
                header_row = None
                for i, row in enumerate(table):
                    if "Código" in row and "Glosa" in row and "Valor" in row:
                        header_row = i
                        break

                # Si se encuentra la fila de encabezado, extraer los datos
                if header_row is not None:
                    # Obtener el índice de las columnas "Código" y "Valor"
                    header = table[header_row]
                    codigo_index = header.index("Código")
                    glosa_index = header.index("Glosa")
                    valor_index = header.index("Valor")

                    # Extraer los datos de las filas siguientes
                    for row in table[header_row + 1:]:
                        if len(row) > max(codigo_index, valor_index):
                            codigo = row[codigo_index].strip() if row[codigo_index] else None
                            glosa = row[glosa_index].strip() if row[glosa_index] else None
                            valor = row[valor_index].strip() if row[valor_index] else None
                            if codigo and valor:
                                data.append({"Código": codigo, "Glosa": glosa, "Valor": valor})
    return data

# Función para extraer datos especificos como el Folio, Rut y Periodo
def extraer_datos_especificos(pdf_path):
    """
    Versión 1.2.4 - Estrategia de Coordenadas (Fiscloud Hunter)
    Si el texto está desordenado, recorta el área superior derecha 
    donde el SII siempre pone el Folio, RUT y Periodo.
    """
    import fitz, re, os
    doc = None
    try:
        doc = fitz.open(pdf_path)
        page = doc[0]
        
        # 1. Definir el área de interés (Rincón superior derecho)
        # En un F29 estándar, los datos están en el 30% derecho y 15% superior
        ancho = page.rect.width
        alto = page.rect.height
        area_metadatos = fitz.Rect(ancho * 0.65, 0, ancho, alto * 0.20)
        
        # Extraer solo el texto de ese cuadradito
        texto_box = page.get_text("text", clip=area_metadatos)
        # Limpiar texto de ruidos y saltos de línea
        texto_limpio = " ".join(texto_box.split())

        # 2. Intentar capturar por patrones fijos en esa área
        # Buscamos el primer número largo (Folio), el RUT y el año/mes (Periodo)
        folio = re.search(r"0?7\s*\]\s*(\d{7,12})", texto_limpio)
        rut = re.search(r"0?3\s*\]\s*([\d\.-]+k?)", texto_limpio, re.IGNORECASE)
        periodo = re.search(r"15\s*\]\s*(20\d{4})", texto_limpio)

        # 3. SISTEMA DE EMERGENCIA (Búsqueda por proximidad si lo anterior falló)
        if not folio or not rut or not periodo:
            # Si el texto está MUY desordenado, buscamos todos los números en el área
            numeros_en_area = re.findall(r"\b\d[\d\.-]+k?\b", texto_limpio, re.IGNORECASE)
            
            # El Folio suele ser el número más largo (>8 dígitos)
            if not folio:
                for n in numeros_en_area:
                    clean_n = n.replace(".","").replace("-","")
                    if len(clean_n) >= 9 and clean_n.startswith(('8', '9')): # Folios comunes
                        folio = type('obj', (object,), {'group': lambda self, x: n})()
                        break 
            
            # El Periodo siempre tiene 6 dígitos y empieza con 20
            if not periodo:
                for n in numeros_en_area:
                    if len(n) == 6 and n.startswith('20'):
                        periodo = type('obj', (object,), {'group': lambda self, x: n})()
                        break

        # Validación Final de Seguridad
        if not folio or not rut or not periodo:
            # Último intento: Buscar en toda la página ignorando el recorte
            texto_full = " ".join(page.get_text("text").split())
            if not folio: folio = re.search(r"0?7\s*\]\s*(\d+)", texto_full)
            if not rut: rut = re.search(r"0?3\s*\]\s*([\d\.-]+)", texto_full)
            if not periodo: periodo = re.search(r"15\s*\]\s*(\d+)", texto_full)

        if not (folio and rut and periodo):
            raise ValueError("No se detectan Folio/RUT/Periodo. El PDF podría ser una imagen escaneada.")

        return folio.group(1).strip(), rut.group(1).strip(), periodo.group(1).strip()

    except Exception as e:
        # Re-lanzar con nombre de archivo para saber cuál falló
        raise ValueError(f"Fallo en {os.path.basename(pdf_path)}: {str(e)}")
    
    finally:
        if doc: doc.close()

# Función para exportar los datos a un archivo Excel
def export_to_excel(data, excel_path, sheet_name):
    """Exporta datos a una hoja de Excel, con formato especial para códigos.

    Args:
        data (list/dict): Datos a exportar
        excel_path (str): Ruta del archivo Excel
        sheet_name (str): Nombre de la hoja a crear

    Returns:
        None: Guarda los datos en el archivo Excel
    """
    df = pd.DataFrame(data)

    # Función para convertir solo los códigos numéricos
    def convert_code(value):
        if isinstance(value, str) and value.isdigit():
            return int(value)
        return value

    # Aplicar la conversión solo a los valores numéricos
    df["Código"] = df["Código"].apply(convert_code)

    # Ordenar los datos: primero los no numéricos, luego los numéricos
    df["Es_Numérico"] = df["Código"].apply(lambda x: isinstance(x, int))
    df = df.sort_values(by=["Es_Numérico", "Código"], ascending=[False, True])
    df = df.drop(columns=["Es_Numérico"])

    # Exportar a Excel
    with pd.ExcelWriter(excel_path, engine="openpyxl",
        mode="a" if os.path.exists(excel_path) else "w") as writer:
        df.to_excel(writer, sheet_name=sheet_name, index=False)
