"""
Fallback PDF Generation utility for invoices using ReportLab
This is used when WeasyPrint is not available due to system dependencies
"""

import os
from datetime import datetime

from flask import current_app
from flask_babel import gettext as _
from reportlab.lib import colors
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_RIGHT
from reportlab.lib.pagesizes import A4
from reportlab.lib.styles import ParagraphStyle, getSampleStyleSheet
from reportlab.lib.units import cm
from reportlab.pdfgen import canvas
from reportlab.platypus import Image, Paragraph, SimpleDocTemplate, Spacer, Table, TableStyle

from app.models import Settings


class InvoicePDFGeneratorFallback:
    """Generate PDF invoices with company branding using ReportLab"""

    def __init__(self, invoice, settings=None):
        self.invoice = invoice
        self.settings = settings or Settings.get_settings()
        self.styles = getSampleStyleSheet()
        self._setup_custom_styles()

    def _setup_custom_styles(self):
        """Setup custom paragraph styles"""
        self.styles.add(
            ParagraphStyle(
                name="CompanyName",
                parent=self.styles["Heading1"],
                fontSize=18,
                spaceAfter=12,
                textColor=colors.HexColor("#007bff"),
            )
        )

        self.styles.add(
            ParagraphStyle(
                name="InvoiceTitle",
                parent=self.styles["Heading1"],
                fontSize=24,
                spaceAfter=20,
                textColor=colors.HexColor("#007bff"),
                alignment=TA_RIGHT,
            )
        )

        self.styles.add(
            ParagraphStyle(
                name="SectionHeader",
                parent=self.styles["Heading2"],
                fontSize=14,
                spaceAfter=8,
                textColor=colors.HexColor("#007bff"),
            )
        )

        self.styles.add(ParagraphStyle(name="NormalText", parent=self.styles["Normal"], fontSize=10, spaceAfter=6))

    def generate_pdf(self):
        """Generate PDF content and return as bytes"""
        # Create a temporary file to store the PDF
        import io
        import tempfile

        with tempfile.NamedTemporaryFile(suffix=".pdf", delete=False) as tmp_file:
            tmp_path = tmp_file.name

        try:
            # Generate the PDF
            doc = SimpleDocTemplate(
                tmp_path, pagesize=A4, rightMargin=2 * cm, leftMargin=2 * cm, topMargin=2 * cm, bottomMargin=2 * cm
            )

            # Build the story (content)
            story = self._build_story()

            # Build the PDF with page numbers
            doc.build(story, onFirstPage=self._add_page_number, onLaterPages=self._add_page_number)

            # Read the generated PDF
            with open(tmp_path, "rb") as f:
                pdf_bytes = f.read()

            return pdf_bytes

        finally:
            # Clean up temporary file
            if os.path.exists(tmp_path):
                os.unlink(tmp_path)

    def _build_story(self):
        """Build the PDF content story"""
        story = []

        # Header section
        story.extend(self._build_header())
        story.append(Spacer(1, 20))

        # Client and project information
        story.extend(self._build_client_section())
        story.append(Spacer(1, 20))

        # Invoice items table
        story.extend(self._build_items_table())
        story.append(Spacer(1, 20))

        # Additional information
        story.extend(self._build_additional_info())
        story.append(Spacer(1, 20))

        # Footer
        story.extend(self._build_footer())

        return story

    def _build_header(self):
        """Build the header section with company info and invoice details"""
        story = []

        # Company information (left side)
        company_info = []
        company_info.append(Paragraph(self.settings.company_name, self.styles["CompanyName"]))

        if self.settings.company_address:
            company_info.append(Paragraph(self.settings.company_address, self.styles["NormalText"]))

        if self.settings.company_email:
            company_info.append(Paragraph(f"Email: {self.settings.company_email}", self.styles["NormalText"]))

        if self.settings.company_phone:
            company_info.append(Paragraph(f"Phone: {self.settings.company_phone}", self.styles["NormalText"]))

        if self.settings.company_website:
            company_info.append(Paragraph(f"Website: {self.settings.company_website}", self.styles["NormalText"]))

        if self.settings.company_tax_id:
            company_info.append(Paragraph(f"Tax ID: {self.settings.company_tax_id}", self.styles["NormalText"]))

        if getattr(self.settings, "invoices_peppol_compliant", False):
            sid = (getattr(self.settings, "peppol_sender_endpoint_id", None) or "").strip()
            ssc = (getattr(self.settings, "peppol_sender_scheme_id", None) or "").strip()
            if sid and ssc:
                company_info.append(Paragraph(f"PEPPOL Endpoint: {ssc}:{sid}", self.styles["NormalText"]))

        # Invoice information (right side)
        invoice_info = []

        # Add logo if available (top right) using Image flowable
        if self.settings.has_logo():
            logo_path = self.settings.get_logo_path()
            if logo_path and os.path.exists(logo_path):
                try:
                    img = Image(logo_path, width=4 * cm, height=2 * cm, kind="proportional")
                    invoice_info.append(img)
                    invoice_info.append(Spacer(1, 6))
                except Exception:
                    # Fallback to text if image fails
                    invoice_info.append(Paragraph("[Company Logo]", self.styles["NormalText"]))

        invoice_info.append(Paragraph(_("INVOICE"), self.styles["InvoiceTitle"]))
        invoice_info.append(
            Paragraph(_("Invoice #: %(num)s", num=self.invoice.invoice_number), self.styles["NormalText"])
        )
        try:
            # Use DD.MM.YYYY format for invoices and quotes
            issue_label = _("Issue Date: %(date)s", date=self.invoice.issue_date.strftime("%d.%m.%Y"))
            due_label = _("Due Date: %(date)s", date=self.invoice.due_date.strftime("%d.%m.%Y"))
        except Exception:
            issue_label = _("Issue Date: %(date)s", date=self.invoice.issue_date.strftime("%d.%m.%Y"))
            due_label = _("Due Date: %(date)s", date=self.invoice.due_date.strftime("%d.%m.%Y"))
        invoice_info.append(Paragraph(issue_label, self.styles["NormalText"]))
        invoice_info.append(Paragraph(due_label, self.styles["NormalText"]))
        invoice_info.append(Paragraph(f"Status: {self.invoice.status.title()}", self.styles["NormalText"]))

        # Create a table to layout company info and invoice info side by side
        header_data = [[company_info, invoice_info]]
        header_table = Table(header_data, colWidths=[9 * cm, 6 * cm])
        header_table.setStyle(
            TableStyle(
                [
                    ("ALIGN", (0, 0), (0, 0), "LEFT"),
                    ("ALIGN", (1, 0), (1, 0), "RIGHT"),
                    ("VALIGN", (0, 0), (-1, -1), "TOP"),
                ]
            )
        )

        story.append(header_table)
        return story

    def _build_client_section(self):
        """Build the client and project information section"""
        story = []

        # Client information
        story.append(Paragraph("Bill To:", self.styles["SectionHeader"]))
        story.append(Paragraph(self.invoice.client_name, self.styles["NormalText"]))

        if self.invoice.client_email:
            story.append(Paragraph(self.invoice.client_email, self.styles["NormalText"]))

        if self.invoice.client_address:
            story.append(Paragraph(self.invoice.client_address, self.styles["NormalText"]))

        if getattr(self.settings, "invoices_peppol_compliant", False) and getattr(self.invoice, "client", None):
            client = self.invoice.client
            bvat = (client.get_custom_field("vat_id", "") or client.get_custom_field("tax_id", "") or "").strip()
            if bvat:
                story.append(Paragraph(f"VAT ID: {bvat}", self.styles["NormalText"]))
            beid = (client.get_custom_field("peppol_endpoint_id", "") or "").strip()
            bsc = (client.get_custom_field("peppol_scheme_id", "") or "").strip()
            if beid and bsc:
                story.append(Paragraph(f"PEPPOL Endpoint: {bsc}:{beid}", self.styles["NormalText"]))

        story.append(Spacer(1, 12))

        # Project information
        story.append(Paragraph("Project:", self.styles["SectionHeader"]))
        story.append(Paragraph(self.invoice.project.name, self.styles["NormalText"]))

        if self.invoice.project.description:
            story.append(Paragraph(self.invoice.project.description, self.styles["NormalText"]))

        return story

    def _build_items_table(self):
        """Build the invoice items table including extra goods"""
        story = []

        story.append(Paragraph(_("Invoice Items"), self.styles["SectionHeader"]))

        # Table headers
        headers = [_("Description"), _("Quantity (Hours)"), _("Unit Price"), _("Total Amount")]

        # Table data
        data = [headers]

        # Add regular invoice items
        for item in self.invoice.items:
            row = [
                item.description,
                f"{item.quantity:.2f}",
                self._format_currency(item.unit_price),
                self._format_currency(item.total_amount),
            ]
            data.append(row)

        # Add extra goods
        for good in self.invoice.extra_goods:
            # Build description with additional details
            description_parts = [good.name]
            if good.description:
                description_parts.append(f"\n{good.description}")
            if good.sku:
                description_parts.append(f"\nSKU: {good.sku}")
            if good.category:
                description_parts.append(f"\nCategory: {good.category.title()}")

            description = "\n".join(description_parts)

            row = [
                description,
                f"{good.quantity:.2f}",
                self._format_currency(good.unit_price),
                self._format_currency(good.total_amount),
            ]
            data.append(row)

        # Add expenses
        expenses = (
            self.invoice.expenses.all()
            if hasattr(self.invoice.expenses, "all")
            else list(self.invoice.expenses) if getattr(self.invoice, "expenses", None) else []
        )
        for expense in expenses:
            description_parts = [expense.title]
            if expense.description:
                description_parts.append(f"\n{expense.description}")
            if expense.category:
                description_parts.append(f"\n{_('Expense')}: {expense.category.title()}")
            if expense.vendor:
                description_parts.append(f"\n{_('Vendor')}: {expense.vendor}")
            if expense.expense_date:
                description_parts.append(f"\n{_('Date')}: {expense.expense_date.strftime('%d.%m.%Y')}")

            description = "\n".join(description_parts)
            total = getattr(expense, "total_amount", expense.amount)

            row = [
                description,
                "1",
                self._format_currency(total),
                self._format_currency(total),
            ]
            data.append(row)

        # Add totals
        data.append(["", "", _("Subtotal:"), self._format_currency(self.invoice.subtotal)])

        if self.invoice.tax_rate > 0:
            data.append(
                [
                    "",
                    "",
                    _("Tax (%(rate).2f%%):", rate=self.invoice.tax_rate),
                    self._format_currency(self.invoice.tax_amount),
                ]
            )

        data.append(["", "", _("Total Amount:"), self._format_currency(self.invoice.total_amount)])

        # Create table
        table = Table(data, colWidths=[9 * cm, 3 * cm, 3 * cm, 3 * cm], repeatRows=1)
        table.setStyle(
            TableStyle(
                [
                    ("BACKGROUND", (0, 0), (-1, 0), colors.HexColor("#f8fafc")),
                    ("TEXTCOLOR", (0, 0), (-1, 0), colors.HexColor("#475569")),
                    ("ALIGN", (0, 0), (-1, -1), "LEFT"),
                    ("ALIGN", (1, 1), (-1, -1), "RIGHT"),
                    ("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"),
                    ("FONTSIZE", (0, 0), (-1, 0), 12),
                    ("BOTTOMPADDING", (0, 0), (-1, 0), 12),
                    ("BACKGROUND", (0, -3), (-1, -1), colors.HexColor("#eef2ff")),
                    ("FONTNAME", (0, -3), (-1, -1), "Helvetica-Bold"),
                    ("GRID", (0, 0), (-1, -1), 0.5, colors.HexColor("#e2e8f0")),
                    ("BOX", (0, 0), (-1, -1), 0.8, colors.HexColor("#e2e8f0")),
                ]
            )
        )

        story.append(table)
        return story

    def _format_currency(self, value):
        """Format numeric currency with thousands separators and 2 decimals."""
        try:
            return f"{float(value):,.2f} {self.settings.currency}"
        except Exception:
            return f"{value} {self.settings.currency}"

    def _add_page_number(self, canv, doc):
        """Add page number at the bottom-right of each page."""
        page_num = canv.getPageNumber()
        text = f"Page {page_num}"

        # Get page dimensions for boundary checking
        page_width = doc.pagesize[0]
        page_height = doc.pagesize[1]

        canv.saveState()
        canv.setFont("Helvetica", 9)
        try:
            canv.setFillColor(colors.HexColor("#666666"))
        except Exception:
            pass

        # Ensure page number is within page boundaries
        x = min(doc.leftMargin + doc.width, page_width - 10)
        y = max(doc.bottomMargin - 0.5 * cm, 10)
        canv.drawRightString(x, y, text)

        canv.restoreState()

    def _build_additional_info(self):
        """Build additional information section"""
        story = []

        if self.invoice.notes:
            story.append(Paragraph(_("Notes:"), self.styles["SectionHeader"]))
            story.append(Paragraph(self.invoice.notes, self.styles["NormalText"]))
            story.append(Spacer(1, 12))

        if self.invoice.terms:
            story.append(Paragraph(_("Terms:"), self.styles["SectionHeader"]))
            story.append(Paragraph(self.invoice.terms, self.styles["NormalText"]))
            story.append(Spacer(1, 12))

        return story

    def _build_footer(self):
        """Build the footer section"""
        story = []

        # Payment information
        if self.settings.company_bank_info:
            story.append(Paragraph(_("Payment Information:"), self.styles["SectionHeader"]))
            story.append(Paragraph(self.settings.company_bank_info, self.styles["NormalText"]))
            story.append(Spacer(1, 12))

        # Terms and conditions
        story.append(Paragraph(_("Terms & Conditions:"), self.styles["SectionHeader"]))
        story.append(Paragraph(self.settings.invoice_terms, self.styles["NormalText"]))

        return story


def format_quote_item_description_for_pdf(item) -> str:
    """Label for a quote line including expense/goods metadata (issue #585)."""
    dn = getattr(item, "display_name", None)
    desc = (getattr(item, "description", None) or "") or ""
    lk = (getattr(item, "line_kind", None) or "item") or "item"
    if dn:
        text = str(dn)
        if desc and str(desc) not in (str(dn), "-"):
            text = f"{text} — {desc}"
    else:
        text = str(desc)
    if lk == "expense" and getattr(item, "category", None):
        text = f"{text} ({item.category})"
    if lk == "good" and getattr(item, "sku", None):
        text = f"{text} [SKU: {item.sku}]"
    return text


class QuotePDFGeneratorFallback:
    """Generate PDF quotes with company branding using ReportLab"""

    def __init__(self, quote, settings=None):
        self.quote = quote
        self.settings = settings or Settings.get_settings()
        self.styles = getSampleStyleSheet()
        self._setup_custom_styles()

    def _setup_custom_styles(self):
        """Setup custom paragraph styles"""
        self.styles.add(
            ParagraphStyle(
                name="CompanyName",
                parent=self.styles["Heading1"],
                fontSize=18,
                spaceAfter=12,
                textColor=colors.HexColor("#007bff"),
            )
        )

        self.styles.add(
            ParagraphStyle(
                name="QuoteTitle",
                parent=self.styles["Heading1"],
                fontSize=24,
                spaceAfter=20,
                textColor=colors.HexColor("#007bff"),
                alignment=TA_RIGHT,
            )
        )

        self.styles.add(
            ParagraphStyle(
                name="SectionHeader",
                parent=self.styles["Heading2"],
                fontSize=14,
                spaceAfter=8,
                textColor=colors.HexColor("#007bff"),
            )
        )

        self.styles.add(ParagraphStyle(name="NormalText", parent=self.styles["Normal"], fontSize=10, spaceAfter=6))

    def generate_pdf(self):
        """Generate PDF content and return as bytes"""
        import io
        import tempfile

        with tempfile.NamedTemporaryFile(suffix=".pdf", delete=False) as tmp_file:
            tmp_path = tmp_file.name

        try:
            doc = SimpleDocTemplate(
                tmp_path, pagesize=A4, rightMargin=2 * cm, leftMargin=2 * cm, topMargin=2 * cm, bottomMargin=2 * cm
            )

            story = self._build_story()
            doc.build(story, onFirstPage=self._add_page_number, onLaterPages=self._add_page_number)

            with open(tmp_path, "rb") as f:
                pdf_bytes = f.read()

            return pdf_bytes

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

    def _build_story(self):
        """Build the PDF content story"""
        story = []

        # Header
        story.extend(self._build_header())
        story.append(Spacer(1, 20))

        # Client section
        story.extend(self._build_client_section())
        story.append(Spacer(1, 20))

        # Quote items
        story.extend(self._build_items_table())
        story.append(Spacer(1, 20))

        # Totals
        story.extend(self._build_totals())
        story.append(Spacer(1, 20))

        # Additional info
        story.extend(self._build_additional_info())

        return story

    def _build_header(self):
        """Build header section"""
        story = []

        # Company name and info
        if self.settings.company_name:
            story.append(Paragraph(self.settings.company_name, self.styles["CompanyName"]))

        if self.settings.company_address:
            story.append(Paragraph(self.settings.company_address.replace("\n", "<br/>"), self.styles["NormalText"]))

        story.append(Spacer(1, 12))

        # Quote title and number
        quote_title = f"{_('QUOTE')} {self.quote.quote_number}"
        story.append(Paragraph(quote_title, self.styles["QuoteTitle"]))

        return story

    def _build_client_section(self):
        """Build client information section"""
        story = []

        if self.quote.client:
            story.append(Paragraph(_("Quote For:"), self.styles["SectionHeader"]))
            story.append(Paragraph(self.quote.client.name, self.styles["NormalText"]))
            if self.quote.client.address:
                story.append(Paragraph(self.quote.client.address.replace("\n", "<br/>"), self.styles["NormalText"]))
            if self.quote.client.email:
                story.append(Paragraph(f"Email: {self.quote.client.email}", self.styles["NormalText"]))

        story.append(Spacer(1, 12))

        # Quote details
        story.append(Paragraph(_("Quote Details:"), self.styles["SectionHeader"]))
        story.append(Paragraph(f"{_('Title')}: {self.quote.title}", self.styles["NormalText"]))
        story.append(
            Paragraph(
                f"{_('Date')}: {self.quote.created_at.strftime('%Y-%m-%d') if self.quote.created_at else 'N/A'}",
                self.styles["NormalText"],
            )
        )
        if self.quote.valid_until:
            story.append(
                Paragraph(
                    f"{_('Valid Until')}: {self.quote.valid_until.strftime('%Y-%m-%d')}", self.styles["NormalText"]
                )
            )

        return story

    def _build_items_table(self):
        """Build quote items table"""
        story = []

        story.append(Paragraph(_("Items:"), self.styles["SectionHeader"]))

        # Table data
        data = [[_("Description"), _("Quantity"), _("Unit Price"), _("Total")]]

        for item in self.quote.items:
            data.append(
                [
                    format_quote_item_description_for_pdf(item),
                    str(item.quantity),
                    self._format_currency(item.unit_price),
                    self._format_currency(item.total_amount),
                ]
            )

        table = Table(data, colWidths=[8 * cm, 2 * cm, 3 * cm, 3 * cm])
        table.setStyle(
            TableStyle(
                [
                    ("BACKGROUND", (0, 0), (-1, 0), colors.HexColor("#007bff")),
                    ("TEXTCOLOR", (0, 0), (-1, 0), colors.whitesmoke),
                    ("ALIGN", (0, 0), (-1, -1), "LEFT"),
                    ("ALIGN", (1, 0), (-1, -1), "RIGHT"),
                    ("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"),
                    ("FONTSIZE", (0, 0), (-1, 0), 10),
                    ("BOTTOMPADDING", (0, 0), (-1, 0), 12),
                    ("BACKGROUND", (0, 1), (-1, -1), colors.beige),
                    ("GRID", (0, 0), (-1, -1), 1, colors.black),
                ]
            )
        )

        story.append(table)

        return story

    def _build_totals(self):
        """Build totals section"""
        story = []

        # Calculate totals
        self.quote.calculate_totals()

        totals_data = [
            [_("Subtotal:"), self._format_currency(self.quote.subtotal)],
        ]

        if self.quote.tax_rate > 0:
            totals_data.append([f"{_('Tax')} ({self.quote.tax_rate}%):", self._format_currency(self.quote.tax_amount)])

        totals_data.append([_("Total:"), self._format_currency(self.quote.total_amount)])

        totals_table = Table(totals_data, colWidths=[6 * cm, 4 * cm])
        totals_table.setStyle(
            TableStyle(
                [
                    ("ALIGN", (0, 0), (-1, -1), "RIGHT"),
                    ("FONTNAME", (-1, -1), (-1, -1), "Helvetica-Bold"),
                    ("FONTSIZE", (-1, -1), (-1, -1), 12),
                    ("TOPPADDING", (0, 0), (-1, -1), 6),
                    ("BOTTOMPADDING", (0, 0), (-1, -1), 6),
                ]
            )
        )

        story.append(Spacer(1, 12))
        story.append(totals_table)

        return story

    def _build_additional_info(self):
        """Build additional information section"""
        story = []

        if self.quote.description:
            story.append(Paragraph(_("Description:"), self.styles["SectionHeader"]))
            story.append(Paragraph(self.quote.description.replace("\n", "<br/>"), self.styles["NormalText"]))
            story.append(Spacer(1, 12))

        if self.quote.terms:
            story.append(Paragraph(_("Terms & Conditions:"), self.styles["SectionHeader"]))
            story.append(Paragraph(self.quote.terms.replace("\n", "<br/>"), self.styles["NormalText"]))

        return story

    def _format_currency(self, value):
        """Format currency value"""
        currency = self.quote.currency_code if self.quote.currency_code else "EUR"
        return f"{currency} {float(value):.2f}"

    def _add_page_number(self, canv, doc):
        """Add page number to PDF"""
        page_num = canv.getPageNumber()
        text = f"{_('Page')} {page_num}"

        # Get page dimensions for boundary checking
        page_width = doc.pagesize[0]
        page_height = doc.pagesize[1]

        canv.saveState()
        canv.setFont("Helvetica", 9)
        # Ensure page number is within page boundaries
        x = min(page_width - 2 * cm, page_width - 10)
        y = max(1 * cm, 10)
        canv.drawRightString(x, y, text)

        canv.restoreState()
