import io
import os
import shutil
import urllib.parse
import uuid
from datetime import date, datetime

from fastapi import APIRouter, Request, Depends, Form, File, UploadFile, BackgroundTasks, HTTPException, status
from fastapi.responses import HTMLResponse, JSONResponse, StreamingResponse, FileResponse
from sqlalchemy import or_
from sqlalchemy.orm import Session, joinedload

import models
from security import EMELOGEP_SZEREPKOROK
from database import get_db
from security import (
    is_safe_extension, sanitize_filename, get_current_user, get_working_company_id,
    apply_user_data_scope_filter, is_machine_allowed, is_company_active, require_modul,
    tartalom_illeszkedik_e_kiterjesztesre
)
from image_utils import kep_e, tomorit_kepet
from msz_logic import (
    check_uzemora_drift_and_escalate, kezeli_sikertelen_vizsgalati_minositest, eui_fovizsgalatra_jogosult_e,
    VIZSGALATI_MINOSITES_KIVONO_ERTEKEK
)
from routers.machines import get_search_filter, tipus_egyezo_gepek, _tipus_norm
from berles_utils import berelt_gep_idk_a_ceghez, aktiv_berlet
from kozos_dokumentum_utils import (
    KOZOS_FAJLTIPUSOK, kozos_prefix, kozos_utvonal_e, kozosbe_masol, fizikai_torol, arva_kozos_torlese, hivatkozas_szam
)
from naplo_utils import naploz
from templates_env import templates, helyi_ido, helyi_datetime, helyi_nap_utc_hatarai

router = APIRouter(dependencies=[Depends(require_modul("EMELOGEP"))])


# ---------------------------------------------------------------------------------------------------------------------
# Dokumentum-feltöltés (/upload-file) szerver-oldali szabályai (v64, J-03 - docs/JOGOSULTSAGOK.md).
# A feltöltő felület (list.html) csak kliens-oldali korlátokat tartalmaz; a szervernek is érvényesítenie kell őket.
# ---------------------------------------------------------------------------------------------------------------------
# Akik bármilyen dokumentumtípust feltölthetnek (a többi szerepkör - pl. Felhasználó - csak az ALAP_FAJLTIPUSOK-at).
# A típus szabad szöveg is lehet (az MSZ 16226 oldal "egyéb dokumentumtípusai"), ezért itt NINCS zárt lista - a veszélyes
# hatásokat (dátum-átállítás, minősítés) külön szabály védi, lásd _datum_minosites_hiba().
SZAKMAI_FELTOLTO_SZEREPKOROK = ("Admin", "Emelőgép szakértő", "Emelőgép vizsgáló", "Emelőgép ügyintéző")
# v78: a "Fénykép - Adattábla" önálló típus (a gép adattáblájának fényképe: gépazonosító); képként töltődik fel és az alap típusok közé tartozik.
ADATTABLA_FAJLTIPUS = "Fénykép - Adattábla"
ALAP_FAJLTIPUSOK = ("Fénykép", ADATTABLA_FAJLTIPUS, "Gépnapló")
# A "Felhasználó" szerepkör a /gep-fajlok listában csak ezeket látja (a feltölthető alap típusok + a napi ellenőrzés / javítás fotói).
# "Kockázatértékelés": az MSZ 9750 1.2 pont (gép-szerkesztésen feltöltött, nem szakmai-feltöltős) írásos indoklása - nem érzékeny,
# ugyanúgy látható mindenkinek, mint a gep_adatlap.html-en a közvetlen "Kockázatértékelés megnyitása" link.
FELHASZNALO_LATHATO_FAJLTIPUSOK = ("Fénykép", ADATTABLA_FAJLTIPUS, "Gépnapló", "Napi ellenőrzés fotó", "Javítási munkalap", "Kockázatértékelés")
# Ezeknél a típusoknál a feltöltés a gép vizsgálati dátumát is átállíthatja (update_date=true), az első négynél minősítést is adhat.
VIZSGALATI_JKV_FAJLTIPUSOK = (
    "Szerkezeti vizsgálat jkv", "Fővizsgálat jkv", "Időszakos biztonsági felülvizsgálat jkv", "Rendkívüli vizsgálat jkv",
)
UZEMBEHELYEZESI_FAJLTIPUS = "Üzembehelyezési jkv / Ismételt üzembehelyezés"
DATUMOS_FAJLTIPUSOK = VIZSGALATI_JKV_FAJLTIPUSOK + (UZEMBEHELYEZESI_FAJLTIPUS,)
FAJLTIPUS_MAX_HOSSZ = 100   # a File.file_type oszlop hossza


def _fajltipus_hiba(current_user, file_type: str):
    """None, ha az adott felhasználó feltöltheti ezt a dokumentumtípust, különben a hibaüzenet."""
    if not file_type or len(file_type) > FAJLTIPUS_MAX_HOSSZ:
        return "Érvénytelen dokumentumtípus!"
    if current_user.role not in SZAKMAI_FELTOLTO_SZEREPKOROK and file_type not in ALAP_FAJLTIPUSOK:
        return "Ezt a dokumentumtípust a szerepköröd nem töltheti fel (csak fénykép és gépnapló)!"
    return None


def _datum_minosites_hiba(gep, current_user, file_type: str, szigor_ki: bool):
    """None, ha a felhasználó egy feltöltött jegyzőkönyvvel átállíthatja a gép vizsgálati dátumát / minősítést adhat,
    különben a hibaüzenet. A szabály UGYANAZ, mint a vizsgálat-rögzítésnél (routers/inspections.py, /general-jegyzokonyv):
      - Admin (rendszeradmin is), Emelőgép szakértő: minden típus;
      - Emelőgép vizsgáló: kizárólag a Szerkezeti vizsgálat jkv;
      - Emelőgép ügyintéző: Szerkezeti, Rendkívüli, Üzembehelyezési jkv; a Fővizsgálat / Időszakos biztonsági felülvizsgálat jkv
        csak ha a cég beállításában a szigorítás ki van kapcsolva ÉS a gép az EBSZ 7.2.10 szerint jogosult (eui_fovizsgalatra_jogosult_e);
      - mindenki más (Felhasználó stb.): soha."""
    szerep = current_user.role
    if szerep in ("Admin", "Emelőgép szakértő"):
        return None
    if szerep == "Emelőgép vizsgáló":
        if file_type == "Szerkezeti vizsgálat jkv":
            return None
        return "Emelőgép vizsgáló kizárólag szerkezeti vizsgálati jegyzőkönyvvel állíthat dátumot / minősítést!"
    if szerep == "Emelőgép ügyintéző":
        if file_type in ("Fővizsgálat jkv", "Időszakos biztonsági felülvizsgálat jkv"):
            if not szigor_ki:
                return "Az ügyintézői fővizsgálat nincs engedélyezve a beállításokban!"
            if not eui_fovizsgalatra_jogosult_e(gep):
                return "Emelőgép ügyintéző nem rögzíthet fővizsgálatot/időszakos biztonsági felülvizsgálatot ehhez a géphez a jogszabály értelmében (teherbírás vagy kezelői munkahely miatt)!"
        return None
    return "A szerepköröd nem állíthat vizsgálati dátumot / minősítést feltöltött dokumentummal!"


def _fajl_mentese_egyedi_nevvel(mappa: str, nev: str, iro):
    """A fájlt a megadott mappába menti, és SOHA nem ír felül meglévőt (J-03 / K8: eddig az azonos nevű fájl - pl. egy hivatalos,
    kiszámítható nevű jegyzőkönyv-PDF - felülíródott). Ütközésnél a név egy véletlen utótagot kap (`nev_ab12cd34.kit`).
    Kizárólagos létrehozással ("xb") nyitunk, így két egyidejű, azonos nevű feltöltés sem írhatja felül egymást.
    `iro(fajl)` írja ki a tartalmat. Visszaadja a mentett fájl elérési útját (mappa/név)."""
    torzs, kiterjesztes = os.path.splitext(nev)
    for kiserlet in range(6):
        jelolt = nev if kiserlet == 0 else f"{torzs}_{uuid.uuid4().hex[:8]}{kiterjesztes}"
        hely = f"{mappa}/{jelolt}"
        try:
            with open(hely, "xb") as fajl_objektum:
                iro(fajl_objektum)
            return hely
        except FileExistsError:
            continue
    raise RuntimeError("Nem sikerült egyedi fájlnevet képezni a feltöltéshez.")


@router.get("/export-excel")
def export_excel(
    request: Request,
    mode: str = "all",
    search1: str = "",
    search2: str = "",
    search3: str = "",
    cols: str = "",
    db: Session = Depends(get_db),
    current_user: models.User = Depends(get_current_user)
):
    # Beimportáljuk a profi Excel generálót a függvényen belül
    import openpyxl
    from openpyxl.styles import Font, PatternFill

    working_company_id = get_working_company_id(current_user, request)
    # JAVÍTVA (2026-10-11-i user-jelzés): eddig a bérelt-nálam gépek (más cégtől aktív/jóváhagyott
    # bérlettel kihelyezve, l. [[project_v86_berlet_telephely_keszenleti_hely_oroklodes]]) teljesen
    # KIMARADTAK az exportból, mert a lekérdezés kizárólag a saját céget (company_id) nézte - l. a
    # _gepek_szurt_lekerdezes (routers/machines.py) ugyanezt a mintát követő javítása.
    berelt_gep_idk = berelt_gep_idk_a_ceghez(working_company_id, db)
    if berelt_gep_idk:
        query = db.query(models.Machine).filter(
            or_(models.Machine.company_id == working_company_id, models.Machine.id.in_(berelt_gep_idk))
        )
    else:
        query = db.query(models.Machine).filter(models.Machine.company_id == working_company_id)
    query = apply_user_data_scope_filter(query, current_user)

    if mode == "visible":
        if search1:
            query = query.filter(get_search_filter(search1, models))
        if search2:
            query = query.filter(get_search_filter(search2, models))
        if search3:
            query = query.filter(get_search_filter(search3, models))

    gepek = query.all()

    # Bérelt-nálam gépnél a Telephely/"Készenléti hely" a bérlő (a jóváhagyáskor megadott) saját
    # adatát mutassa, ne a bérbeadóét - ugyanaz a felülírás, mint a /lista és a gép-adatlap nézeteken.
    for gep in gepek:
        gep.megjelenitett_telephely = gep.telephely
        gep.megjelenitett_keszenleti_hely = gep.megnevezes
        if gep.company_id != working_company_id:
            berlet = aktiv_berlet(gep, db)
            if berlet and berlet.jovahagyva:
                if berlet.berlo_site_id:
                    gep.megjelenitett_telephely = berlet.berlo_site
                if berlet.berlo_keszenleti_hely:
                    gep.megjelenitett_keszenleti_hely = berlet.berlo_keszenleti_hely

    configs = db.query(models.MachineTypeConfig).filter(models.MachineTypeConfig.company_id == working_company_id).all()
    rejtett_map = {}
    for c in configs:
        if c.rejtett_mezok:
            rejtett_map[c.geptipus] = [x.strip() for x in c.rejtett_mezok.split(",")]
        else:
            rejtett_map[c.geptipus] = []

    def get_value_if_not_hidden(gep, db_field_name, value_func):
        rejtett_mezok = rejtett_map.get(gep.geptipus, [])
        if db_field_name in rejtett_mezok:
            return "Nem releváns"
        return value_func(gep)

    def format_teher(g):
        return f"{g.teherbiras} kg" if g.teherbiras else "-"

    def format_datum(d):
        return d.strftime("%Y-%m-%d") if d else "-"

    def format_gep_jelzo(g):
        if not g:
            return "-"
        return f"{g.megnevezes or '-'} ({g.gyari_szam or 'gyári szám nélkül'})"

    col_map = {
        1: ("Telephely", lambda g: g.megjelenitett_telephely.nev if g.megjelenitett_telephely else "-"),
        2: ("Helyszín", lambda g: get_value_if_not_hidden(g, "megnevezes", lambda x: x.megjelenitett_keszenleti_hely)),
        3: ("Gyártó", lambda g: get_value_if_not_hidden(g, "gyarto", lambda x: x.gyarto)),
        4: ("Típus", lambda g: get_value_if_not_hidden(g, "tipus", lambda x: x.tipus)),
        5: ("Gyári szám", lambda g: get_value_if_not_hidden(g, "gyari_szam", lambda x: x.gyari_szam)),
        6: ("Géptípus", lambda g: g.geptipus),
        7: ("Csoportszám", lambda g: get_value_if_not_hidden(g, "csoportszam", lambda x: x.calculated_csoportszam or "-")),
        8: ("Üzemóra", lambda g: get_value_if_not_hidden(g, "uzemora", lambda x: x.uzemora)),
        9: ("Leltári szám", lambda g: get_value_if_not_hidden(g, "leltari_szam", lambda x: x.leltari_szam or "-")),
        10: ("Teherbírás", lambda g: get_value_if_not_hidden(g, "teherbiras", lambda x: format_teher(x))),
        11: ("Gyártás dátuma", lambda g: get_value_if_not_hidden(g, "gyartas_datum", lambda x: format_datum(x.gyartas_datum))),
        12: ("Üzembe helyezés", lambda g: get_value_if_not_hidden(g, "uzembe_helyezes_datum", lambda x: format_datum(x.uzembe_helyezes_datum))),
        13: ("Státusz", lambda g: f"{g.statusz}" if g.statusz != "Aktív" else "Aktív"),
        # ÚJ (2026-10-11-i user-jelzés): a bérelt-nálam gépek exportba kerülésével fontos jelölni,
        # melyik gép saját és melyik bérelt - és a fő gép/tartozék kapcsolat eddig egyáltalán nem
        # látszott az exportban (nem volt nyoma, hogy egy sor egy másikhoz tartozik).
        14: ("Eredet", lambda g: "Saját" if g.company_id == working_company_id else f"Bérelt ({g.ceg.nev if g.ceg else '-'})"),
        15: ("Fő gép", lambda g: format_gep_jelzo(g.fo_gep) if g.fo_gep_id else "-"),
        16: ("Tartozékok", lambda g: ", ".join(format_gep_jelzo(t) for t in g.tartozekok) if g.tartozekok else "-"),
        # 2026-10-11-i user-jelzés: az ID a rendszer belső adatbázis-azonosítója, üzletileg nem
        # releváns (a gyári szám / leltári szám az üzleti azonosító) - ezért az utolsó oszlopba
        # került, hogy ne a legszembetűnőbb (első) helyen legyen egy technikai mező.
        0: ("ID", lambda g: g.id),
    }

    selected_indices = []
    if cols:
        for c in cols.split(","):
            selected_indices.append(int(c))
    else:
        for k in col_map.keys():
            selected_indices.append(k)

    # --- ÚJ: OPENPYXL EXCEL GENERÁLÁS ---
    wb = openpyxl.Workbook()
    ws = wb.active
    ws.title = "Emelőgép Lista"

    # ÚJ (2026-10-11-i user-jelzés): dokumentum-metaadat, hogy a fájl az EmeLOG rendszerből származik
    # (Fájl > Tulajdonságok a legtöbb Office-szerű programban ezt mutatja).
    wb.properties.creator = "EmeLOG"
    wb.properties.lastModifiedBy = "EmeLOG"
    wb.properties.title = "EmeLOG emelőgép-export"
    wb.properties.subject = "Emelőgép-nyilvántartás export"
    wb.properties.description = "Az EmeLOG (emelőgép-nyilvántartó és vizsgálatkezelő) rendszerrel készült export."
    wb.properties.category = "EmeLOG export"

    # Stílusok előkészítése
    header_font = Font(bold=True)
    disabled_fill = PatternFill(start_color="EEEEEE", end_color="EEEEEE", fill_type="solid")  # Világosszürke háttér
    disabled_font = Font(color="888888", italic=True)  # Szürke, dőlt betű

    # 1. Fejléc beírása és formázása
    header_row = [col_map[i][0] for i in selected_indices if i in col_map]
    ws.append(header_row)
    for cell in ws[1]:
        cell.font = header_font

    # 2. Adatok beírása és a "Nem releváns" cellák színezése
    for gep in gepek:
        adat_sor = []
        for i in selected_indices:
            if i in col_map:
                adat_sor.append(col_map[i][1](gep))

        ws.append(adat_sor)
        current_row = ws.max_row

        # Végigmegyünk az éppen beszúrt soron, és ha letiltott adatot találunk, színezzük
        for col_idx, cell_value in enumerate(adat_sor, start=1):
            if cell_value == "Nem releváns":
                cell = ws.cell(row=current_row, column=col_idx)
                cell.fill = disabled_fill
                cell.font = disabled_font

    # 3. Oszlopszélességek automatikus igazítása
    for col in ws.columns:
        max_length = 0
        column_letter = col[0].column_letter
        for cell in col:
            try:
                if len(str(cell.value)) > max_length:
                    max_length = len(str(cell.value))
            except:
                pass
        adjusted_width = min(max_length + 2, 40)  # Max 40 karakter széles lehet egy oszlop
        ws.column_dimensions[column_letter].width = adjusted_width

    # 4. Fájl mentése a memóriába és elküldése
    output = io.BytesIO()
    wb.save(output)
    output.seek(0)

    filename = urllib.parse.quote("EmeLOG_Export.xlsx")

    return StreamingResponse(
        output,
        media_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
        headers={'Content-Disposition': f'attachment; filename*=UTF-8\'\'{filename}'}
    )


@router.post("/gyors-uzemora")
async def gyors_uzemora(
    request: Request,
    background_tasks: BackgroundTasks,
    machine_id: int = Form(...),
    uzemora: float = Form(...),
    db: Session = Depends(get_db),
    current_user: models.User = Depends(get_current_user)
):
    if current_user.role not in EMELOGEP_SZEREPKOROK:      # J-25 (v76): pozitív lista
        return JSONResponse(status_code=403, content={"message": "Nincs jogosultságod az üzemóra frissítésére!"})

    if current_user.role in ["Felhasználó", "Emelőgép ügyintéző"]:
        if not getattr(current_user, 'jog_uzemora_rogzites', False):
            return JSONResponse(
                status_code=403,
                content={"message": "Nincs jogosultságod az üzemóra frissítésére!"}
            )

    working_company_id = get_working_company_id(current_user, request)

    if not is_company_active(working_company_id, db):
        return JSONResponse(
            status_code=403,
            content={"message": "Ez a cég inaktív státuszú, üzemóra nem frissíthető!"}
        )

    if current_user.csak_olvasas:
        return JSONResponse(
            status_code=403,
            content={"message": "Csak megtekintési jogosultsággal rendelkezel, szerkesztés nem lehetséges!"}
        )

    gep = db.query(models.Machine).filter(
        models.Machine.id == machine_id,
        models.Machine.company_id == working_company_id
    ).first()

    if not gep or not is_machine_allowed(gep, current_user):
        return JSONResponse(
            status_code=404,
            content={"message": "A keresett gép nem található!"}
        )

    old_val = gep.uzemora
    gep.uzemora = uzemora

    # Ha a tényleges használat jelentősen meghaladja a tervezett napi átlagot,
    # a rendszer automatikusan szigorítja a besorolást és értesít.
    check_uzemora_drift_and_escalate(gep, db, background_tasks)

    log = models.AuditLog(
        machine_id=gep.id,
        user_id=current_user.id,
        field_name="Üzemóra",
        old_value=str(old_val),
        new_value=str(uzemora)
    )
    db.add(log)
    db.commit()

    return JSONResponse(status_code=200, content={"message": "Sikeres mentés!"})


# ---------------------------------------------------------------------------------------------------------------------
# MEGOSZTOTT DOKUMENTUMOK (v80, Miklós kérése) - Használati utasítás / Gépkönyv / Adatlap: egy fájlra több gép hivatkozik, újra feltölteni nem kell.
# Működés, tárolás, törlés: kozos_dokumentum_utils.py és docs/KOZOS_DOKUMENTUM.md.
# ---------------------------------------------------------------------------------------------------------------------
def _kozos_kapu(request: Request, db: Session, current_user):
    """A megosztás ugyanazokat a kapukat követi, mint a feltöltés (/upload-file): aktív cég, nem csak olvasó, feltöltési jog, és szakmai szerepkör
    (a Felhasználó ezeket a típusokat nem is tölthetné fel). Visszatérés: (munkakörnyezet cége, None) vagy (None, hibaválasz)."""
    cid = get_working_company_id(current_user, request)
    if not is_company_active(cid, db):
        return None, JSONResponse(status_code=403, content={"message": "Ez a cég inaktív státuszú, dokumentum nem csatolható!"})
    if current_user.csak_olvasas:
        return None, JSONResponse(status_code=403, content={"message": "Csak megtekintési jogosultsággal rendelkezel, szerkesztés nem lehetséges!"})
    if current_user.role in ["Felhasználó", "Emelőgép ügyintéző"] and not getattr(current_user, 'jog_dokumentum_feltoltes', False):
        return None, JSONResponse(status_code=403, content={"message": "Nincs jogosultságod dokumentum feltöltésére!"})
    if current_user.role not in SZAKMAI_FELTOLTO_SZEREPKOROK:
        return None, JSONResponse(status_code=403, content={"message": "Ezt a dokumentumtípust a szerepköröd nem kezelheti!"})
    return cid, None


def _kozos_tarsgepek(db: Session, gep, current_user) -> list:
    """A gép azonos gyártójú ÉS típusú, a felhasználó által látható társgépei (a gép maga nélkül), a cégen belül."""
    return [g for g in tipus_egyezo_gepek(db, gep.company_id, gep.gyarto, gep.tipus) if g.id != gep.id and is_machine_allowed(g, current_user)]


def _kozos_cel_hiba(forras_gep, cel, current_user):
    """None, ha a cél-gép megkaphatja a forrásgép dokumentumát, különben a hiba oka (szöveg)."""
    if cel.id == forras_gep.id:
        return "ugyanaz a gép"
    if cel.company_id != forras_gep.company_id:
        return "másik cég gépe"
    if not is_machine_allowed(cel, current_user):
        return "nincs hozzáférésed a géphez"
    gy, ti = _tipus_norm(forras_gep.gyarto), _tipus_norm(forras_gep.tipus)
    if not gy or not ti or gy == "-" or ti == "-" or _tipus_norm(cel.gyarto) != gy or _tipus_norm(cel.tipus) != ti:
        return "nem azonos gyártó és típus"
    return None


def _kozos_fajlnev(fajl) -> str:
    return os.path.basename(fajl.file_path or "")


def _hivatkozas_keszit(db: Session, forras, forras_gep, cel, current_user):
    """Hivatkozás-sor a cél-gépnek a (már közös mappában lévő) forrás-fájlra + napló a cél-gép eseményei közé. Nem commitol."""
    uj = models.File(machine_id=cel.id, file_path=forras.file_path, file_type=forras.file_type, megjegyzes=forras.megjegyzes)
    db.add(uj)
    naploz(db, current_user, None, "DOKUMENTUM HIVATKOZÁS", regi="-",
           uj=f"Meglévő dokumentum használata: {forras.file_type}: {_kozos_fajlnev(forras)} (forrás: #{forras_gep.id} {forras_gep.megnevezes or '-'})",
           machine_id=cel.id)
    return uj


def _kozos_forras(db: Session, cid: int, current_user, file_id: int):
    """(forrás File, forrás gép, None) vagy (None, None, hibaválasz): a forrás a munkakörnyezet cégéé, látható, és megosztható típusú."""
    forras = db.query(models.File).filter(models.File.id == file_id).first()
    forras_gep = forras.machine if forras else None
    if not forras or not forras_gep or forras_gep.company_id != cid or not is_machine_allowed(forras_gep, current_user):
        return None, None, JSONResponse(status_code=404, content={"message": "A hivatkozott dokumentum nem található!"})
    if forras.file_type not in KOZOS_FAJLTIPUSOK:
        return None, None, JSONResponse(status_code=400, content={"message": "Csak Használati utasítás, Gépkönyv és Adatlap osztható meg!"})
    return forras, forras_gep, None


def _kozos_commit(db: Session, regi_fizikai, uj_masolat):
    """Commit; siker után a régi fizikai példány törlése, hibánál visszagörgetés és az újonnan létrehozott másolat törlése. Visszatérés: True, ha sikerült."""
    try:
        db.commit()
    except Exception as e:
        db.rollback()
        fizikai_torol(uj_masolat)
        print(f"❌ Hiba a megosztott dokumentum mentésekor: {type(e).__name__}: {e}")
        return False
    fizikai_torol(regi_fizikai)
    return True


def _kozos_ajanlat(db: Session, gep, uj_fajl, current_user):
    """Feltöltés után: mely társgépeknek nincs még ilyen típusú dokumentuma (a rájuk alkalmazás felajánlható), és hányuknak van már.
    None, ha nincs kinek felajánlani."""
    tarsak = _kozos_tarsgepek(db, gep, current_user)
    if not tarsak:
        return None
    van = {sor[0] for sor in db.query(models.File.machine_id).filter(
        models.File.machine_id.in_([g.id for g in tarsak]), models.File.file_type == uj_fajl.file_type).all()}
    jeloltek = [g for g in tarsak if g.id not in van]
    if not jeloltek:
        return None
    return {
        "file_id": uj_fajl.id,
        "file_type": uj_fajl.file_type,
        "mar_van": len(van),
        "jeloltek": [{"id": g.id, "megnevezes": g.megnevezes, "gyari_szam": g.gyari_szam, "leltari_szam": g.leltari_szam,
                      "telephely": g.telephely.nev if g.telephely else None} for g in jeloltek],
    }


@router.get("/gep-kozos-dokumentumok/{machine_id}")
def gep_kozos_dokumentumok(
    request: Request,
    machine_id: int,
    file_type: str = "",
    db: Session = Depends(get_db),
    current_user: models.User = Depends(get_current_user)
):
    """Feltöltés előtt: a gép azonos gyártójú+típusú társgépein már meglévő, ilyen típusú dokumentumok (fájlonként egyszer) - ezekre a gép egy kattintással
    hivatkozhat (POST /hivatkozas-fajl), nem kell újra feltölteni. CSAK OLVAS; csak annak ad listát, aki a megosztást végre is hajthatná."""
    cid, hiba = _kozos_kapu(request, db, current_user)
    if hiba or file_type not in KOZOS_FAJLTIPUSOK:
        return {"dokumentumok": [], "van_mar": False}
    gep = db.query(models.Machine).filter(models.Machine.id == machine_id, models.Machine.company_id == cid).first()
    if not gep or not is_machine_allowed(gep, current_user):
        return {"dokumentumok": [], "van_mar": False}
    tarsak = {g.id: g for g in _kozos_tarsgepek(db, gep, current_user)}
    van_mar = db.query(models.File).filter(models.File.machine_id == gep.id, models.File.file_type == file_type).count() > 0
    csoportok = {}
    if tarsak:
        for f in db.query(models.File).filter(models.File.machine_id.in_(list(tarsak)), models.File.file_type == file_type).order_by(
                models.File.uploaded_at.desc(), models.File.id.desc()).all():
            if not f.file_path or not os.path.isfile(f.file_path.lstrip("/")):
                continue                                                    # hiányzó fizikai fájlt nem ajánlunk fel
            cs = csoportok.setdefault(f.file_path, {"file_id": f.id, "fajlnev": _kozos_fajlnev(f), "feltoltve": helyi_ido(f.uploaded_at),
                                                    "gepek": []})
            cs["gepek"].append(tarsak[f.machine_id].megnevezes or f"#{f.machine_id}")
    return {"van_mar": van_mar, "dokumentumok": [
        {"file_id": cs["file_id"], "fajlnev": cs["fajlnev"], "feltoltve": cs["feltoltve"], "gepek": cs["gepek"][:5], "gep_db": len(cs["gepek"])}
        for cs in csoportok.values()]}


@router.post("/hivatkozas-fajl")
def hivatkozas_fajl(
    request: Request,
    machine_id: int = Form(...),
    file_id: int = Form(...),
    db: Session = Depends(get_db),
    current_user: models.User = Depends(get_current_user)
):
    """A gép egy MEGLÉVŐ (azonos gyártójú+típusú gép) Használati utasítás / Gépkönyv / Adatlap dokumentumára hivatkozik - fizikai feltöltés nélkül."""
    cid, hiba = _kozos_kapu(request, db, current_user)
    if hiba:
        return hiba
    cel = db.query(models.Machine).filter(models.Machine.id == machine_id, models.Machine.company_id == cid).first()
    if not cel or not is_machine_allowed(cel, current_user):
        return JSONResponse(status_code=403, content={"message": "Hiba történt vagy nincs jogosultságod!"})
    forras, forras_gep, hiba = _kozos_forras(db, cid, current_user, file_id)
    if hiba:
        return hiba
    ok = _kozos_cel_hiba(forras_gep, cel, current_user)
    if ok:
        return JSONResponse(status_code=400, content={"message": f"Erre a gépre nem használható ez a dokumentum ({ok})!"})
    if db.query(models.File).filter(models.File.machine_id == cel.id, models.File.file_path == forras.file_path).first():
        return JSONResponse(status_code=409, content={"message": "Ez a gép már hivatkozik erre a dokumentumra!"})

    try:
        regi, masolat = kozosbe_masol(forras, cid)
    except FileNotFoundError:
        return JSONResponse(status_code=404, content={"message": "A dokumentum fájlja nem található a szerveren!"})
    if regi:
        naploz(db, current_user, None, "DOKUMENTUM MEGOSZTÁS", regi="-",
               uj=f"{forras.file_type}: {_kozos_fajlnev(forras)} közös dokumentummá vált; hivatkozik rá: #{cel.id} {cel.megnevezes or '-'}",
               machine_id=forras_gep.id)
    # a hivatkozás-sor a (esetleg most átírt) közös útvonalra mutat
    _hivatkozas_keszit(db, forras, forras_gep, cel, current_user)
    if not _kozos_commit(db, regi, masolat):
        return JSONResponse(status_code=500, content={"message": "Hiba történt a mentés közben, semmi nem változott!"})
    return JSONResponse(status_code=200, content={"message": "A dokumentum hozzákapcsolva a géphez."})


@router.post("/kozos-dokumentum-alkalmaz")
def kozos_dokumentum_alkalmaz(
    request: Request,
    file_id: int = Form(...),
    machine_ids: list[int] = Form(...),
    db: Session = Depends(get_db),
    current_user: models.User = Depends(get_current_user)
):
    """Egy (frissen feltöltött) Használati utasítás / Gépkönyv / Adatlap hivatkozásának létrehozása a KIJELÖLT, azonos gyártójú+típusú gépeknek.
    Akinek már van ilyen TÍPUSÚ dokumentuma, azt nem írja felül (kihagyja és jelzi). Az egész egy tranzakció."""
    cid, hiba = _kozos_kapu(request, db, current_user)
    if hiba:
        return hiba
    forras, forras_gep, hiba = _kozos_forras(db, cid, current_user, file_id)
    if hiba:
        return hiba

    alkalmazhato, kihagyva = [], []
    for mid in dict.fromkeys(machine_ids):                      # duplikátumok nélkül, sorrendtartóan
        cel = db.query(models.Machine).filter(models.Machine.id == mid, models.Machine.company_id == cid).first()
        if not cel:
            kihagyva.append({"id": mid, "ok": "a gép nem található"})
            continue
        ok = _kozos_cel_hiba(forras_gep, cel, current_user)
        if not ok and db.query(models.File).filter(models.File.machine_id == cel.id, models.File.file_type == forras.file_type).count() > 0:
            ok = f"már van ilyen típusú dokumentuma ({forras.file_type})"
        if ok:
            kihagyva.append({"id": mid, "ok": ok})
        else:
            alkalmazhato.append(cel)
    if not alkalmazhato:
        return JSONResponse(status_code=200, content={"alkalmazva": 0, "kihagyva": kihagyva})

    try:
        regi, masolat = kozosbe_masol(forras, cid)
    except FileNotFoundError:
        return JSONResponse(status_code=404, content={"message": "A dokumentum fájlja nem található a szerveren!"})
    for cel in alkalmazhato:
        _hivatkozas_keszit(db, forras, forras_gep, cel, current_user)
    naploz(db, current_user, None, "DOKUMENTUM MEGOSZTÁS", regi="-",
           uj=f"{forras.file_type}: {_kozos_fajlnev(forras)} megosztva {len(alkalmazhato)} géppel: " + ", ".join(f"#{g.id}" for g in alkalmazhato),
           machine_id=forras_gep.id)
    if not _kozos_commit(db, regi, masolat):
        return JSONResponse(status_code=500, content={"message": "Hiba történt a mentés közben, semmi nem változott!"})
    return JSONResponse(status_code=200, content={"alkalmazva": len(alkalmazhato), "kihagyva": kihagyva})


@router.get("/uploads/{company_id:int}/kozos/{filename}")
def kozos_fajl_kiszolgalo(
    company_id: int,
    filename: str,
    db: Session = Depends(get_db),
    current_user: models.User = Depends(get_current_user)
):
    """A közös mappában lévő (megosztott) dokumentum kiszolgálása. A gép-alapú ellenőrzés (secure_file_server) ide nem alkalmazható, mert a fájl nem egy gép
    mappájában van: elérhető, ha a felhasználó LEGALÁBB EGY olyan gépet láthat (is_machine_allowed), amelynek van ilyen útvonalú File-sora."""
    utvonal = f"{kozos_prefix(company_id)}{sanitize_filename(filename)}"
    sorok = db.query(models.File).join(models.Machine, models.File.machine_id == models.Machine.id).filter(
        models.File.file_path == utvonal, models.Machine.company_id == company_id
    ).all()
    if not any(is_machine_allowed(s.machine, current_user) for s in sorok):
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Nincs jogosultságod a kért dokumentum eléréséhez!")
    if not os.path.isfile(utvonal.lstrip("/")):
        raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="A keresett fájl nem található a szerveren.")
    return FileResponse(utvonal.lstrip("/"))


@router.get("/gep-fajlok/{machine_id}")
def gep_fajlok(
    request: Request,
    machine_id: int,
    db: Session = Depends(get_db),
    current_user: models.User = Depends(get_current_user)
):
    working_company_id = get_working_company_id(current_user, request)
    gep = db.query(models.Machine).filter(
        models.Machine.id == machine_id,
        models.Machine.company_id == working_company_id
    ).first()

    if not gep or not is_machine_allowed(gep, current_user):
        return []

    # v78: legújabb feltöltés elöl; a "nap" a feltöltés HELYI (Europe/Budapest) napja - a felület ez szerint csoportosítja a fájlokat
    # (az egy napon feltöltött fotók együtt látszanak, így az állapot időbeli változása követhető).
    files = db.query(models.File).filter(models.File.machine_id == machine_id).order_by(
        models.File.uploaded_at.desc(), models.File.id.desc()
    ).all()

    eredmeny = []
    for f in files:
        if current_user.role == "Felhasználó":
            if f.file_type not in FELHASZNALO_LATHATO_FAJLTIPUSOK:
                continue

        eredmeny.append({
            "id": f.id,
            "file_path": f.file_path,
            "file_type": f.file_type,
            "uploaded_at": helyi_ido(f.uploaded_at),
            "nap": helyi_ido(f.uploaded_at, "%Y-%m-%d")
        })
    return eredmeny


@router.post("/upload-file")
def upload_file(
    request: Request,
    background_tasks: BackgroundTasks,
    machine_id: int = Form(...),
    file_type: str = Form(...),
    update_date: str = Form(default="false"),
    minosites: str = Form(default=""),
    megjegyzes: str = Form(default=""),
    file: UploadFile = File(...),
    db: Session = Depends(get_db),
    current_user: models.User = Depends(get_current_user)
):
    # >>> ÚJ BIZTONSÁGI ELLENŐRZÉS <<<
    if not is_safe_extension(file.filename):
        return JSONResponse(
            status_code=400,
            content={"message": "Biztonsági hiba: Nem engedélyezett fájlformátum! Csak kép, PDF, DOCX és XLSX tölthető fel."}
        )

    working_company_id = get_working_company_id(current_user, request)

    if not is_company_active(working_company_id, db):
        return JSONResponse(
            status_code=403,
            content={"message": "Ez a cég inaktív státuszú, dokumentum nem tölthető fel!"}
        )

    if current_user.csak_olvasas:
        return JSONResponse(
            status_code=403,
            content={"message": "Csak megtekintési jogosultsággal rendelkezel, szerkesztés nem lehetséges!"}
        )

    if current_user.role in ["Felhasználó", "Emelőgép ügyintéző"]:
        if not getattr(current_user, 'jog_dokumentum_feltoltes', False):
            return JSONResponse(
                status_code=403,
                content={"message": "Nincs jogosultságod dokumentum feltöltésére!"}
            )

    gep = db.query(models.Machine).filter(
        models.Machine.id == machine_id,
        models.Machine.company_id == working_company_id
    ).first()

    if not gep or not is_machine_allowed(gep, current_user):
        return JSONResponse(
            status_code=403,
            content={"message": "Hiba történt vagy nincs jogosultságod!"}
        )

    # J-03: a dokumentumtípus és a dátum-/minősítés-módosítás szerver-oldali szabályai (a felület korlátai csak kliens-oldaliak).
    file_type = (file_type or "").strip()
    hiba = _fajltipus_hiba(current_user, file_type)
    if hiba:
        return JSONResponse(status_code=403 if "szerepköröd" in hiba else 400, content={"message": hiba})

    # v78: az adattábla-fénykép csak kép lehet (a többi típusnál a meglévő szabály marad: kép esetén tömörítés, egyébként tartalom-ellenőrzés)
    if file_type == ADATTABLA_FAJLTIPUS and not kep_e(file.filename):
        return JSONResponse(status_code=400, content={"message": "Az adattábla-fénykép csak kép (jpg, png, gif) lehet!"})

    datum_kerve = (update_date == "true" and file_type in DATUMOS_FAJLTIPUSOK)
    minosites_hatasos = (bool(minosites) and minosites in VIZSGALATI_MINOSITES_KIVONO_ERTEKEK)
    if minosites_hatasos and file_type not in VIZSGALATI_JKV_FAJLTIPUSOK:
        return JSONResponse(status_code=400, content={"message": "Minősítés csak vizsgálati jegyzőkönyv feltöltésekor adható meg!"})
    if datum_kerve or minosites_hatasos:
        szigor_ki = db.query(models.Dictionary).filter(
            models.Dictionary.company_id == working_company_id,
            models.Dictionary.kategoria == "RendeletSzigoritasKikapcsolva",
            models.Dictionary.ertek == "True"
        ).first() is not None
        hiba = _datum_minosites_hiba(gep, current_user, file_type, szigor_ki)
        if hiba:
            return JSONResponse(status_code=403, content={"message": hiba})

    mappa_vege = f"uploads/{working_company_id}/{machine_id}"
    os.makedirs(mappa_vege, exist_ok=True)

    safe_filename = sanitize_filename(file.filename)

    if kep_e(file.filename):
        kep_bytes = tomorit_kepet(file.file.read())
        if kep_bytes is None:
            return JSONResponse(status_code=400, content={"message": "A feltöltött fájl nem érvényes kép!"})
        safe_filename = safe_filename.rsplit(".", 1)[0] + ".jpg"
        file_location = _fajl_mentese_egyedi_nevvel(mappa_vege, safe_filename, lambda fo: fo.write(kep_bytes))
    else:
        fejresz = file.file.read(8)
        file.file.seek(0)
        if not tartalom_illeszkedik_e_kiterjesztesre(file.filename, fejresz):
            return JSONResponse(status_code=400, content={"message": "A feltöltött fájl tartalma nem egyezik a kiterjesztésével!"})
        file_location = _fajl_mentese_egyedi_nevvel(mappa_vege, safe_filename, lambda fo: shutil.copyfileobj(file.file, fo))

    uj_fajl = models.File(
        machine_id=machine_id,
        file_path="/" + file_location,
        file_type=file_type,
        megjegyzes=megjegyzes.strip() if megjegyzes and megjegyzes.strip() else None
    )
    db.add(uj_fajl)

    log_uzenet = f"Feltöltött dokumentum: {file_type}"
    mai_nap = date.today()

    if datum_kerve:
        if file_type == "Szerkezeti vizsgálat jkv":
            gep.szerkezeti_vizsgalat_datum = mai_nap
            gep.szerkezeti_vizsgalat_uzemora = gep.uzemora
            log_uzenet += " -> Szerkezeti vizsgálati dátum frissítve."
        elif file_type == "Fővizsgálat jkv":
            gep.fovizsgalat_datum = mai_nap
            gep.fovizsgalat_uzemora = gep.uzemora
            log_uzenet += " -> Fővizsgálati dátum frissítve."
        elif file_type == "Időszakos biztonsági felülvizsgálat jkv":
            gep.biztonsagi_vizsgalat_datum = mai_nap
            log_uzenet += " -> Biztonsági felülvizsgálati dátum frissítve."
        elif file_type == "Rendkívüli vizsgálat jkv":
            gep.biztonsagi_vizsgalat_datum = mai_nap
            if hasattr(gep, 'kornyezet_megvaltozott'):
                gep.kornyezet_megvaltozott = False
            log_uzenet += " -> Rendkívüli vizsgálati dátum frissítve."
        elif file_type == "Üzembehelyezési jkv / Ismételt üzembehelyezés":
            gep.uzembe_helyezes_datum = mai_nap
            if hasattr(gep, 'kornyezet_megvaltozott'):
                gep.kornyezet_megvaltozott = False
            log_uzenet += " -> Üzembe helyezési dátum frissítve."

    log = models.AuditLog(
        machine_id=machine_id,
        user_id=current_user.id,
        field_name="DOKUMENTUM FELTÖLTÉS",
        old_value="-",
        new_value=log_uzenet
    )
    db.add(log)

    # ÚJ: ha a feltöltött vizsgálati dokumentumhoz "Korlátozással alkalmas" vagy "Nem alkalmas"
    # minősítést adott meg a feltöltő, a gép automatikusan a "Kivonva (vizsgán nem megfelelés
    # miatt)" státuszba kerül, hibajegy nyílik rá, és a cég beállítása szerint e-mail is kimegy.
    if minosites_hatasos:
        kezeli_sikertelen_vizsgalati_minositest(
            gep, minosites, f"Feltöltött dokumentum ({file_type})", current_user, db, background_tasks
        )

    db.commit()
    valasz = {"message": "Sikeres feltöltés és naplózás!"}
    if file_type in KOZOS_FAJLTIPUSOK:
        # v80: a megosztható típusnál felajánljuk a többi azonos gyártójú+típusú gépre való alkalmazást (a felület kérdez, majd /kozos-dokumentum-alkalmaz)
        ajanlat = _kozos_ajanlat(db, gep, uj_fajl, current_user)
        if ajanlat:
            valasz["kozos"] = ajanlat
    return JSONResponse(status_code=200, content=valasz)


@router.delete("/torol-fajl/{file_id}")
def torol_fajl(
    request: Request,
    file_id: int,
    db: Session = Depends(get_db),
    current_user: models.User = Depends(get_current_user)
):
    working_company_id = get_working_company_id(current_user, request)

    if current_user.role not in ["Admin", "Emelőgép ügyintéző"]:
        return JSONResponse(
            status_code=403,
            content={"message": "Nincs jogod dokumentum törlésére!"}
        )

    if not is_company_active(working_company_id, db):
        return JSONResponse(
            status_code=403,
            content={"message": "Ez a cég inaktív státuszú, dokumentum nem törölhető!"}
        )

    if current_user.csak_olvasas:
        return JSONResponse(
            status_code=403,
            content={"message": "Csak megtekintési jogosultsággal rendelkezel, szerkesztés nem lehetséges!"}
        )

    fajl = db.query(models.File).filter(models.File.id == file_id).first()

    if fajl and fajl.machine.company_id == working_company_id:
        # v80: a KÖZÖS mappában lévő (megosztott) dokumentumnál csak az adott gép hivatkozása törlődik; a fizikai fájl csak az utolsó hivatkozással együtt
        kozos_utvonal = fajl.file_path if kozos_utvonal_e(fajl.file_path, working_company_id) else None
        if not kozos_utvonal:
            try:
                os.remove(fajl.file_path.lstrip('/'))
            except Exception:
                pass

        # J-17: a törlés eddig nyomtalan volt (hivatalos jegyzőkönyvet is törölhetett) - most bekerül a gép naplójába.
        db.add(models.AuditLog(
            machine_id=fajl.machine_id,
            user_id=current_user.id,
            field_name="DOKUMENTUM TÖRLÉS",
            old_value=f"{fajl.file_type}: {os.path.basename(fajl.file_path or '')}" + (" (hivatkozás)" if kozos_utvonal else ""),
            new_value="-"
        ))
        db.delete(fajl)
        db.commit()
        if kozos_utvonal:
            arva_kozos_torlese(db, [kozos_utvonal])
        return JSONResponse(status_code=200, content={"message": "Törölve!"})

    return JSONResponse(status_code=404, content={"message": "Hiba történt."})


@router.get("/uploads/{company_id:int}/{machine_id:int}/{filename}")
def secure_file_server(
    company_id: int,
    machine_id: int,
    filename: str,
    db: Session = Depends(get_db),
    current_user: models.User = Depends(get_current_user)
):
    gep = db.query(models.Machine).filter(
        models.Machine.id == machine_id,
        models.Machine.company_id == company_id
    ).first()

    if not gep or not is_machine_allowed(gep, current_user):
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="Nincs jogosultságod a kért dokumentum eléréséhez!"
        )

    safe_filename = sanitize_filename(filename)
    file_path = f"uploads/{company_id}/{machine_id}/{safe_filename}"

    if not os.path.exists(file_path):
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="A keresett fájl nem található a szerveren."
        )

    return FileResponse(file_path)


def _datum_szuro_hatarok(tol: str, ig: str):
    """Opcionális dátum-intervallum feldolgozása a napló-szűrőkhöz (évek múltán egyre nagyobb
    naplókban a keresést segítendő). Hibás vagy üres bemenetnél None-t ad - az adott irányban
    ilyenkor nincs korlátozás."""
    tol_datum = None
    ig_datum = None
    if tol:
        try:
            tol_datum = datetime.strptime(tol, "%Y-%m-%d").date()
        except ValueError:
            pass
    if ig:
        try:
            ig_datum = datetime.strptime(ig, "%Y-%m-%d").date()
        except ValueError:
            pass
    return tol_datum, ig_datum


@router.get("/gep-naplo/{machine_id}")
def gep_naplo(
    request: Request,
    machine_id: int,
    tol: str = "",
    ig: str = "",
    db: Session = Depends(get_db),
    current_user: models.User = Depends(get_current_user)
):
    working_company_id = get_working_company_id(current_user, request)
    gep = db.query(models.Machine).filter(
        models.Machine.id == machine_id,
        models.Machine.company_id == working_company_id
    ).first()

    if not gep or not is_machine_allowed(gep, current_user):
        return []

    tol_datum, ig_datum = _datum_szuro_hatarok(tol, ig)

    query = db.query(models.AuditLog).options(joinedload(models.AuditLog.user)).filter(models.AuditLog.machine_id == machine_id)
    if tol_datum:
        query = query.filter(models.AuditLog.timestamp >= helyi_nap_utc_hatarai(tol_datum)[0])
    if ig_datum:
        query = query.filter(models.AuditLog.timestamp <= helyi_nap_utc_hatarai(ig_datum)[1])

    logs = query.order_by(models.AuditLog.timestamp.desc()).all()

    eredmeny = []
    for log in logs:
        user_nev = "Rendszer"
        if log.user:
            user_nev = log.user.username

        eredmeny.append({
            "field_name": log.field_name,
            "old_value": log.old_value,
            "new_value": log.new_value,
            "timestamp": helyi_ido(log.timestamp),
            "user": user_nev
        })

    return eredmeny


@router.get("/gep-vizsgalatok/{machine_id}")
def gep_vizsgalatok(
    request: Request,
    machine_id: int,
    tol: str = "",
    ig: str = "",
    db: Session = Depends(get_db),
    current_user: models.User = Depends(get_current_user)
):
    working_company_id = get_working_company_id(current_user, request)
    gep = db.query(models.Machine).filter(
        models.Machine.id == machine_id,
        models.Machine.company_id == working_company_id
    ).first()

    if not gep or not is_machine_allowed(gep, current_user):
        return []

    tol_datum, ig_datum = _datum_szuro_hatarok(tol, ig)

    query = db.query(models.Inspection).options(joinedload(models.Inspection.user)).filter(models.Inspection.machine_id == machine_id)
    if tol_datum:
        query = query.filter(models.Inspection.datum >= tol_datum)
    if ig_datum:
        query = query.filter(models.Inspection.datum <= ig_datum)

    vizsgalatok = query.order_by(models.Inspection.datum.desc()).all()

    eredmeny = []
    for v in vizsgalatok:
        user_nev = "Ismeretlen"
        if v.user:
            user_nev = v.user.username

        megjegyzes_szov = ""
        if v.megjegyzes:
            megjegyzes_szov = v.megjegyzes

        eredmeny.append({
            "tipus": v.vizsgalat_tipusa,
            "datum": v.datum.strftime("%Y-%m-%d"),
            "eredmeny": v.eredmeny,
            "megjegyzes": megjegyzes_szov,
            "user": user_nev
        })

    return eredmeny


def build_gep_teljes_naplo(gep, db: Session):
    """
    Egyesített, időrendbe rendezett idővonal: hivatalos vizsgálatok, napi ellenőrzések /
    adminisztrációs módosítások (AuditLog) és hibajegyek/javítások (MaintenanceTicket)
    egyetlen listában.

    Az opcionális "idopont_szoveg" felülírja a megjelenítést (vizsgálatoknál: csak dátum,
    ill. dátum + "kiállítva:" megjegyzés), a rendezés/szűrés ilyenkor is az "idopont"-on megy.

    Az "idopont" mindenhol HELYI (Europe/Budapest) naiv datetime: az UTC-ben tárolt
    időbélyegeket (AuditLog, MaintenanceTicket) itt váltjuk át, a vizsgálatok helyi
    naptári dátuma (Inspection.datum) pedig eleve helyi - így a rendezés, a tól-ig
    szűrés és a megjelenítés egységesen helyi időben történik.
    """
    esemenyek = []

    vizsgalatok = db.query(models.Inspection).options(joinedload(models.Inspection.user)).filter(
        models.Inspection.machine_id == gep.id
    ).all()
    for v in vizsgalatok:
        # A vizsgálat a jegyzőkönyvön szereplő NAPJA (v.datum) szerint kerül a helyére.
        # Időpontot csak akkor mutatunk, ha ismert a rögzítés valódi ideje (letrehozva):
        # ha ugyanarra a napra esik, az a sor időpontja; ha a jegyzőkönyv visszadátumozott
        # (később állították ki), a dátum mellé külön "kiállítva:" megjegyzés kerül. Ha nem
        # ismert (régi, PDF nélküli sor), csak a dátum jelenik meg - nem egy hamis 00:00.
        rogzitve = helyi_datetime(getattr(v, "letrehozva", None))
        if rogzitve and rogzitve.date() == v.datum:
            idopont, idopont_szoveg = rogzitve, None
        else:
            idopont = datetime.combine(v.datum, datetime.min.time())
            idopont_szoveg = v.datum.strftime("%Y-%m-%d")
            if rogzitve:
                idopont_szoveg += f" (kiállítva: {rogzitve.strftime('%Y-%m-%d %H:%M')})"
        esemenyek.append({
            "idopont": idopont,
            "idopont_szoveg": idopont_szoveg,
            "tipus": "Vizsgálat",
            "cim": v.vizsgalat_tipusa,
            "reszletek": v.eredmeny + (f" — {v.megjegyzes}" if v.megjegyzes else ""),
            "user": v.user.username if v.user else "Ismeretlen",
            "dokumentum": v.jegyzokonyv_pdf_path
        })

    # ÚJ (2026-10-10-i user-kérés): a kézzel (vagy megosztott dokumentumként hivatkozva, l.
    # docs/KOZOS_DOKUMENTUM.md) feltöltött fájlok eddig EGYÁLTALÁN nem jelentek meg ezen az
    # idővonalon - csak a programmal generált jegyzőkönyvek (Inspection-forrás) és a
    # hibajegyekhez tartozó fotó/munkalap (MaintenanceTicket-forrás) látszott. A három, MÁR
    # máshonnan (Inspection / MaintenanceTicket forrásból) megjelenő file_type-ot itt
    # szándékosan kihagyjuk, nehogy duplán szerepeljen ugyanaz a dokumentum.
    MAR_MASHONNAN_MEGJELENO_FAJLTIPUSOK = ("Vizsgálati jegyzőkönyv", "Napi ellenőrzés fotó", "Javítási munkalap")
    feltoltott_fajlok = db.query(models.File).filter(
        models.File.machine_id == gep.id,
        models.File.file_type.notin_(MAR_MASHONNAN_MEGJELENO_FAJLTIPUSOK)
    ).all()
    for f in feltoltott_fajlok:
        esemenyek.append({
            "idopont": helyi_datetime(f.uploaded_at),
            "tipus": "Dokumentum",
            "cim": f.file_type or "Egyéb dokumentum",
            "reszletek": f.megjegyzes or "-",
            "user": "-",       # a File tábla nem tárolja a feltöltő felhasználót
            "dokumentum": f.file_path
        })

    naplo_bejegyzesek = db.query(models.AuditLog).options(joinedload(models.AuditLog.user)).filter(
        models.AuditLog.machine_id == gep.id
    ).all()
    for log in naplo_bejegyzesek:
        esemenyek.append({
            "idopont": helyi_datetime(log.timestamp),
            "tipus": "Napló",
            "cim": log.field_name,
            "reszletek": f"{log.old_value} → {log.new_value}" if log.old_value and log.old_value != "-" else log.new_value,
            "user": log.user.username if log.user else "Rendszer",
            "dokumentum": None
        })

    hibajegyek = db.query(models.MaintenanceTicket).filter(models.MaintenanceTicket.machine_id == gep.id).all()
    for t in hibajegyek:
        esemenyek.append({
            "idopont": helyi_datetime(t.nyitas_datum),
            "tipus": "Hibajegy",
            "cim": f"Hibajegy nyitva ({t.sulyossag})",
            "reszletek": t.hiba_leirasa or "-",
            "user": t.bejelento_nev or "Ismeretlen",
            "dokumentum": t.fenykep_path
        })
        if t.statusz == "Lezárva" and t.lezaras_datum:
            esemenyek.append({
                "idopont": helyi_datetime(t.lezaras_datum),
                "tipus": "Hibajegy",
                "cim": "Hibajegy lezárva / Karbantartás",
                "reszletek": t.javitas_indoklas or "-",
                "dokumentum": t.munkalap_path,
                "user": t.lezaro_user or "Ismeretlen"
            })

    esemenyek.sort(key=lambda e: e["idopont"], reverse=True)
    return esemenyek


@router.get("/gep-teljes-naplo/{machine_id}")
def gep_teljes_naplo(
    request: Request,
    machine_id: int,
    tol: str = "",
    ig: str = "",
    db: Session = Depends(get_db),
    current_user: models.User = Depends(get_current_user)
):
    working_company_id = get_working_company_id(current_user, request)
    gep = db.query(models.Machine).filter(
        models.Machine.id == machine_id,
        models.Machine.company_id == working_company_id
    ).first()

    if not gep or not is_machine_allowed(gep, current_user):
        return []

    tol_datum, ig_datum = _datum_szuro_hatarok(tol, ig)

    esemenyek = build_gep_teljes_naplo(gep, db)
    if tol_datum:
        esemenyek = [e for e in esemenyek if e["idopont"].date() >= tol_datum]
    if ig_datum:
        esemenyek = [e for e in esemenyek if e["idopont"].date() <= ig_datum]

    return [
        {
            "idopont": e.get("idopont_szoveg") or e["idopont"].strftime("%Y-%m-%d %H:%M"),
            "tipus": e["tipus"],
            "cim": e["cim"],
            "reszletek": e["reszletek"],
            "user": e["user"],
            "dokumentum": e["dokumentum"]
        }
        for e in esemenyek
    ]


@router.get("/gep-teljes-naplo-nyomtatas/{machine_id}", response_class=HTMLResponse)
def gep_teljes_naplo_nyomtatas(
    request: Request,
    machine_id: int,
    mod: str = "egyszeru",
    nev: str = "false",
    tol: str = "",
    ig: str = "",
    db: Session = Depends(get_db),
    current_user: models.User = Depends(get_current_user)
):
    working_company_id = get_working_company_id(current_user, request)
    gep = db.query(models.Machine).filter(
        models.Machine.id == machine_id,
        models.Machine.company_id == working_company_id
    ).first()

    if not gep or not is_machine_allowed(gep, current_user):
        return HTMLResponse("<h1 style='text-align:center; margin-top:50px;'>Nincs jogosultságod vagy a gép nem található!</h1>", status_code=404)

    bovitett = (mod == "bovitett")
    nev_lathato = (nev == "true")

    tol_datum, ig_datum = _datum_szuro_hatarok(tol, ig)

    esemenyek = build_gep_teljes_naplo(gep, db)
    if tol_datum:
        esemenyek = [e for e in esemenyek if e["idopont"].date() >= tol_datum]
    if ig_datum:
        esemenyek = [e for e in esemenyek if e["idopont"].date() <= ig_datum]

    # Egyszerű nézetnél csak a napi óraállás-változást tartalmazó bejegyzésekhez rendelünk üzemóra oszlopot
    sorok = []
    for e in esemenyek:
        uzemora_szov = "-"
        if e["tipus"] == "Napló" and "h |" in (e["reszletek"] or ""):
            uzemora_szov = e["reszletek"].split("h |")[0].split(":")[-1].strip() + " h"
        sorok.append({
            "idopont": e.get("idopont_szoveg") or e["idopont"].strftime("%Y-%m-%d %H:%M"),
            "tipus": e["tipus"],
            "cim": e["cim"],
            "reszletek": e["reszletek"],
            "user": e["user"] if nev_lathato else "-",
            "uzemora": uzemora_szov
        })

    return templates.TemplateResponse(
        request=request,
        name="naplo-nyomtatas.html",
        context={
            "gep": gep,
            "sorok": sorok,
            "bovitett": bovitett,
            "nev_lathato": nev_lathato,
            "nyomtatva": date.today().strftime("%Y-%m-%d"),
            "szuro_tol": tol_datum.strftime("%Y-%m-%d") if tol_datum else None,
            "szuro_ig": ig_datum.strftime("%Y-%m-%d") if ig_datum else None
        }
    )
