import os
from fpdf import FPDF
import config
from datetime import datetime
import qrcode
import io
from services.fiscal_service import FiscalService

class PDFGenerator(FPDF):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.set_auto_page_break(True, margin=15)

    def _safe_text(self, text):
        """Ensures text is compatible with Latin-1 (Helvetica/Core fonts)"""
        if text is None:
            return ""
        text = str(text)
        # Mapping for Cyrillic characters to Latin equivalents
        mapping = {
            'а': 'a', 'б': 'b', 'в': 'v', 'г': 'g', 'д': 'd', 'ђ': 'dj', 'е': 'e', 'ж': 'zh',
            'з': 'z', 'и': 'i', 'ј': 'j', 'к': 'k', 'л': 'l', 'љ': 'lj', 'м': 'm', 'н': 'n',
            'њ': 'nj', 'о': 'o', 'п': 'p', 'р': 'r', 'с': 's', 'т': 't', 'ћ': 'c', 'у': 'u',
            'ф': 'f', 'х': 'h', 'ц': 'c', 'ч': 'ch', 'џ': 'dz', 'ш': 'sh',
            'А': 'A', 'Б': 'B', 'В': 'V', 'Г': 'G', 'Д': 'D', 'Ђ': 'Dj', 'Е': 'E', 'Ж': 'Zh',
            'З': 'Z', 'И': 'I', 'Ј': 'J', 'К': 'K', 'Л': 'L', 'Љ': 'Lj', 'М': 'M', 'Н': 'N',
            'Њ': 'Nj', 'О': 'O', 'П': 'P', 'Р': 'R', 'С': 'S', 'Т': 'T', 'Ћ': 'C', 'У': 'U',
            'Ф': 'F', 'Х': 'H', 'Ц': 'C', 'Ч': 'Ch', 'Џ': 'Dz', 'Ш': 'Sh'
        }
        table = str.maketrans(mapping)
        text = text.translate(table)
        # Encode to latin-1 and replace any remaining unsupported chars with '?'
        return text.encode('latin-1', 'replace').decode('latin-1')

    def cell(self, w=None, h=None, text="", *args, **kwargs):
        return super().cell(w, h, self._safe_text(text), *args, **kwargs)

    def multi_cell(self, w, h=None, text="", *args, **kwargs):
        return super().multi_cell(w, h, self._safe_text(text), *args, **kwargs)
        
    def header_logo(self):
        # Placeholder for a logo if needed
        self.set_font("helvetica", "B", 20)
        self.set_text_color(31, 41, 55) # text-gray-800
        self.cell(0, 10, config.COMPANY_NAME, ln=True, align='L')
        self.set_font("helvetica", "", 8)
        self.set_text_color(107, 114, 128) # text-gray-500
        self.cell(0, 4, config.COMPANY_ADDRESS, ln=True)
        self.cell(0, 4, f"PIB: {config.COMPANY_PIB} | Ziro racun: {config.ZIRO_RACUN}", ln=True)
        self.ln(10)

    def draw_table_header(self, columns):
        self.set_fill_color(249, 250, 251) # gray-50
        self.set_text_color(55, 65, 81) # gray-700
        self.set_font("helvetica", "B", 9)
        
        for col in columns:
            self.cell(col['w'], 8, col['label'], border=1, fill=True, align=col['align'])
        self.ln()

    def format_money(self, amount):
        return f"{amount:.2f}".replace(".", ",")

class InvoiceService:
    @staticmethod
    def _get_output_path(filename):
        pdf_dir = os.path.join(config.UPLOAD_DIR, "invoices")
        os.makedirs(pdf_dir, exist_ok=True)
        filepath = os.path.join(pdf_dir, filename)
        return filepath, os.path.join("uploads", "invoices", filename).replace("\\", "/")

    @staticmethod
    def generate_uplatnica(order_id, payer_name, payer_address, amount):
        """Generates a standard Payment Slip (Uplatnica) for individuals"""
        pdf = PDFGenerator(orientation='P', unit='mm', format='A4')
        pdf.set_auto_page_break(False)
        pdf.add_page()
        pdf.set_font("helvetica", size=7)

        # Draw the structure (as in previous version but can be polished)
        pdf.rect(0, 0, 210, 99)
        pdf.line(105, 0, 105, 99)

        # ... (transferring the logic from uplatnica_generator.py) ...
        # I will keep the existing precise layout for uplatnica since it's a standard form
        labels = ["Hitnost", "Prenos", "Uplata", "Isplata"]
        for i, label in enumerate(labels):
            x = 110 + i * 22
            pdf.set_xy(x, 2)
            pdf.cell(14, 4, label)
            pdf.rect(x + 14, 2, 4, 4)
            if label == "Uplata":
                pdf.line(x + 14, 2, x + 18, 6); pdf.line(x + 18, 2, x + 14, 6)

        pdf.set_font("helvetica", "B", 8)
        pdf.set_xy(5, 5); pdf.cell(95, 5, "NALOG PLATIOCA", align="C")
        
        pdf.rect(5, 12, 95, 14)
        pdf.set_font("helvetica", size=9)
        pdf.set_xy(7, 14); pdf.cell(90, 4, payer_name[:40])
        pdf.set_xy(7, 18); pdf.cell(90, 4, payer_address[:40])

        pdf.set_font("helvetica", size=6)
        pdf.set_xy(5, 26); pdf.cell(95, 4, "(Naziv platioca)", align="C")

        pdf.rect(5, 30, 95, 14)
        pdf.set_font("helvetica", size=9)
        pdf.set_xy(7, 32); pdf.cell(90, 4, "Usluge 3D stampe")
        pdf.set_xy(7, 36); pdf.cell(90, 4, f"Narudzba {order_id}")

        pdf.set_font("helvetica", size=6)
        pdf.set_xy(5, 44); pdf.cell(95, 4, "(Svrha placanja)", align="C")

        pdf.rect(5, 48, 95, 14)
        pdf.set_font("helvetica", size=9)
        pdf.set_xy(7, 50); pdf.cell(90, 4, config.COMPANY_NAME)

        pdf.set_font("helvetica", size=6)
        pdf.set_xy(5, 62); pdf.cell(95, 4, "(Naziv primaoca)", align="C")

        pdf.set_font("helvetica", size=7)
        pdf.set_xy(110, 22); pdf.cell(10, 4, "EUR")
        pdf.rect(120, 22, 50, 10); pdf.rect(175, 22, 30, 10)
        
        pdf.set_font("helvetica", "B", 11)
        pdf.set_xy(120, 24); pdf.cell(50, 6, f"{amount:.2f}".replace(".", ","), align="C")
        pdf.set_xy(175, 24); pdf.cell(30, 6, "121", align="C")

        pdf.rect(110, 36, 95, 10)
        pdf.set_font("helvetica", size=10)
        pdf.set_xy(110, 38); pdf.cell(95, 6, config.ZIRO_RACUN, align="C")

        pdf.rect(110, 50, 20, 8); pdf.rect(135, 50, 70, 8)
        pdf.set_xy(110, 52); pdf.cell(20, 4, "00", align="C")
        pdf.set_xy(135, 52); pdf.cell(70, 4, str(order_id), align="C")

        filename = f"uplatnica_order_{order_id}.pdf"
        filepath, web_path = InvoiceService._get_output_path(filename)
        pdf.output(filepath)
        return web_path

    @staticmethod
    def generate_document(order_data, doc_type="predracun", override_price=None):
        """
        Generic generator for Predracun (Proforma) or Faktura (Invoice)
        Compliant with Montenegro VAT laws.
        """
        pdf = PDFGenerator()
        pdf.add_page()
        pdf.header_logo()

        title = "PREDRACUN (Proforma Invoice / Avansni racun)" if doc_type == "predracun" else "FAKTURA / RACUN (Invoice)"
        doc_id = f"{order_data['id']}/{datetime.now().year}"
        now_str = datetime.now().strftime('%d.%m.%Y.')
        
        pdf.set_font("helvetica", "B", 14)
        pdf.cell(0, 10, f"{title} #{doc_id}", ln=True)
        pdf.set_font("helvetica", "", 9)
        pdf.cell(0, 5, f"Mjesto izdavanja: {config.COMPANY_CITY}", ln=True)
        pdf.cell(0, 5, f"Datum izdavanja: {now_str}", ln=True)
        pdf.cell(0, 5, f"Datum prometa: {now_str}", ln=True)
        pdf.ln(10)

        # Buyer and Seller horizontal layout
        pdf.set_font("helvetica", "B", 10)
        pdf.cell(95, 5, "PRODAVAC / SUPPLIER:", ln=False)
        pdf.cell(95, 5, "KUPAC / CUSTOMER:", ln=True)
        
        pdf.set_font("helvetica", "", 9)
        # Supplier Details
        current_y = pdf.get_y()
        pdf.multi_cell(90, 4, f"{config.COMPANY_NAME}\n{config.COMPANY_ADDRESS}\nPIB: {config.COMPANY_PIB}\nZiro racun: {config.ZIRO_RACUN}")
        
        # Customer Details
        pdf.set_xy(105, current_y)
        is_company = bool(order_data.get('is_company'))
        buyer_name = order_data.get('company_name') or f"{order_data.get('first_name', '')} {order_data.get('last_name', '')}"
        buyer_address = order_data.get('company_address') or order_data.get('shipping_address', 'N/A')
        buyer_pib = order_data.get('company_pib') or ""
        # Note: Buyer's bank account isn't collected, so we leave it as N/A or empty
        pdf.multi_cell(90, 4, f"{buyer_name}\nAddress: {buyer_address}\nPIB/JMBG: {buyer_pib}\nZiro racun: N/A")
        
        pdf.ln(10)
        pdf.set_xy(10, pdf.get_y() + 5)

        # Items Table
        columns = [
            {'w': 10, 'label': '#', 'align': 'C'},
            {'w': 90, 'label': 'Opis / Description', 'align': 'L'},
            {'w': 20, 'label': 'Kol / Qty', 'align': 'C'},
            {'w': 35, 'label': 'Iznos / Total', 'align': 'R'},
        ]
        pdf.draw_table_header(columns)

        pdf.set_font("helvetica", "", 9)
        
        # Fetch actual fixed items from DB
        items = db.execute_query("SELECT * FROM order_items WHERE order_id = %s", (order_data['id'],))
        
        if not items:
            # Fallback to legacy single row if no items found (for old orders)
            total_amount = float(override_price if override_price is not None else (order_data.get('total_price') or 0))
            pdf.cell(10, 10, "1", border=1, align='C')
            pdf.cell(90, 10, f"Usluge 3D stampe (Order #{order_data['id']})", border=1)
            pdf.cell(20, 10, "1", border=1, align='C')
            pdf.cell(35, 10, pdf.format_money(total_amount), border=1, align='R', ln=True)
        else:
            total_amount = 0
            for idx, item in enumerate(items, 1):
                item_total = float(item['total_price'])
                total_amount += item_total
                pdf.cell(10, 8, str(idx), border=1, align='C')
                pdf.cell(90, 8, str(item['description']), border=1)
                pdf.cell(20, 8, str(item['quantity']), border=1, align='C')
                pdf.cell(35, 8, pdf.format_money(item_total), border=1, align='R', ln=True)

        # Summary
        pdv_rate = config.PDV_RATE
        pdf.ln(5)
        pdf.set_font("helvetica", "", 10)
        base_amount = total_amount / (1 + pdv_rate/100)
        pdv_amount = total_amount - base_amount

        pdf.cell(155, 6, "Osnovica / Base Amount (bez PDV):", align='R')
        pdf.cell(35, 6, pdf.format_money(base_amount), align='R', ln=True)
        pdf.cell(155, 6, f"PDV {pdv_rate}% / VAT Amount:", align='R')
        pdf.cell(35, 6, pdf.format_money(pdv_amount), align='R', ln=True)

        pdf.set_font("helvetica", "B", 12)
        pdf.cell(155, 12, "UKUPNO / TOTAL (EUR):", align='R')
        pdf.cell(35, 12, pdf.format_money(total_amount), align='R', ln=True)

        pdf.ln(20)
        
        # --- FISCALIZATION BLOCK ---
        print(f"DEBUG: Generating document type: {doc_type}")
        manual_qr = order_data.get('fiscal_qr_url')
        manual_ikof = order_data.get('ikof')
        manual_jikr = order_data.get('jikr')
        manual_ts = order_data.get('fiscalized_at')

        if doc_type == "faktura" or manual_qr:
            print("DEBUG: Entering Fiscalization Block")
            
            # Use manual data if available, otherwise generate mock/active
            ikof = manual_ikof or FiscalService.generate_ikof(order_data['id'], total_amount)[0]
            ts_obj = manual_ts or datetime.now()
            ts = ts_obj.strftime("%Y-%m-%dT%H:%M:%S+02:00") if hasattr(ts_obj, 'strftime') else str(ts_obj)
            jikr = manual_jikr or "MOCK-JIKR-EFI-STAGING-123"
            
            qr_url = manual_qr or FiscalService.generate_qr_url(jikr, ikof, ts, total_amount)
            print(f"DEBUG: QR URL: {qr_url}")
            
            # 4. Create QR Image
            qr = qrcode.QRCode(box_size=10, border=0)
            qr.add_data(qr_url)
            qr.make(fit=True)
            img_qr = qr.make_image(fill_color="black", back_color="white")
            
            # Convert to bytes for FPDF
            img_byte_arr = io.BytesIO()
            img_qr.save(img_byte_arr, format='PNG')
            img_byte_arr.seek(0)
            
            # 5. Place QR and Fiscal Info
            try:
                pdf.image(img_byte_arr, x=10, y=pdf.get_y(), w=30, h=30, type='PNG')
            except Exception as e:
                print(f"DEBUG: Failed to embed QR image: {e}")
            
            pdf.set_xy(45, pdf.get_y() + 5)
            pdf.set_font("helvetica", "B", 8)
            pdf.cell(0, 4, f"IKOF: {ikof}", ln=True)
            pdf.set_xy(45, pdf.get_y())
            pdf.cell(0, 4, f"JIKR: {jikr}", ln=True)
            pdf.set_xy(45, pdf.get_y())
            pdf.set_font("helvetica", "", 7)
            pdf.cell(0, 4, f"Fiskalizovano: {ts}", ln=True)
            
            pdf.set_y(pdf.get_y() + 15)
        # ---------------------------

        pdf.set_font("helvetica", "", 9)
        pdf.cell(95, 10, "Fakturisao (Izdavalac):", ln=False)
        pdf.cell(95, 10, "Primio (Kupac):", ln=True)
        pdf.ln(5)
        pdf.line(10, pdf.get_y(), 80, pdf.get_y())
        pdf.line(110, pdf.get_y(), 180, pdf.get_y())

        # Footer
        pdf.ln(15)
        pdf.set_font("helvetica", "I", 8)
        if doc_type == "predracun":
            msg = "Predracun je validan bez pecata i potpisa shodno clanu 31 Zakona o PDV. Placanje se vrsi u roku od 3 dana na navedeni ziro racun.\nThis is a proforma invoice and is valid without stamp and signature."
        else:
            msg = "Faktura je validna bez pecata i potpisa shodno clanu 31 Zakona o PDV. Roba/usluga je isporucena u skladu sa ugovorom.\nThis is a final invoice and is valid without stamp and signature."
        pdf.multi_cell(0, 5, msg)

        filename = f"{doc_type}_order_{order_data['id']}.pdf"
        filepath, web_path = InvoiceService._get_output_path(filename)
        print(f"DEBUG: Saving PDF to absolute path: {os.path.abspath(filepath)}")
        pdf.output(filepath)
        return web_path
