import io
from pathlib import Path

from fpdf import FPDF
from fpdf.enums import XPos, YPos, MethodReturnValue

from msz_constants import MSZ_MATRIX, hu_datum

STATIC_DIR = Path(__file__).resolve().parent / "static"
# A projekt gyökere - ide horgonyozzuk az arculati logó (és minden más, DB-ben tárolt, "/uploads/…"
# kezdetű relatív útvonalú) fájl elérési útját, NE a process aktuális munkakönyvtárához (cwd)
# képest. Élesben a gunicorn WorkingDirectory-ja eltérhet a helyi dev (uvicorn a projekt
# gyökeréből induló) szokásától - egy relatív Path(...).exists() ilyenkor csendben Hamis-t adna,
# és a logó minden észrevehető hiba nélkül egyszerűen sosem jelenne meg a jegyzőkönyvön.
PROJEKT_GYOKER = Path(__file__).resolve().parent


def logo_beillesztese(pdf: FPDF, arculat: dict, x: float = 170, y: float = 8, w: float = 30):
    """Az arculatban beállított cég-logó beillesztése a PDF fejlécébe - 2026-09-30-i user-jelzés
    (feltöltött JPG nem jelent meg a jegyzőkönyvön) nyomán szándékosan NEM némán nyeli el a
    hibát: ha a fájl hiányzik vagy az fpdf2 nem tudja beágyazni, a szerver logjába kerül a pontos
    ok. Emellett, ha a közvetlen beágyazás sikertelen (pl. szokatlan JPEG-kódolás/ICC-profil egy
    export-szoftverből, amit az fpdf2/Pillow adott verziója nem kezel), egy Pillow-alapú
    újrakódolással (tiszta RGB, ICC-profil nélküli JPEG) még egyszer megpróbálja - ez a legtöbb
    "egzotikus" export-hibát lefedi anélkül, hogy tudnunk kellene előre a pontos okát."""
    logo_utvonal = arculat.get("logo_utvonal")
    if not logo_utvonal:
        return

    logo_fizikai_ut = PROJEKT_GYOKER / logo_utvonal.lstrip("/")
    if not logo_fizikai_ut.exists():
        print(f"❌ Arculati logó nem található a várt útvonalon: {logo_fizikai_ut}")
        return

    try:
        pdf.image(str(logo_fizikai_ut), x=x, y=y, w=w)
        return
    except Exception as e:
        print(f"❌ Arculati logó beillesztése sikertelen ({logo_fizikai_ut}): {type(e).__name__}: {e} - újrakódolással próbálkozom.")

    try:
        from PIL import Image
        with Image.open(logo_fizikai_ut) as kep:
            if kep.mode != "RGB":
                kep = kep.convert("RGB")
            buffer = io.BytesIO()
            kep.save(buffer, format="JPEG", quality=90)
            buffer.seek(0)
            pdf.image(buffer, x=x, y=y, w=w)
    except Exception as e:
        print(f"❌ Arculati logó újrakódolt beillesztése is sikertelen ({logo_fizikai_ut}): {type(e).__name__}: {e} - a jegyzőkönyv logó nélkül készül.")


def rajzol_tablazat(pdf, oszlop_szelessegek, fejlecek, sorok, sor_magassag=6, align_lista=None):
    """Általános, oldaltörés-biztos táblázatrajzoló segédfüggvény fpdf2-höz - a
    routers/inspections.py-ban (general_jegyzokonyv) már bevált két-lépéses mintát
    (dry_run-os magasság-előmérés -> üres keret -> keret nélküli szöveg-overlay)
    alkalmazza generikusan, tetszőleges oszlopszámra/szélességre.

    KRITIKUS: enélkül a minta nélkül a multi_cell() menet közbeni automatikus
    oldaltörése szétcsúszott kereteket vagy "Not enough horizontal space" hibát
    okoz - ez a hibaosztály eddig HÁROMSZOR fordult elő ebben a projektben.
    """
    if not sorok:
        return
    if align_lista is None:
        align_lista = ["L"] * len(oszlop_szelessegek)

    def fejlec_rajzolasa():
        # A fejléc-címkék is tördelhetnek (pl. "Elérhetősége (e-mail, telefon vagy fax)"
        # nem fér ki egy keskeny oszlopba egyetlen sorban) - ugyanaz a dry_run-os
        # magasság-előmérés + keret + overlay minta kell ide is, különben a hosszabb
        # fejléc-szöveg egyszerűen túllóg/átfedésbe kerül a szomszédos oszloppal.
        pdf.set_font("DejaVu", "B", 8)
        pdf.set_fill_color(220, 220, 220)
        fejlec_magassag = max(
            [7] + [
                pdf.multi_cell(szel, 4, cim, dry_run=True, output=MethodReturnValue.HEIGHT)
                for szel, cim in zip(oszlop_szelessegek, fejlecek)
            ]
        )
        x_start = pdf.get_x()
        y_start = pdf.get_y()
        for szel in oszlop_szelessegek:
            pdf.cell(szel, fejlec_magassag, "", border=1, fill=True)
        x = x_start
        for szel, cim in zip(oszlop_szelessegek, fejlecek):
            pdf.set_xy(x, y_start)
            pdf.multi_cell(szel, 4, cim, align="C")
            x += szel
        pdf.set_xy(x_start, y_start + fejlec_magassag)
        pdf.set_font("DejaVu", "", 8)

    fejlec_rajzolasa()

    for sor in sorok:
        szovegek = [str(cella) if cella not in (None, "") else "-" for cella in sor]

        tervezett_magassag = max(
            [sor_magassag] + [
                pdf.multi_cell(szel, sor_magassag, szoveg, dry_run=True, output=MethodReturnValue.HEIGHT)
                for szel, szoveg in zip(oszlop_szelessegek, szovegek)
            ]
        )

        if pdf.get_y() + tervezett_magassag > pdf.page_break_trigger:
            pdf.add_page()
            fejlec_rajzolasa()

        x_start = pdf.get_x()
        y_start = pdf.get_y()

        pdf.set_xy(x_start, y_start)
        for szel in oszlop_szelessegek:
            pdf.cell(szel, tervezett_magassag, "", border=1)

        x = x_start
        for szel, szoveg, align in zip(oszlop_szelessegek, szovegek, align_lista):
            pdf.set_xy(x, y_start)
            pdf.multi_cell(szel, sor_magassag, szoveg, align=align)
            x += szel

        pdf.set_y(y_start + tervezett_magassag)


class JegyzokonyvPDF(FPDF):
    def __init__(self, gep_adatok, ceg_adatok, vizsgalat_tipus, vizsgalo_adatok, arculat=None,
                 rendkivuli=False, rendkivuli_indoklas=None, szabvanyok=None):
        super().__init__()
        # A vizsgálat során alkalmazott előírások és szabványok felsorolása - csak az 1. oldal
        # tetején jelenik meg (lásd header()).
        self.szabvanyok = (szabvanyok or "").strip()
        # A kérdés-táblázat fejléce (jelmagyarázat + oszlopcímek) minden oldalon megjelenik, amíg a
        # táblázat tart - az összefoglaló/záró blokkoknál a hívó kikapcsolja, hogy egy csak az
        # aláírást tartalmazó oldalra ne kerüljön üres táblázatfejléc.
        self.tablazat_fejlec = True
        self.gep = gep_adatok
        self.ceg = ceg_adatok
        self.vizsg_tipus = vizsgalat_tipus
        self.vizsgalo = vizsgalo_adatok
        # Céges arculat (logó, egyedi fejléc-szöveg, lábjegyzet márka) - opcionális, Beállításokban testreszabható.
        self.arculat = arculat or {}
        # Az IBF egy alesete - a korábbi önálló "Rendkívüli vizsgálat" típus megszűnt,
        # ezt mostantól egy jelölő + indoklás jelzi az IBF-en belül (lásd EBSZ 7.2).
        self.rendkivuli = rendkivuli
        self.rendkivuli_indoklas = rendkivuli_indoklas

        self.add_font("DejaVu", "", str(STATIC_DIR / "DejaVuSans.ttf"))
        self.add_font("DejaVu", "B", str(STATIC_DIR / "DejaVuSans-Bold.ttf"))

    def header(self):
        logo_beillesztese(self, self.arculat)

        cim_toldalek = " (Rendkívüli)" if self.rendkivuli else ""
        self.set_font("DejaVu", "B", 14)
        self.cell(0, 10, f"{self.vizsg_tipus}{cim_toldalek} jegyzőkönyv", ln=True, align="C")

        fejlec_szoveg = self.arculat.get("fejlec_szoveg")
        if fejlec_szoveg:
            self.set_font("DejaVu", "", 9)
            self.cell(0, 5, fejlec_szoveg, ln=True, align="C")

        if self.rendkivuli and self.rendkivuli_indoklas:
            self.set_font("DejaVu", "B", 9)
            self.cell(0, 5, f"Rendkívüli vizsgálat indoklása: {self.rendkivuli_indoklas}", ln=True, align="C")

        self.set_font("DejaVu", "", 10)
        # KRITIKUS: ezek a fejléc-sorok korábban sima cell()-lel íródtak - hosszú
        # gépnév/géptípus/típus (vagy vizsgálónév) esetén a szöveg egyszerűen lelógott a
        # lap jobb szélén, mert a cell() nem tördel. multi_cell()-re cserélve, MINDEGYIK
        # explicit new_x=XPos.LMARGIN, new_y=YPos.NEXT-et kap - lásd a jelmagyarázat-soroknál
        # lent (és [[project_ebk_pdf_multicell_bug]]) a több egymás utáni multi_cell()
        # cursor-drift hibaosztályát, aminek itt is neki lehetne futni explicit pozicionálás nélkül.
        self.multi_cell(0, 6, f"Üzemeltető / Tulajdonos: {self.ceg.nev} (Adószám: {self.ceg.adoszam or '-'})", new_x=XPos.LMARGIN, new_y=YPos.NEXT, align="L")
        self.multi_cell(0, 6, f"Gép megnevezése: {self.gep.megnevezes} | Géptípus: {self.gep.geptipus or '-'} | Típus: {self.gep.tipus}", new_x=XPos.LMARGIN, new_y=YPos.NEXT, align="L")

        csoportszam_str = self.gep.calculated_csoportszam
        if not csoportszam_str:
            csoportszam_str = "-"

        self.multi_cell(0, 6, f"Gyártó: {self.gep.gyarto} | Gyári szám: {self.gep.gyari_szam} | Csoportszám: {csoportszam_str}", new_x=XPos.LMARGIN, new_y=YPos.NEXT, align="L")
        self.multi_cell(0, 6, f"Teherbírás: {self.gep.teherbiras} kg | Üzemóra állása: {self.gep.uzemora} h", new_x=XPos.LMARGIN, new_y=YPos.NEXT, align="L")

        biz_szam = getattr(self.vizsgalo, 'bizonyitvany_szam', "-")
        if not biz_szam:
            biz_szam = "-"

        kam_szam = getattr(self.vizsgalo, 'kamarai_azonosito', "-")
        if not kam_szam:
            kam_szam = "-"

        eng_szam = getattr(self.vizsgalo, 'engedely_szam', "-")
        if not eng_szam:
            eng_szam = "-"

        self.multi_cell(0, 6, f"Vizsgáló szakember: {self.vizsgalo.username} | Biz.szám: {biz_szam} | Kamarai az.: {kam_szam} | Eng.szám: {eng_szam}", new_x=XPos.LMARGIN, new_y=YPos.NEXT, align="L")
        self.ln(2)

        if self.szabvanyok and self.page_no() == 1:
            self.set_font("DejaVu", "B", 9)
            self.multi_cell(0, 5, "Vizsgálat során alkalmazott előírások és szabványok:", new_x=XPos.LMARGIN, new_y=YPos.NEXT, align="L")
            self.set_font("DejaVu", "", 9)
            self.multi_cell(0, 5, self.szabvanyok, new_x=XPos.LMARGIN, new_y=YPos.NEXT, align="L")
            self.ln(2)

        if not self.tablazat_fejlec:
            return

        # Jelmagyarázat a "Módja" oszlop MSZ 9721 szerinti rövidítéseihez.
        self.set_font("DejaVu", "", 6.5)
        # KRITIKUS: a multi_cell() alapértelmezett new_x=XPos.RIGHT miatt egy második,
        # közvetlenül utána hívott multi_cell a jobb margóhoz közeli x-pozícióból indulna,
        # ahol a "fennmaradó szélesség" (w=0) már nem elég egyetlen karakter töréséhez sem
        # ("Not enough horizontal space" hiba) - ezért mindkét sor után explicit a bal
        # margóra és a következő sorra kell állítani a kurzort.
        self.multi_cell(
            0, 3.2,
            "Jelmagyarázat: SZV = Szemrevételezéses vizsgálat | T = Tapintásos vizsgálat | "
            "ME = Mérőeszközös vizsgálat | MM = Mérőműszeres vizsgálat | "
            "ÜJ = Üresjárati (működési) vizsgálat | ÜT = Üzemi terheléses vizsgálat | "
            "TT = Túlterhelés elleni védelem vizsgálata",
            new_x=XPos.LMARGIN, new_y=YPos.NEXT
        )
        self.multi_cell(
            0, 3.2,
            "Értékelés: M = Megfelelt | NM = Nem megfelelt | NA = Nem releváns",
            new_x=XPos.LMARGIN, new_y=YPos.NEXT
        )
        self.ln(2)

        self.set_font("DejaVu", "B", 8)
        self.set_fill_color(220, 220, 220)
        self.cell(15, 8, "Szabv.", border=1, fill=True, align="C")
        self.cell(90, 8, "A vizsgálat tárgya az MSZ 9721 szerint", border=1, fill=True, align="C")
        self.cell(15, 8, "Módja", border=1, fill=True, align="C")
        self.cell(50, 8, "Mért érték, megállapítás", border=1, fill=True, align="C")
        self.cell(20, 8, "Értékelés", border=1, fill=True, align="C")
        self.ln()

    def minositesi_megallapitas(self, vegso_ertekeles, hatarido=None):
        """A minősítés alatti, ahhoz igazodó záró megállapítás (3 lehetséges szöveg). A
        `hatarido` a "Soron kívül javítani, pótolni kell" tételhez megadott határidő (date)."""
        if "Nem alkalmas" in vegso_ertekeles:
            szoveg = (
                "A vizsgálat során feltárt hiányosság miatt a berendezés nem üzemeltethető/használható "
                "a javítást követő ismételt vizsgálatig."
            )
        elif "Korlátozással" in vegso_ertekeles:
            hatarido_szoveg = hu_datum(hatarido) if hatarido else "..............."
            szoveg = (
                "A hivatkozott előírásokon alapuló fent elvégzett ellenőrzéseket tartalmazó vizsgálat alapján "
                f"a vizsgált berendezés a hiba elhárításáig, legkésőbb {hatarido_szoveg} határidőig üzemeltethető."
            )
        else:
            szoveg = (
                "A hivatkozott előírásokon alapuló fent elvégzett ellenőrzéseket tartalmazó vizsgálat alapján "
                "a vizsgált berendezésen fellelt hiba nincs, biztonságosan üzemeltethető."
            )

        self.ln(2)
        self.set_font("DejaVu", "", 9)
        if self.will_page_break(20):
            self.add_page()
        self.multi_cell(0, 5.5, szoveg, border=1, new_x=XPos.LMARGIN, new_y=YPos.NEXT, align="L")

    def kovetkezo_vizsgalat_blokk(self, adatok):
        """A soron következő vizsgálatok blokkja (csak "Megfelelt" minősítésnél hívjuk): az
        MSZ 9750 időköz-táblázat a gép csoportszámának sorát kiemelve, alatta a kiszámolt
        következő időpontokkal. `adatok`: msz_constants.kovetkezo_vizsgalatok() eredménye."""
        if not adatok:
            return

        tablas = not adatok["teherfelvevo"]
        becsult_magassag = 10 + (46 if tablas else 0) + 7 * len(adatok["sorok"])
        self.ln(3)
        if self.will_page_break(becsult_magassag):
            self.add_page()

        self.set_font("DejaVu", "B", 10)
        self.cell(0, 7, "Soron következő vizsgálatok", new_x=XPos.LMARGIN, new_y=YPos.NEXT)

        if tablas:
            csoportszam = adatok["csoportszam"]
            self.set_font("DejaVu", "B", 8)
            self.set_fill_color(220, 220, 220)
            self.cell(30, 6, "Csoportszám", border=1, fill=True, align="C")
            self.cell(80, 6, "Szerkezeti vizsgálat időköze", border=1, fill=True, align="C")
            self.cell(80, 6, "Fővizsgálat időköze", border=1, fill=True, align="C", new_x=XPos.LMARGIN, new_y=YPos.NEXT)
            for cs, szabaly in MSZ_MATRIX.items():
                sajat = (cs == csoportszam)
                self.set_font("DejaVu", "B" if sajat else "", 8)
                self.set_fill_color(198, 239, 206)
                self.cell(30, 5.5, f"{cs}. csoport", border=1, fill=sajat, align="C")
                self.cell(80, 5.5, f"{szabaly['szerk_ho']} hónap / {szabaly['szerk_ora']} üzemóra", border=1, fill=sajat, align="C")
                self.cell(80, 5.5, f"{szabaly['fo_ho']} hónap / {szabaly['fo_ora']} üzemóra", border=1, fill=sajat, align="C", new_x=XPos.LMARGIN, new_y=YPos.NEXT)
            self.set_font("DejaVu", "", 7)
            self.multi_cell(
                0, 3.5,
                "MSZ 9750 - az időszakos vizsgálatok időközei: a két érték közül az a mérvadó, amelyet az "
                "emelőgép az üzemeltetése során előbb elér.",
                new_x=XPos.LMARGIN, new_y=YPos.NEXT
            )
            self.ln(1)

            self.set_font("DejaVu", "B", 9)
            self.cell(0, 6, f"Üzemi csoportszám az MSZ 9750 alapján: {csoportszam}-es", new_x=XPos.LMARGIN, new_y=YPos.NEXT)

        for sor in adatok["sorok"]:
            self.set_font("DejaVu", "B", 9)
            if sor["datum"]:
                ertek = f"legkésőbb {hu_datum(sor['datum'])} ({sor['honap']} hónap)"
            else:
                ertek = f"- ({sor.get('megjegyzes') or 'nem határozható meg'})"
            self.multi_cell(0, 6, f"{sor['cimke']}: {ertek}", new_x=XPos.LMARGIN, new_y=YPos.NEXT, align="L")

    def footer(self):
        self.set_y(-15)
        self.set_font("DejaVu", "", 8)
        lablec_szoveg = "EmeLOG Nyilvántartó rendszerrel készült - www.emelog.hu"
        self.cell(0, 10, lablec_szoveg, align="L")
        self.set_x(10)
        self.cell(0, 10, f"Oldal {self.page_no()}/{{nb}}", align="R")


class TuzvedelmiNaploPDF(FPDF):
    """A tűzvédelmi üzemeltetési napló (tűzoltó készülék) nyomtatható, éves állapotot mutató
    riportja - a hatósági mintanyomtatvány (TvMI 4.5.5) elrendezését követi."""

    OSZLOP_SZELESSEG = [38, 22, 26, 20, 22, 16, 16, 16, 32, 11, 11, 11, 11, 24, 24]

    def __init__(self, site_adatok, ceg_adatok, ev, legutobbi_esemeny=None):
        super().__init__(orientation="L", format="A4")
        self.site = site_adatok
        self.ceg = ceg_adatok
        self.ev = ev
        self.legutobbi = legutobbi_esemeny or {}
        self.add_font("DejaVu", "", str(STATIC_DIR / "DejaVuSans.ttf"))
        self.add_font("DejaVu", "B", str(STATIC_DIR / "DejaVuSans-Bold.ttf"))

    def header(self):
        self.set_font("DejaVu", "B", 14)
        self.cell(0, 8, "TŰZVÉDELMI ÜZEMELTETÉSI NAPLÓ", ln=True, align="C")
        self.set_font("DejaVu", "B", 10)
        self.cell(0, 6, f"TŰZOLTÓ KÉSZÜLÉK - {self.ev}. év", ln=True, align="C")
        self.ln(2)

        self.set_font("DejaVu", "", 9)
        self.cell(0, 5, f"Létesítmény neve, címe: {self.site.nev} - {self.site.cim or '-'}", ln=True)
        self.cell(0, 5, f"Üzemeltető neve, elérhetősége: {self.ceg.nev} - {self.ceg.elerhetoseg or '-'}", ln=True)
        self.cell(0, 5, f"Az elvégzett karbantartás típusa: {self.legutobbi.get('tipus', '-')} | dátuma: {self.legutobbi.get('datum', '-')}", ln=True)
        self.cell(0, 5, f"Karbantartást végző szervezet neve, székhelye: {self.legutobbi.get('ceg_nev', '-')} / {self.legutobbi.get('ceg_szekhely', '-')}", ln=True)
        self.cell(0, 5, f"Karbantartást végző neve: {self.legutobbi.get('vegzo_neve', '-')} | Szakvizsga szám/érvényesség: {self.legutobbi.get('szakvizsga_szam', '-')} / {self.legutobbi.get('szakvizsga_ervenyesseg', '-')}", ln=True)
        self.ln(2)

        self.set_font("DejaVu", "B", 6.5)
        self.set_fill_color(220, 220, 220)
        fejlecek = [
            "Készenléti hely", "Típus", "Gyártási szám", "Gyártás ideje", "Oltásteljesítmény",
            "Alap", "Közép", "Teljes körű", "Megjegyzés", "I.n.év", "II.n.év", "III.n.év", "IV.n.év",
            "Hiányosság", "Intézkedés",
        ]
        for szel, cim in zip(self.OSZLOP_SZELESSEG, fejlecek):
            self.cell(szel, 12, cim, border=1, fill=True, align="C")
        self.ln()

    def footer(self):
        self.set_y(-12)
        self.set_font("DejaVu", "", 7)
        self.cell(0, 8, "EmeLOG Nyilvántartó rendszerrel készült", align="L")
        self.set_x(-30)
        self.cell(20, 8, f"Oldal {self.page_no()}/{{nb}}", align="R")

    def sor_hozzaadasa(self, adatok: list):
        self.set_font("DejaVu", "", 7)
        for szel, ertek in zip(self.OSZLOP_SZELESSEG, adatok):
            self.cell(szel, 8, str(ertek) if ertek is not None else "-", border=1, align="C")
        self.ln()


class Msz16226DokumentumPDF(FPDF):
    """MSZ 16226 (Gépi hajtású targonca üzemviteli dokumentuma) - a szabvány TARTALMát
    fedi le, de a SAJÁT elrendezésünkben (nem a hivatalos 3.1/3.2/... számozásban), ahogy
    a userrel megbeszéltük. Csak a header()/footer() (márkajelzés) él ebben az
    osztályban - a teljes tartalom a routers/msz16226.py PDF-generáló route-jában épül
    fel, ugyanúgy, ahogy a JegyzokonyvPDF/general_jegyzokonyv() párosnál is."""

    def __init__(self, gep_adatok, ceg_adatok, arculat=None):
        super().__init__()
        self.gep = gep_adatok
        self.ceg = ceg_adatok
        self.arculat = arculat or {}

        self.add_font("DejaVu", "", str(STATIC_DIR / "DejaVuSans.ttf"))
        self.add_font("DejaVu", "B", str(STATIC_DIR / "DejaVuSans-Bold.ttf"))

    def header(self):
        logo_beillesztese(self, self.arculat)

        self.set_font("DejaVu", "B", 14)
        self.cell(0, 10, "Üzemviteli Dokumentum", ln=True, align="C")

        fejlec_szoveg = self.arculat.get("fejlec_szoveg")
        if fejlec_szoveg:
            self.set_font("DejaVu", "", 9)
            self.cell(0, 5, fejlec_szoveg, ln=True, align="C")

        self.set_font("DejaVu", "", 10)
        self.multi_cell(0, 6, f"Üzemeltető / Tulajdonos: {self.ceg.nev} (Adószám: {self.ceg.adoszam or '-'})", new_x=XPos.LMARGIN, new_y=YPos.NEXT, align="L")
        self.multi_cell(0, 6, f"Gép megnevezése: {self.gep.megnevezes} | Géptípus: {self.gep.geptipus or '-'} | Gyári szám: {self.gep.gyari_szam or '-'}", new_x=XPos.LMARGIN, new_y=YPos.NEXT, align="L")
        self.ln(3)

    def footer(self):
        self.set_y(-15)
        self.set_font("DejaVu", "", 8)
        self.cell(0, 10, "EmeLOG Nyilvántartó rendszerrel készült - www.emelog.hu", align="L")
        self.set_x(10)
        self.cell(0, 10, f"Oldal {self.page_no()}/{{nb}}", align="R")
