# -*- coding: utf-8 -*-
# Fusion PDF Template Filler
# Generic utility for filling any PDF template with data overlays.
# Uses the same pattern as Odoo Enterprise Sign module (sign/utils/pdf_handling.py):
#   - Read original PDF page dimensions from mediaBox
#   - Create reportlab Canvas overlay at the same page size
#   - Convert percentage positions (0.0-1.0) to absolute PDF coordinates
#   - Merge overlay onto original page via mergePage()

import logging
from io import BytesIO

from reportlab.pdfgen import canvas
from reportlab.lib.utils import ImageReader

from odoo.tools.pdf import PdfFileReader, PdfFileWriter

_logger = logging.getLogger(__name__)


class PDFTemplateFiller:
    """Generic PDF template filler. Works with any template, any number of pages."""

    @staticmethod
    def fill_template(template_pdf_bytes, fields_by_page, context, signatures=None):
        """Fill a PDF template by overlaying text/checkmarks/signatures at configured positions.

        Args:
            template_pdf_bytes: bytes of the original PDF
            fields_by_page: {page_num: [field_dicts]} where page_num is 1-based
                Each field_dict has: field_key, pos_x, pos_y, width, height,
                                     field_type, font_size, font_name
            context: flat dict of {field_key: value} with all available data
            signatures: dict of {field_key: binary_png} for signature image fields

        Returns:
            bytes of the filled PDF (all pages preserved)
        """
        if signatures is None:
            signatures = {}

        try:
            original = PdfFileReader(BytesIO(template_pdf_bytes))
        except Exception as e:
            _logger.error("Failed to read template PDF: %s", e)
            raise

        output = PdfFileWriter()
        num_pages = original.getNumPages()

        for page_idx in range(num_pages):
            page = original.getPage(page_idx)
            page_num = page_idx + 1  # 1-based page number
            mb = page.mediaBox
            page_w = float(mb.getWidth())
            page_h = float(mb.getHeight())
            origin_x = float(mb.getLowerLeft_x())
            origin_y = float(mb.getLowerLeft_y())

            fields = fields_by_page.get(page_num, [])

            if fields:
                overlay_buf = BytesIO()
                c = canvas.Canvas(
                    overlay_buf,
                    pagesize=(origin_x + page_w, origin_y + page_h),
                )

                for field in fields:
                    PDFTemplateFiller._draw_field(
                        c, field, context, signatures,
                        page_w, page_h, origin_x, origin_y,
                    )

                c.save()
                overlay_buf.seek(0)

                # Merge overlay onto original page (same as sign module)
                overlay_pdf = PdfFileReader(overlay_buf)
                page.mergePage(overlay_pdf.getPage(0))

            output.addPage(page)

        result = BytesIO()
        output.write(result)
        return result.getvalue()

    @staticmethod
    def _draw_field(c, field, context, signatures,
                    page_w, page_h, origin_x=0, origin_y=0):
        """Draw a single field onto the reportlab canvas.

        Args:
            c: reportlab Canvas
            field: dict with field_key, pos_x, pos_y, width, height, field_type, etc.
            context: data context dict
            signatures: dict of {field_key: binary} for signature fields
            page_w: page width in PDF points
            page_h: page height in PDF points
            origin_x: mediaBox lower-left X (accounts for non-zero origin)
            origin_y: mediaBox lower-left Y (accounts for non-zero origin)
        """
        field_key = field.get('field_key') or field.get('field_name', '')
        field_type = field.get('field_type', 'text')
        value = context.get(field_key, field.get('default_value', ''))

        if not value and field_type != 'signature':
            return

        # Convert percentage positions to absolute PDF coordinates.
        # pos_x/pos_y are 0.0-1.0 ratios from top-left of the visible page.
        # PDF coordinate system: origin at bottom-left, Y goes up.
        # origin_x/origin_y account for PDFs whose mediaBox doesn't start at (0,0).
        abs_x = field['pos_x'] * page_w + origin_x
        abs_y = (origin_y + page_h) - (field['pos_y'] * page_h)

        font_name = field.get('font_name', 'Helvetica')
        font_size = field.get('font_size', 10.0)

        if field_type in ('text', 'date'):
            c.setFont(font_name, font_size)
            text_val = str(value)
            field_h = field.get('height', 0.018) * page_h
            text_y = abs_y - field_h + (field_h - font_size) / 2
            align = field.get('text_align', 'left')
            if align == 'center':
                center_x = abs_x + (field.get('width', 0.15) * page_w) / 2
                c.drawCentredString(center_x, text_y, text_val)
            elif align == 'right':
                right_x = abs_x + field.get('width', 0.15) * page_w
                c.drawRightString(right_x, text_y, text_val)
            else:
                c.drawString(abs_x, text_y, text_val)

        elif field_type == 'checkbox':
            if value:
                # Draw a cross mark (✗) that fills the checkbox box
                cb_w = field.get('width', 0.015) * page_w
                cb_h = field.get('height', 0.018) * page_h
                # Inset slightly so the cross doesn't touch the box edges
                pad = min(cb_w, cb_h) * 0.15
                x1 = abs_x + pad
                y1 = abs_y - cb_h + pad
                x2 = abs_x + cb_w - pad
                y2 = abs_y - pad
                c.saveState()
                c.setStrokeColorRGB(0, 0, 0)
                c.setLineWidth(1.5)
                # Draw X (two diagonal lines)
                c.line(x1, y1, x2, y2)
                c.line(x1, y2, x2, y1)
                c.restoreState()

        elif field_type == 'signature':
            sig_data = signatures.get(field_key)
            if sig_data:
                try:
                    img = ImageReader(BytesIO(sig_data))
                    sig_w = field.get('width', 0.15) * page_w
                    sig_h = field.get('height', 0.05) * page_h
                    # Draw signature image (position from top, so adjust Y)
                    c.drawImage(
                        img, abs_x, abs_y - sig_h,
                        width=sig_w, height=sig_h,
                        mask='auto',
                    )
                except Exception as e:
                    _logger.warning("Failed to draw signature for %s: %s", field_key, e)
