import os
from collections import defaultdict
from datetime import datetime
from flask import current_app, render_template
from fpdf import FPDF

# ── helpers ─────────────────────────────────────────────────────────────────

def _val(v):
    return None if v is None or v == 0 or v == '' else str(v)

def _fmt_date(d):
    if d is None:
        return None
    if isinstance(d, str):
        d = d[:10]
        for fmt in ('%Y-%m-%d', '%d.%m.%Y'):
            try:
                return datetime.strptime(d, fmt).strftime('%d.%m.%Y')
            except ValueError:
                continue
        return d
    return d.strftime('%d.%m.%Y')

def _ist_trenner(pos):
    return (not pos.pos_nr or pos.pos_nr == '') and (pos.faktor == 0 or pos.faktor is None) and (pos.laenge == 0 or pos.laenge is None) and (pos.breite == 0 or pos.breite is None) and (pos.tiefe == 0 or pos.tiefe is None) and (pos.menge == 0 or pos.menge is None) and (pos.einzelpreis == 0 or pos.einzelpreis is None) and (pos.gesamtpreis == 0 or pos.gesamtpreis is None)

# ── Farben ──────────────────────────────────────────────────────────────────

BLUE = (47, 84, 150)
LIGHT_GRAY = (0.93, 0.93, 0.93)
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)

# ── PDF-Klasse ──────────────────────────────────────────────────────────────

class AufmassPDF(FPDF):
    def footer(self):
        self.set_y(-8)
        self.set_font('DJ', 'I', 7)
        self.set_text_color(128, 128, 128)
        self.cell(0, 6, f'Seite {self.page_no()}/{{nb}}', align='C', new_x='LMARGIN', new_y='NEXT')

# ── Hauptfunktion ───────────────────────────────────────────────────────────

def _render_pdf_html(project, aufmass, positionen, company=None):
    ap_name = _name(project)
    groups, seen_pos = _build_summary(positionen)
    return render_template(
        'aufmass/export_pdf.html',
        project=project, aufmass=aufmass, positionen=positionen,
        company=company, ap_name=ap_name, groups=dict(groups),
        seen_pos=seen_pos, _val=_val, _fmt_date=_fmt_date,
        _ist_trenner=_ist_trenner,
    )

def _name(project):
    return f'{_val(project.ansprechpartner_vorname) or ""} {_val(project.ansprechpartner_nachname) or ""}'.strip()

def _build_summary(positionen):
    groups = defaultdict(lambda: {'kurztext': '', 'menge': 0.0, 'ep': 0.0, 'gp': 0.0})
    seen = []
    for p in positionen:
        if _ist_trenner(p) or not p.pos_nr:
            continue
        key = p.pos_nr
        if key not in groups:
            seen.append(key)
        groups[key]['kurztext'] = p.kurztext or ''
        groups[key]['menge'] += p.menge_hinten if p.menge_hinten else (p.menge or 0)
        groups[key]['ep'] = p.einzelpreis or 0
        groups[key]['gp'] += p.gesamtpreis or 0
    return groups, seen

def _val_or(v, default=''):
    return str(v) if v is not None and v != 0 and v != '' else default

def _fmt(v):
    return f'{v:.2f}'.replace('.',',') if v is not None else ''

# ── Spaltenbreiten (mm) – Verhältnis wie Excel max_widths ───────────────────
# A4 quer = 297mm, margin 5mm → 287mm verfügbar, aber wir nutzen 282mm für die Tabelle
W_POS = [20, 17, 12, 14, 14, 14, 16, 9, 63, 52, 16, 16, 19]  # sum = 282mm
# 20+17+12+14+14+14+16+9+63+52+16+16+19 = 282 ✓
W_SUM = [20, 172, 28, 28, 34]  # Zusammenfassung: PNr, Kurztext, Menge, EP, GP
# 20+172+28+28+34 = 282mm (gleiche Breite wie Positionstabelle)

def _font_path(name, fallback=None):
    win = f'C:/Windows/Fonts/{name}'
    lin = f'/usr/share/fonts/truetype/dejavu/{name}'
    if os.path.exists(win):
        return win
    if os.path.exists(lin):
        return lin
    return _font_path(fallback) if fallback else name

DJV = _font_path('DejaVuSans.ttf')
DJV_B = _font_path('DejaVuSans-Bold.ttf')
DJV_O = _font_path('DejaVuSans-Oblique.ttf', fallback='DejaVuSans.ttf')
DJV_BI = _font_path('DejaVuSans-BoldOblique.ttf', fallback='DejaVuSans-Bold.ttf')

def export_project_to_pdf(project, aufmass, positionen, output_path, company=None):
    pdf = AufmassPDF(orientation='L', format='A4')
    pdf.alias_nb_pages()
    pdf.set_auto_page_break(auto=True, margin=10)
    pdf.add_page()
    pdf.set_margins(7, 5, 7)  # 7mm links/rechts → 283mm verfügbar
    # Aber wir nutzen 282mm passend zu den Tabellen
    pdf.set_margins(7.5, 5, 7.5)  # 7.5mm links/rechts → 282mm verfügbar
    pdf.add_font('DJ', '', DJV, uni=True)
    pdf.add_font('DJ', 'B', DJV_B, uni=True)
    pdf.add_font('DJ', 'I', DJV_O, uni=True)
    pdf.add_font('DJ', 'BI', DJV_BI, uni=True)

    ap_name = _name(project)
    groups, seen_pos = _build_summary(positionen)
    total_gp = sum(g['gp'] for g in groups.values())

    # ── Logo / Titel ─────────────────────────────────────────────────────────
    logo_shown = False
    if company and company.logo:
        lp = company.logo
        if not os.path.isabs(lp):
            lp = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), lp)
        if os.path.exists(lp):
            try:
                pdf.image(lp, x=5, y=5, w=30)
                logo_shown = True
            except Exception:
                pass
    if not logo_shown:
        if company and company.name:
            pdf.set_font('DJ', 'B', 12)
            pdf.set_text_color(*BLUE)
            pdf.cell(0, 8, company.name, align='L', new_x='LMARGIN', new_y='NEXT')
        pdf.set_font('DJ', 'B', 16)
        pdf.set_text_color(*BLUE)
        pdf.cell(0, 8, 'Aufmaß', align='C', new_x='LMARGIN', new_y='NEXT')
    else:
        pdf.set_font('DJ', 'B', 16)
        pdf.set_text_color(*BLUE)
        pdf.cell(0, 8, 'Aufmaß', align='C', new_x='LMARGIN', new_y='NEXT')
    pdf.set_text_color(*BLACK)
    pdf.ln(3)

    # ── Kopfzeilen (8 Spalten zu je 35.25mm = 282mm) ───────────────────────────
    CW = 35.25  # jede Spalte gleich breit
    LH = 5.5
    pdf.set_font('DJ', '', 7.5)

    def cell_lbl(txt, w=CW):
        pdf.set_fill_color(242, 242, 242)
        pdf.set_font('DJ', 'B', 7.5)
        pdf.cell(w, LH, txt, border=1, fill=True, align='L')

    def cell_val(txt, w=CW):
        pdf.set_font('DJ', '', 7.5)
        pdf.cell(w, LH, txt, border=1, align='L')

    def nl():
        pdf.set_x(7.5)

    # Row 1: Vertrag(2) / LV-Name(4) / Aufmaß-Datum(2)
    cell_lbl('Vertrag:'); cell_val(_val_or(project.vertrag), CW)
    cell_lbl('LV-Name:'); cell_val(_val_or(project.lv_name), CW*3)
    cell_lbl('Aufmaß-Datum:'); cell_val(_fmt_date(project.datum) or '', CW*2)
    nl(); pdf.ln(LH)

    # Row 2: Projekt(2) / Baustelle(6)
    cell_lbl('Projekt:'); cell_val(_val_or(project.bezeichnung), CW)
    cell_lbl('Baustelle:'); cell_val(_val_or(project.baustelle), CW*5)
    nl(); pdf.ln(LH)

    # Row 3: Typ(2) / Bauabschnitt(6)
    cell_lbl('Typ:'); cell_val(_val_or(aufmass.typ if aufmass else None), CW)
    cell_lbl('Bauabschnitt:'); cell_val(_val_or(project.bauabschnitt), CW*5)
    nl(); pdf.ln(LH)

    # Row 4: SM-Nr(2) / Startdatum(2) / Name(1) / Wert(1) / Tel(2)
    cell_lbl('SM-Nr.:'); cell_val(_val_or(project.sm_nr), CW)
    cell_lbl('Startdatum:'); cell_val(_fmt_date(project.datum_start) or '', CW)
    cell_lbl('Name:'); cell_val(_val_or(ap_name))
    cell_lbl('Tel:'); cell_val(_val_or(project.ansprechpartner_tel), CW)
    nl(); pdf.ln(LH)

    # Row 5: Abruf-Nr(2) / Enddatum(2) / Email(4)
    cell_lbl('Abruf-Nr.:'); cell_val(_val_or(project.abruf_nr), CW)
    cell_lbl('Enddatum:'); cell_val(_fmt_date(project.datum_ende) or '', CW)
    cell_lbl('Email:'); cell_val(_val_or(project.ansprechpartner_email), CW*4)
    nl(); pdf.ln(LH + 2)

    # ── Positionstabelle ─────────────────────────────────────────────────────
    headers = ['Abschn.', 'Pos-Nr', 'Fakt.', 'Länge', 'Breite', 'Tiefe',
               'Menge', 'EH', 'Kurztext', 'Bemerkung', 'Menge', 'EP (€)', 'GP (€)']

    # Tabellenkopf
    pdf.set_fill_color(*BLUE)
    pdf.set_text_color(*WHITE)
    pdf.set_font('DJ', 'B', 6)
    x0 = pdf.get_x()
    y0 = pdf.get_y()
    for i, h in enumerate(headers):
        pdf.cell(W_POS[i], 5, h, border=1, fill=True, align='C')
    pdf.ln()
    pdf.set_text_color(*BLACK)

    # Datenzeilen
    pdf.set_font('DJ', '', 6)
    row_h = 4.5
    gesamt = 0.0
    pos_counter = 0
    for pos in positionen:
        if _ist_trenner(pos):
            pdf.set_fill_color(245, 245, 245)
            pdf.cell(sum(W_POS), 3, '', border=1, fill=True)
            pdf.ln()
            continue
        pos_counter += 1
        menge = pos.menge if pos.menge else None
        menge_h = pos.menge_hinten if pos.menge_hinten else None
        if pos.einheit in ('ST', 'LE', 'STD', 'h', 'Psch'):
            menge = pos.faktor * 1 if pos.faktor else None
        gp = pos.gesamtpreis or 0
        gesamt += gp

        y0 = pdf.get_y()
        x0 = pdf.get_x()

        # Kurztext & Bemerkung: MultiCell für Wrap, dann Höhe bestimmen
        kurz = _val_or(pos.kurztext)
        bemerk = _val_or(pos.bemerkung)
        # Einfache Zeilenhöhe (kein MultiCell – zu komplex)
        # Stattdessen: Text auf eine Zeile beschränken (abschneiden bei Überlauf)
        MAX_KURZTEXT = 95
        MAX_BEMERK = 28
        if len(kurz) > MAX_KURZTEXT:
            kurz = kurz[:MAX_KURZTEXT-3] + '...'
        if len(bemerk) > MAX_BEMERK:
            bemerk = bemerk[:MAX_BEMERK-3] + '...'

        vals = [
            pos.abschnitt or '', pos.pos_nr or '',
            _fmt(pos.faktor), _fmt(pos.laenge), _fmt(pos.breite), _fmt(pos.tiefe),
            _fmt(menge), pos.einheit or '', kurz, bemerk,
            _fmt(menge_h), _fmt(pos.einzelpreis), _fmt(gp)
        ]

        for i, v in enumerate(vals):
            a = 'L' if i in (8, 9) else ('C' if i in (0, 7) else 'R')
            pdf.cell(W_POS[i], row_h, v, border=1, align=a)
        pdf.ln()

    # Summenzeile
    pdf.set_font('DJ', 'B', 6)
    pdf.cell(sum(W_POS[:11]), row_h, '', border=1, align='R')
    pdf.cell(W_POS[11], row_h, 'Summe:', border=1, align='R')
    pdf.cell(W_POS[12], row_h, f'{gesamt:.2f}', border=1, align='R')
    pdf.ln()

    # ── Mengen-Zusammenfassung ─────────────────────────────────────────────
    if seen_pos:
        pdf.ln(4)
        pdf.set_fill_color(214, 228, 240)
        pdf.set_text_color(*BLUE)
        pdf.set_font('DJ', 'B', 9)
        pdf.cell(sum(W_SUM), 6, 'Mengen- und Positions-Zusammenfassung', border=1, fill=True, align='C')
        pdf.ln()

        pdf.set_text_color(*WHITE)
        pdf.set_fill_color(*BLUE)
        pdf.set_font('DJ', 'B', 6)
        for i, h in enumerate(['Pos-Nr', 'Kurztext', 'Menge', 'EP (€)', 'GP (€)']):
            pdf.cell(W_SUM[i], 5, h, border=1, fill=True, align='C')
        pdf.ln()
        pdf.set_text_color(*BLACK)

        total = 0.0
        pdf.set_font('DJ', '', 7)
        MAX_KURZTEXT_SUM = 120
        for key in seen_pos:
            g = groups[key]
            total += g['gp']
            kurz_sum = g['kurztext']
            if len(kurz_sum) > MAX_KURZTEXT_SUM:
                kurz_sum = kurz_sum[:MAX_KURZTEXT_SUM-3] + '...'
            vals = [key, kurz_sum, _fmt(g['menge']), _fmt(g['ep']), _fmt(g['gp'])]
            for i, v in enumerate(vals):
                a = 'L' if i == 1 else 'C' if i == 0 else 'R'
                pdf.cell(W_SUM[i], 5, v, border=1, align=a)
            pdf.ln()

        pdf.set_font('DJ', 'B', 7)
        pdf.cell(W_SUM[0] + W_SUM[1], 5, '', border=1)
        pdf.cell(W_SUM[2], 5, 'Summe:', border=1, align='R')
        pdf.cell(W_SUM[3], 5, '', border=1)
        pdf.cell(W_SUM[4], 5, f'{total:.2f}', border=1, align='R')
        pdf.ln()

    pdf.output(output_path)
    return output_path
