import sys
import json
import openpyxl
import io
import copy
from openpyxl.drawing.image import Image as OpenpyxlImage
from PIL import Image as PILImage

def copy_images(source_sheet, target_sheet):
    """Copia imágenes de una hoja a otra de manera segura en openpyxl"""
    for img in source_sheet._images:
        img_bytes = io.BytesIO(img.ref.getvalue())
        new_img = OpenpyxlImage(img_bytes)
        new_img.anchor = img.anchor
        target_sheet.add_image(new_img)

def replace_in_sheet(sheet, label, value, replace_self=False):
    """Reemplaza la celda adyacente a un texto dado, o la celda misma si replace_self=True"""
    if value is None:
        value = 'X'
        
    for row in sheet.iter_rows(min_row=1, max_row=100):
        for cell in row:
            if cell.value and isinstance(cell.value, str):
                if label.lower() in cell.value.lower():
                    if replace_self:
                        cell.value = value
                        return True
                    else:
                        # Buscar la siguiente celda lógica (saltando celdas combinadas)
                        col_idx = cell.column
                        for merged_range in sheet.merged_cells.ranges:
                            if cell.coordinate in merged_range:
                                col_idx = merged_range.max_col
                                break
                        
                        target = sheet.cell(row=cell.row, column=col_idx + 1)
                        target.value = value
                        return True
    return False

from openpyxl.drawing.spreadsheet_drawing import OneCellAnchor, AnchorMarker
from openpyxl.drawing.xdr import XDRPositiveSize2D
from openpyxl.utils.cell import coordinate_to_tuple

def resize_image_constrained(img_path, max_width=540, max_height=310, container_width=660, container_height=340):
    """Abre una imagen, la redimensiona a mayor tamaño manteniendo su proporción y le añade padding transparente para desplazarla más a la derecha y abajo dentro de la tabla."""
    with PILImage.open(img_path) as img:
        width, height = img.size
        # Calcular ratio para mantener la proporción sin deformar
        ratio = min(max_width / width, max_height / height)
        
        new_width = int(width * ratio)
        new_height = int(height * ratio)
        
        # Redimensionar la imagen limpia
        img_resized = img.resize((new_width, new_height), PILImage.Resampling.LANCZOS)
        if img_resized.mode != 'RGBA':
            img_resized = img_resized.convert('RGBA')
            
        # Calcular el padding (margen) transparente sumando offset a la derecha y hacia abajo
        pad_left = max(0, ((container_width - new_width) // 2) + 30)
        pad_top = max(0, ((container_height - new_height) // 2) + 20)
        
        canvas_width = new_width + pad_left
        canvas_height = new_height + pad_top
        
        # Crear lienzo 100% transparente para actuar como padding/margen
        canvas = PILImage.new('RGBA', (canvas_width, canvas_height), (0, 0, 0, 0))
        canvas.paste(img_resized, (pad_left, pad_top))
        
        img_byte_arr = io.BytesIO()
        canvas.save(img_byte_arr, format='PNG')
        img_byte_arr.seek(0)
        
        xl_img = OpenpyxlImage(img_byte_arr)
        xl_img.width = canvas_width
        xl_img.height = canvas_height
        
        return xl_img

def clear_outside_table(sheet):
    """Limpia todo el contenido a la derecha de la columna M (columna 13)"""
    for row in sheet.iter_rows(min_col=14, max_col=50, min_row=1, max_row=100):
        for cell in row:
            if cell.value:
                cell.value = None

def main():
    if len(sys.argv) < 4:
        print("Usage: python generate_excel_report.py <template.xlsx> <data.json> <output.xlsx>")
        sys.exit(1)

    template_path = sys.argv[1]
    json_path = sys.argv[2]
    output_path = sys.argv[3]

    with open(json_path, 'r', encoding='utf-8') as f:
        data = json.load(f)

    wb = openpyxl.load_workbook(template_path)
    
    # Nombres de las hojas base
    base_names = ['Anexo (1)', 'Reporte Fotografico (1)']

    # Limpiar cualquier hoja de basura de la plantilla antes de empezar
    # para evitar que openpyxl renombre nuestras hojas (ej. 'Reporte Fotografico 11')
    for sheet_name in list(wb.sheetnames):
        if sheet_name not in base_names:
            wb.remove(wb[sheet_name])
            
    sheet_anexo = wb['Anexo (1)']
    sheet_reporte = wb['Reporte Fotografico (1)']

    obra_index = 1
    
    generated_sheet_names = []
    
    for muestra in data:
        # Anexo
        target_anexo = wb.copy_worksheet(sheet_anexo)
        target_anexo.title = f"Anexo {obra_index}"
        generated_sheet_names.append(target_anexo.title)
        copy_images(sheet_anexo, target_anexo)
        clear_outside_table(target_anexo)
        
        replace_in_sheet(target_anexo, 'Entidad Fiscalizada:', muestra.get('entidad_fiscalizada', 'X'))
        replace_in_sheet(target_anexo, 'Cuenta p', str(muestra.get('cuenta_publica', 'X')))
        replace_in_sheet(target_anexo, 'Anexo :', str(obra_index))
        replace_in_sheet(target_anexo, 'CONTRATO:', muestra.get('numero_contrato', 'X'))
        replace_in_sheet(target_anexo, 'MONTO DE CONTRATO:', muestra.get('inversion_autorizada', 'X'))
        replace_in_sheet(target_anexo, 'DESCRIPCIÓN:', muestra.get('nombre_obra', 'X'))
        replace_in_sheet(target_anexo, 'MONTO EJERCIDO:', muestra.get('inversion_ejercida', 'X'))
        replace_in_sheet(target_anexo, 'CONTRATISTA:', muestra.get('contratista', 'X'))
        
        estado = muestra.get('estado_obra')
        if estado:
            replace_in_sheet(target_anexo, estado, 'X')

        # Reportes Fotográficos
        fotos = muestra.get('fotos', [])
        fotos_count = max(1, len(fotos))
        photo_pages = (fotos_count + 1) // 2

        for p in range(1, photo_pages + 1):
            suffix = "" if p == 1 else f".{p-1}"
            target_reporte = wb.copy_worksheet(sheet_reporte)
            target_reporte.title = f"Reporte Fotografico {obra_index}{suffix}"
            generated_sheet_names.append(target_reporte.title)
            
            # Copiar logo del header asegurando que quede ajustado en A1 sin empalmarse con Cuenta Pública
            for img in sheet_reporte._images:
                row = img.anchor._from.row if hasattr(img.anchor, '_from') else 0
                if row < 10:
                    img_bytes = io.BytesIO(img.ref.getvalue())
                    new_img = OpenpyxlImage(img_bytes)
                    new_img.anchor = 'A1'
                    if new_img.width > 210:
                        ratio = 210.0 / new_img.width
                        new_img.width = 210
                        new_img.height = int(new_img.height * ratio)
                    target_reporte.add_image(new_img)

            clear_outside_table(target_reporte)

            anexo_num = str(obra_index) if p == 1 else f"{obra_index}.{p-1}"
            
            replace_in_sheet(target_reporte, 'Entidad Fiscalizada:', muestra.get('entidad_fiscalizada', 'X'))
            replace_in_sheet(target_reporte, 'Cuenta p', str(muestra.get('cuenta_publica', 'X')))
            replace_in_sheet(target_reporte, 'Anexo :', anexo_num)
            replace_in_sheet(target_reporte, 'OBRA:', muestra.get('nombre_obra', 'X'))
            replace_in_sheet(target_reporte, 'No. CONTRATO:', muestra.get('numero_contrato', 'X'))
            replace_in_sheet(target_reporte, 'IMPORTE CONTRATADO:', muestra.get('inversion_autorizada', 'X'))
            replace_in_sheet(target_reporte, 'IMPORTE EJERCIDO:', muestra.get('inversion_ejercida', 'X'))
            replace_in_sheet(target_reporte, 'CONTRATISTA:', muestra.get('contratista', 'X'))
            
            # Si no lleva fotos, marcamos la casilla
            if muestra.get('tipo_plantilla_sin_fotos', False) and p == 1:
                target_reporte['D31'] = 'X'
                
            # Insertar fotos (máximo 2 por página)
            offset = (p - 1) * 2
            
            # Foto 1
            if offset < len(fotos):
                foto1_path = fotos[offset]
                try:
                    xl_img1 = resize_image_constrained(foto1_path)
                    xl_img1.anchor = 'B17'
                    target_reporte.add_image(xl_img1)
                    replace_in_sheet(target_reporte, 'Foto:1', f"Foto:{offset+1}", replace_self=True)
                except Exception as e:
                    print(f"Error cargando foto {foto1_path}: {e}")
                    
            # Foto 2
            if offset + 1 < len(fotos):
                foto2_path = fotos[offset + 1]
                try:
                    xl_img2 = resize_image_constrained(foto2_path)
                    xl_img2.anchor = 'B40'
                    target_reporte.add_image(xl_img2)
                    replace_in_sheet(target_reporte, 'Foto:2', f"Foto:{offset+2}", replace_self=True)
                except Exception as e:
                    print(f"Error cargando foto {foto2_path}: {e}")

        obra_index += 1

    # Eliminar todas las hojas que no fueron generadas por el script
    # (esto borra las hojas base y cualquier otra hoja de ejemplo que venga en la plantilla)
    for sheet_name in wb.sheetnames:
        if sheet_name not in generated_sheet_names:
            wb.remove(wb[sheet_name])

    # Activar la primera hoja si existe
    if len(wb.sheetnames) > 0:
        wb.active = 0
    
    wb.save(output_path)
    print("Success")

if __name__ == "__main__":
    main()
