import sys
import json
import qrcode
import os
import io
from PIL import Image
from pyhanko.sign import signers, fields
from pyhanko.pdf_utils.incremental_writer import IncrementalPdfFileWriter
from pyhanko.sign.fields import SigFieldSpec
from pypdf import PdfWriter, PdfReader
from reportlab.pdfgen import canvas

def generar_qr(url, path):
    qr = qrcode.QRCode(
        version=1,
        error_correction=qrcode.constants.ERROR_CORRECT_H,
        box_size=10,
        border=1,
    )
    qr.add_data(url)
    qr.make(fit=True)
    img = qr.make_image(fill_color="black", back_color="white")
    img.save(path)
    return path

def agregar_visual_flujo2(input_path, output_path, args):
    reader  = PdfReader(input_path)
    writer  = PdfWriter()
    sellos  = args.get('sellos', [])
    codigo  = args['codigo']
    fecha   = args['fecha']
    fecha2  = args['fecha2']
    fk_user = args.get('fk_user', 0)

    qr_temps = {}
    for sello in sellos:
        if sello['type'] == 1:
            qr_path = input_path + '_qr_' + str(sello['eje_x']) + '.png'
            generar_qr(sello['qr_url'], qr_path)
            qr_temps[id(sello)] = qr_path

    for page_num, page in enumerate(reader.pages):
        page_width  = float(page.mediabox.width)
        page_height = float(page.mediabox.height)

        packet = io.BytesIO()
        c = canvas.Canvas(packet, pagesize=(page_width, page_height))

        for sello in sellos:
            eje_x  = float(sello.get('eje_x') or 0)
            eje_y  = float(sello.get('eje_y') or 0)
            width  = float(sello.get('width') or 50)
            height = float(sello.get('height') or 50)
            rl_y   = page_height - eje_y - height

            if sello['type'] == 1:
                # qr_size   = width
                # qr_height = height
                qr_size   = float( 50) # usar width del sello
                qr_height = float(50) # usar height del sello
                qr_path   = qr_temps.get(id(sello))
                rl_qr_y   = page_height - eje_y - qr_height

                c.drawImage(qr_path, eje_x, rl_qr_y, qr_size, qr_height, mask='auto')

                font_size = max(4, int(qr_size * 0.10))
                line_h    = font_size + 2
                text_y    = rl_qr_y - line_h - 2

                c.setFont("Times-Roman", font_size)
                c.setFillColorRGB(0, 0, 0)
                c.drawString(eje_x, text_y,              'document.fasttek.com.pe/verify')
                c.drawString(eje_x, text_y - line_h,     'codigo: ' + codigo)
                c.drawString(eje_x, text_y - line_h * 2, 'FIRMADO DIGITALMENTE POR')

                if fk_user == 24:
                    c.drawString(eje_x, text_y - line_h * 3, 'Asterio Francisco Carbajal Rojas')
                    c.drawString(eje_x, text_y - line_h * 4, 'abogado CIP: 64028')
                elif fk_user == 35:
                    c.drawString(eje_x, text_y - line_h * 3, 'RICARDO FERNANDINI PINTO')
                    c.drawString(eje_x, text_y - line_h * 4, 'COMPOSTELA E.I.R.L')
                else:
                    c.drawString(eje_x, text_y - line_h * 3, 'RICARDO FERNANDINI BARREDA')
                    c.drawString(eje_x, text_y - line_h * 4, 'NOTARIO DE LIMA')

                c.drawString(eje_x, text_y - line_h * 5, fecha)

            elif sello['type'] == 2:
                img_path = sello.get('image_path')
                if img_path and os.path.exists(img_path):
                    c.drawImage(img_path, eje_x, rl_y, width, height, mask='auto')

            elif sello['type'] == 3:
                img_path = sello.get('image_path')
                if img_path and os.path.exists(img_path):
                    c.drawImage(img_path, eje_x, rl_y, width, height, mask='auto')
                c.setFont("Times-Roman", 9)
                c.setFillColorRGB(0.37, 0.50, 0.93)
                c.drawString(eje_x + 50, rl_y + height - 6,  str(len(reader.pages)))
                c.drawString(eje_x + 30, rl_y + height - 14, fecha2)

        c.save()
        packet.seek(0)
        overlay = PdfReader(packet)
        page.merge_page(overlay.pages[0])
        writer.add_page(page)

    with open(output_path, 'wb') as f:
        writer.write(f)

    for qr_path in qr_temps.values():
        if os.path.exists(qr_path):
            os.unlink(qr_path)

def agregar_visual_flujo_default(input_path, output_path, args):
    codigo     = args['codigo']
    fecha      = args['fecha']
    plantilla  = args.get('plantilla')
    fecha_top  = float(args.get('fecha_top', 105))
    fecha_left = float(args.get('fecha_left', 45))
    qr_url     = args['qr_url']
    qr_x       = float(args.get('qr_x', 10))
    qr_y       = float(args.get('qr_y', 242))
    qr_size    = float(args.get('qr_size', 35))

    qr_path = input_path + '_qr_default.png'
    generar_qr(qr_url, qr_path)

    try:
        reader_orig = PdfReader(input_path)
        writer      = PdfWriter()

        for page in reader_orig.pages:
            writer.add_page(page)

        if plantilla and os.path.exists(plantilla):
            reader_plantilla = PdfReader(plantilla)

            for page in reader_plantilla.pages:
                page_width  = float(page.mediabox.width)
                page_height = float(page.mediabox.height)

                packet = io.BytesIO()
                c = canvas.Canvas(packet, pagesize=(page_width, page_height))

                rl_fecha_y = page_height - fecha_top
                c.setFont("Times-Roman", 12)
                c.setFillColorRGB(0, 0, 0)
                c.drawString(fecha_left, rl_fecha_y, fecha)

                rl_qr_y = page_height - qr_y - qr_size
                c.drawImage(qr_path, qr_x, rl_qr_y, qr_size, qr_size, mask='auto')

                c.setFont("Helvetica", 8)
                c.drawString(qr_x + 1, rl_qr_y - 8,  'document.fasttek.com.pe/verify')
                c.drawString(qr_x + 1, rl_qr_y - 16, 'FIRMADO DIGITALMENTE')
                c.drawString(qr_x + 1, rl_qr_y - 24, 'codigo: ' + codigo)

                c.save()
                packet.seek(0)
                overlay = PdfReader(packet)
                page.merge_page(overlay.pages[0])
                writer.add_page(page)

        with open(output_path, 'wb') as f:
            writer.write(f)

    finally:
        if os.path.exists(qr_path):
            os.unlink(qr_path)

def firmar_digitalmente(visual_path, output_path, cert_path, key_path, fk_user):
    with open(visual_path, 'rb') as inf:
        writer = IncrementalPdfFileWriter(inf, strict=False)

        fields.append_signature_field(
            writer,
            sig_field_spec=SigFieldSpec(
                sig_field_name='FirmaDigital',
                on_page=0,
                box=(0, 0, 0, 0)
            )
        )

        signer = signers.SimpleSigner.load(
            key_path,
            cert_path,
            key_passphrase=None
        )

        if fk_user == 24:
            firmante = 'Asterio Francisco Carbajal Rojas'
        elif fk_user == 35:
            firmante = 'RICARDO FERNANDINI PINTO'
        else:
            firmante = 'RICARDO FERNANDINI BARREDA'

        meta = signers.PdfSignatureMetadata(
            field_name='FirmaDigital',
            reason='Firmado Digitalmente',
            location='Lima, Peru',
            name=firmante,
            certify=False
        )

        pdf_signer = signers.PdfSigner(
            meta,
            signer=signer,
            stamp_style=None
        )

        with open(output_path, 'wb') as outf:
            pdf_signer.sign_pdf(writer, output=outf)

def firmar_pdf(args):
    input_path  = args['input']
    output_path = args['output']
    cert_path   = args['cert']
    key_path    = args['key']
    flujo       = args.get('flujo', 1)
    fk_user     = args.get('fk_user', 0)
    visual_path = input_path + '_visual.pdf'

    try:
        if flujo == 2:
            agregar_visual_flujo2(input_path, visual_path, args)
        else:
            agregar_visual_flujo_default(input_path, visual_path, args)

        firmar_digitalmente(visual_path, output_path, cert_path, key_path, fk_user)

        print(json.dumps({'success': True, 'output': output_path}))

    except Exception as e:
        print(json.dumps({'success': False, 'error': str(e)}))
        sys.exit(1)

    finally:
        if os.path.exists(visual_path):
            os.unlink(visual_path)

if __name__ == '__main__':
    try:
        args = json.loads(sys.argv[1])
        firmar_pdf(args)
    except Exception as e:
        print(json.dumps({'success': False, 'error': str(e)}))
        sys.exit(1)
