import io
from pathlib import Path

from fpdf import FPDF
from fpdf.enums import XPos, YPos
from PIL import Image, ImageDraw, ImageFont

STATIC_DIR = Path(__file__).resolve().parent / "static"

SULYOSSAG_SZIN = {"ENYHE": (13, 202, 240), "KOZEPES": (255, 193, 7), "SULYOS": (220, 53, 69)}
SULYOSSAG_CIMKE = {"ENYHE": "Enyhe", "KOZEPES": "Közepes", "SULYOS": "Súlyos"}


def _betutipus(meret: int, felkover: bool = False):
    try:
        fajl = "DejaVuSans-Bold.ttf" if felkover else "DejaVuSans.ttf"
        return ImageFont.truetype(str(STATIC_DIR / fajl), meret)
    except Exception:
        return ImageFont.load_default()


def oszlopdiagram_kep(cim: str, adatok: list, szin=(220, 53, 69), szelesseg: int = 380, magassag: int = 220) -> bytes:
    """Egyszerű, PIL-lel rajzolt vízszintes oszlopdiagram PNG-ként - a fpdf2 nem tud
    natívan diagramot rajzolni, a projekt pedig szándékosan nem használ matplotlib-et."""
    img = Image.new("RGB", (szelesseg, magassag), "white")
    draw = ImageDraw.Draw(img)
    font_cim = _betutipus(15, felkover=True)
    font = _betutipus(12)

    draw.text((6, 6), cim, fill="black", font=font_cim)
    draw.rectangle([0, 0, szelesseg - 1, magassag - 1], outline=(200, 200, 200))

    if not adatok:
        draw.text((10, 45), "Nincs adat erre a napra", fill=(120, 120, 120), font=font)
        return _png_bytes(img)

    label_szelesseg = 150
    jobb_margo = 45
    grafikon_szelesseg = szelesseg - label_szelesseg - jobb_margo
    max_ertek = max(ertek for _, ertek in adatok) or 1
    sor_magassag = max(18, min(30, (magassag - 40) // len(adatok)))
    y = 36

    for label, ertek in adatok:
        cimke = (label[:20] + "…") if len(label) > 21 else label
        draw.text((6, y + (sor_magassag - 14) // 2), cimke, fill="black", font=font)
        bar_hossz = int((ertek / max_ertek) * grafikon_szelesseg) if max_ertek else 0
        bar_hossz = max(bar_hossz, 2) if ertek > 0 else 0
        draw.rectangle(
            [label_szelesseg, y + 3, label_szelesseg + bar_hossz, y + sor_magassag - 5],
            fill=szin,
        )
        draw.text((label_szelesseg + bar_hossz + 6, y + (sor_magassag - 14) // 2), str(ertek), fill="black", font=font)
        y += sor_magassag
        if y > magassag - 10:
            break

    return _png_bytes(img)


def _png_bytes(img: Image.Image) -> bytes:
    buf = io.BytesIO()
    img.save(buf, format="PNG")
    return buf.getvalue()


def _kep_meret_dobozba(fajl, max_szelesseg: float, max_magassag: float) -> tuple[float, float]:
    """Kiszámolja egy kép arány-megtartó, pontos (nem "laza") méretét egy adott dobozba.
    SZÁNDÉKOSAN nem az fpdf2 image()-jének saját keep_aspect_ratio=True paraméterét
    használjuk erre - az a megszorított (kisebbik) tengelyen a kép KÖZEPÉRE igazítja a
    dobozt, nem a bal-felső sarokhoz, ami egy tágas doboznál (pl. álló fénykép egy széles
    dobozban) jelentősen lejjebb/oldalra tolja a kép tényleges pozícióját a vártnál -
    pontosan ez okozott egy nehezen felderíthető átfedést a szöveg/vonal és a kép között."""
    with Image.open(fajl) as im:
        img_w, img_h = im.size
    arany = img_w / img_h
    if max_magassag * arany <= max_szelesseg:
        return max_magassag * arany, max_magassag
    return max_szelesseg, max_szelesseg / arany


class EbkNapiOsszefoglaloPDF(FPDF):
    """Az EBK koordinátor napi összefoglalója egy adott projekt egy adott napjáról -
    az első oldalon 4 diagram (ellenőrzött területek, alvállalkozók érintettsége,
    szabálytalanságok tételenként, szabálytalanságok súlya), utána a részletes táblázatok."""

    def __init__(self, projekt, datum):
        super().__init__(orientation="P", format="A4")
        self.projekt = projekt
        self.datum = datum
        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", 15)
        self.cell(0, 9, "Biztonsági és egészségvédelmi koordinátori napi összefoglaló", ln=True, align="C")
        self.set_font("DejaVu", "", 10)
        self.cell(0, 6, f"{self.projekt.megrendelo_nev} - {self.datum.strftime('%Y-%m-%d')}", ln=True, align="C")
        if self.projekt.kivitelezes_helyszine:
            self.cell(0, 5, self.projekt.kivitelezes_helyszine, ln=True, align="C")
        self.ln(2)

    def footer(self):
        self.set_y(-15)
        self.set_font("DejaVu", "", 8)
        self.cell(0, 10, "EmeLOG Nyilvántartó rendszerrel készült", align="L")
        self.set_x(-30)
        self.cell(0, 10, f"Oldal {self.page_no()}/{{nb}}", align="R")

    def diagramok_hozzaadasa(self, terulet_adatok, alvallalkozo_adatok, tetel_adatok, sulyossag_adatok):
        kep_szelesseg = 90
        x_bal, x_jobb = 10, 108
        y_felso, y_also = self.get_y(), None

        self.image(io.BytesIO(oszlopdiagram_kep("Ellenőrzött területek", terulet_adatok, (13, 110, 253))), x=x_bal, y=y_felso, w=kep_szelesseg)
        self.image(io.BytesIO(oszlopdiagram_kep("Alvállalkozók (szabálytalanság)", alvallalkozo_adatok, (255, 193, 7))), x=x_jobb, y=y_felso, w=kep_szelesseg)
        y_also = y_felso + 62
        self.image(io.BytesIO(oszlopdiagram_kep("Szabálytalanságok tételenként", tetel_adatok, (220, 53, 69))), x=x_bal, y=y_also, w=kep_szelesseg)
        self.image(io.BytesIO(oszlopdiagram_kep("Szabálytalanságok súlya", sulyossag_adatok, (108, 117, 125))), x=x_jobb, y=y_also, w=kep_szelesseg)
        self.set_y(y_also + 62)

    def tablazat_fejlec(self, cim: str):
        self.ln(4)
        self.set_font("DejaVu", "B", 12)
        self.cell(0, 8, cim, ln=True)

    def ellenorzesek_tablazata(self, ellenorzesek):
        oszlopok = [40, 45, 45, 30, 30]
        fejlecek = ["Helyszín", "Épület / Szint", "Ellenőrizte", "Napi rendben", "Szabálytalanság"]
        self.set_font("DejaVu", "B", 8)
        self.set_fill_color(220, 220, 220)
        for szel, cim in zip(oszlopok, fejlecek):
            self.cell(szel, 7, cim, border=1, fill=True, align="C")
        self.ln()
        self.set_font("DejaVu", "", 8)
        for e in ellenorzesek:
            szab_szam = len([t for t in e.tetel_eredmenyek if t.statusz == "SZABALYTALANSAG"])
            rendben_szam = len([t for t in e.tetel_eredmenyek if t.statusz == "RENDBEN"])
            epulet_szint = " / ".join(filter(None, [e.epulet.nev if e.epulet else None, e.szint.nev if e.szint else None])) or "-"
            self.cell(oszlopok[0], 7, (e.terulet.nev if e.terulet else "-")[:22], border=1)
            self.cell(oszlopok[1], 7, epulet_szint[:25], border=1)
            self.cell(oszlopok[2], 7, (e.ellenorzo.username if e.ellenorzo else "-")[:22], border=1, align="C")
            self.cell(oszlopok[3], 7, str(rendben_szam), border=1, align="C")
            self.cell(oszlopok[4], 7, str(szab_szam), border=1, align="C")
            self.ln()

    def szabalytalansagok_tablazata(self, szabalytalansagok):
        oszlopok = [40, 32, 25, 18, 75]
        fejlecek = ["Alvállalkozó", "Tevékenység", "Munkavállaló", "Súly.", "Leírás"]
        self.set_font("DejaVu", "B", 8)
        self.set_fill_color(220, 220, 220)
        for szel, cim in zip(oszlopok, fejlecek):
            self.cell(szel, 7, cim, border=1, fill=True, align="C")
        self.ln()
        self.set_font("DejaVu", "", 8)
        x_start = self.get_x()
        for sz in szabalytalansagok:
            y_start = self.get_y()
            self.set_xy(x_start, y_start)
            self.cell(oszlopok[0], 7, (sz.alvallalkozo.nev if sz.alvallalkozo else "-")[:24], border=1)
            self.cell(oszlopok[1], 7, (sz.tevekenyseg.nev if sz.tevekenyseg else "-")[:20], border=1)
            self.cell(oszlopok[2], 7, (sz.munkavallalo_neve or "-")[:14], border=1)
            self.cell(oszlopok[3], 7, SULYOSSAG_CIMKE.get(sz.sulyossag, "-"), border=1, align="C")
            self.set_xy(x_start + sum(oszlopok[:4]), y_start)
            self.multi_cell(oszlopok[4], 7, (sz.leiras or "-")[:200], border=1, new_x=XPos.LMARGIN, new_y=YPos.NEXT)
            self.set_y(max(self.get_y(), y_start + 7))


class EbkEllenorzesPDF(FPDF):
    """Egy konkrét helyszíni ellenőrzés (bejárás) teljes, nyomtatható jegyzőkönyve - a Napi
    Összefoglalótól eltérően EGYETLEN bejárás minden részletét tartalmazza, a szabálytalanságok
    fényképével és aláírásával együtt."""

    def __init__(self, ellenorzes):
        super().__init__(orientation="P", format="A4")
        self.ellenorzes = ellenorzes
        self.add_font("DejaVu", "", str(STATIC_DIR / "DejaVuSans.ttf"))
        self.add_font("DejaVu", "B", str(STATIC_DIR / "DejaVuSans-Bold.ttf"))
        self.set_auto_page_break(auto=True, margin=18)

    def header(self):
        e = self.ellenorzes
        self.set_font("DejaVu", "B", 15)
        self.cell(0, 9, "Biztonsági és egészségvédelmi koordinátori ellenőrzés", ln=True, align="C")
        self.set_font("DejaVu", "", 10)
        self.cell(0, 6, f"{e.projekt.megrendelo_nev} - {e.datum.strftime('%Y-%m-%d') if e.datum else '-'}", ln=True, align="C")
        helyszin = " / ".join(filter(None, [
            e.terulet.nev if e.terulet else None,
            e.epulet.nev if e.epulet else None,
            "Minden szint" if e.osszes_szint else (e.szint.nev if e.szint else None),
        ]))
        if helyszin:
            self.cell(0, 5, helyszin, ln=True, align="C")
        if e.celellenorzes:
            self.cell(0, 5, f"Célellenőrzés: {e.celellenorzes}", ln=True, align="C")
        self.ln(2)

    def footer(self):
        self.set_y(-15)
        self.set_font("DejaVu", "", 8)
        self.cell(0, 10, "EmeLOG Nyilvántartó rendszerrel készült", align="L")
        self.set_x(-30)
        self.cell(0, 10, f"Oldal {self.page_no()}/{{nb}}", align="R")

    def alapadatok(self):
        e = self.ellenorzes
        self.set_font("DejaVu", "", 10)
        self.cell(0, 6, f"Ellenőrizte: {e.ellenorzo.username if e.ellenorzo else '-'}", ln=True)
        self.cell(0, 6, f'"Minden rendben" gomb használva: {"Igen" if e.mindenrendben else "Nem"}', ln=True)
        self.ln(2)

    def szabalytalansag_blokk(self, sz):
        # Előre lefoglalunk kb. 100mm-t (szöveges rész + legfeljebb max_magassag=60mm-es kép) -
        # ha nem férne ki, inkább új oldalon kezdjük, minthogy a fénykép/aláírás (amit explicit
        # y-nal helyezünk el, így az automatikus oldaltörés nem vigyáz rá) alul levágódjon.
        if self.get_y() > self.page_break_trigger - 100:
            self.add_page()

        szin = SULYOSSAG_SZIN.get(sz.sulyossag, (108, 117, 125))
        self.set_fill_color(*szin)
        self.rect(10, self.get_y() + 1.5, 4, 4, style="F")
        self.set_xy(16, self.get_y())
        self.set_font("DejaVu", "B", 11)
        self.multi_cell(
            0, 6, f"{sz.tetel.szoveg}  [{SULYOSSAG_CIMKE.get(sz.sulyossag, '-')}]",
            new_x=XPos.LMARGIN, new_y=YPos.NEXT,
        )

        self.set_font("DejaVu", "", 9)
        if sz.szint:
            self.cell(0, 5, f"Szint: {sz.szint.nev}", ln=True)
        if sz.engedely_nelkul:
            self.set_font("DejaVu", "B", 9)
            self.cell(0, 5, "Engedély nélküli munkavégzés", ln=True)
            self.set_font("DejaVu", "", 9)
            self.cell(0, 5, f"Cég: {sz.engedely_ceg_nev or '-'}  |  Székhely: {sz.engedely_ceg_szekhely or '-'}", ln=True)
            self.cell(0, 5, f"Felelős vezető: {sz.engedely_felelos_vezeto or '-'}  |  Helyi vezető: {sz.engedely_helyi_vezeto or '-'}", ln=True)
            if sz.engedely_megrendelo_neve or sz.engedely_tevekenyseg:
                self.cell(0, 5, f"Megrendelő: {sz.engedely_megrendelo_neve or '-'}  |  Tevékenység: {sz.engedely_tevekenyseg or '-'}", ln=True)
        else:
            self.cell(0, 5, f"Alvállalkozó: {sz.alvallalkozo.nev if sz.alvallalkozo else '-'}  |  Tevékenység: {sz.tevekenyseg.nev if sz.tevekenyseg else '-'}", ln=True)
        self.cell(0, 5, f"Munkavállaló: {sz.munkavallalo_neve or '-'}  |  Engedély száma: {sz.munkavegzesi_engedely_szam or '-'}", ln=True)

        self.ln(1)
        self.multi_cell(0, 5, f"Leírás: {sz.leiras or '-'}", new_x=XPos.LMARGIN, new_y=YPos.NEXT)

        if sz.elismerve is True:
            elismeres_szoveg = "Elismerte"
        elif sz.elismerve is False:
            elismeres_szoveg = f"Nem ismerte el - {sz.nem_elismeres_indoklas or '-'}"
        else:
            elismeres_szoveg = "Nincs nyilatkozat"
        self.cell(0, 5, elismeres_szoveg, ln=True)

        # A fényképek/aláírások mérete (pl. álló, telefonnal készült fotó) előre nem ismert -
        # rögzített magassági korlát nélkül egy magas kép rálógna a következő szakaszra.
        # SZÁNDÉKOSAN nem az fpdf2 image() saját keep_aspect_ratio=True paraméterét
        # használjuk: az a laza (a kép tényleges méreténél nagyobb) dobozon belül a kisebbik
        # tengelyen KÖZÉPRE igazítja a képet, nem a bal-felső sarokhoz - emiatt egy tágas
        # dobozba (pl. egy széles aláírás-vászon egy magas dobozba) helyezett kép a vártnál
        # sokkal lejjebb csúszott, és átfedte a hozzá képest "fixen" pozicionált vonalat/nevet.
        # Ehelyett előre kiszámoljuk a pontos, "laza hely" nélküli méretet (_kep_meret_dobozba),
        # így a kép garantáltan pontosan (x, y_kep)-nél kezdődik.
        y_kep = self.get_y() + 2
        x = 16
        max_magassag = 60
        alul = y_kep
        if sz.fenykep_path:
            fajl = sz.fenykep_path.lstrip("/")
            if Path(fajl).exists():
                try:
                    kep_w, kep_h = _kep_meret_dobozba(fajl, 55, max_magassag)
                    self.image(fajl, x=x, y=y_kep, w=kep_w, h=kep_h)
                    x += kep_w + 5
                    alul = max(alul, y_kep + kep_h)
                except Exception:
                    pass
        if sz.alairas_path:
            fajl = sz.alairas_path.lstrip("/")
            if Path(fajl).exists():
                try:
                    # Rendes dokumentum-aláírás blokk: kép, alatta vonal, alatta a rögzített
                    # munkavállaló neve - az aláírás képének ezért kevesebb magasság jut, hogy
                    # a vonal+név mindig beleférjen a max_magassag-ba.
                    alairas_w = 45
                    alairas_max_h = max_magassag - 8
                    kep_w, kep_h = _kep_meret_dobozba(fajl, alairas_w, alairas_max_h)
                    self.image(fajl, x=x, y=y_kep, w=kep_w, h=kep_h)
                    vonal_y = y_kep + kep_h + 2
                    self.set_draw_color(120, 120, 120)
                    self.line(x, vonal_y, x + kep_w, vonal_y)
                    self.set_xy(x, vonal_y + 0.5)
                    self.set_font("DejaVu", "", 8)
                    self.cell(kep_w, 4, sz.munkavallalo_neve or "-", align="C")
                    alul = max(alul, vonal_y + 0.5 + 4)
                except Exception:
                    pass
        if alul > y_kep:
            self.set_y(alul)

        self.ln(4)
        self.set_draw_color(200, 200, 200)
        self.line(10, self.get_y(), 200, self.get_y())
        self.ln(4)

    def egyszeru_lista(self, cim: str, tetelek: list):
        if not tetelek:
            return
        self.ln(2)
        self.set_font("DejaVu", "B", 11)
        self.cell(0, 7, cim, ln=True)
        self.set_font("DejaVu", "", 9)
        for t in tetelek:
            self.multi_cell(
                0, 5, f"- {t.tetel.szoveg}" + (f"  (Szint: {t.szint.nev})" if t.szint else ""),
                new_x=XPos.LMARGIN, new_y=YPos.NEXT,
            )
