from sqlalchemy.dialects.mysql import MEDIUMTEXT
from sqlalchemy import Column, Integer, String, Float, Boolean, Date, DateTime, ForeignKey, Table, Text, UniqueConstraint, Index
from sqlalchemy.orm import relationship
from datetime import datetime, timezone
import uuid
from database import Base

# --- KAPCSOLÓTÁBLÁK A JOGOSULTSÁGI HIERARCHIÁHOZ (ÚJ) ---

# 1. Külsős szakértők (Vizsgálók, Ügyintézők) összekötése több céggel
user_companies = Table(
    'user_companies', Base.metadata,
    Column('user_id', Integer, ForeignKey('users.id', ondelete="CASCADE"), primary_key=True),
    Column('company_id', Integer, ForeignKey('companies.id', ondelete="CASCADE"), primary_key=True)
)

# 2. Felhasználók összekötése dedikált telephelyekkel
user_sites = Table(
    'user_sites', Base.metadata,
    Column('user_id', Integer, ForeignKey('users.id', ondelete="CASCADE"), primary_key=True),
    Column('site_id', Integer, ForeignKey('sites.id', ondelete="CASCADE"), primary_key=True)
)

# 3. Felhasználók összekötése dedikált egyedi gépekkel
user_machines = Table(
    'user_machines', Base.metadata,
    Column('user_id', Integer, ForeignKey('users.id', ondelete="CASCADE"), primary_key=True),
    Column('machine_id', Integer, ForeignKey('machines.id', ondelete="CASCADE"), primary_key=True)
)

# 4. Cégek modul-előfizetése (melyik modulhoz fér hozzá egyáltalán a cég - a
# rendszeradminisztrátor állítja be, csak ő láthatja/szerkesztheti)
company_modulok = Table(
    'company_modulok', Base.metadata,
    Column('company_id', Integer, ForeignKey('companies.id', ondelete="CASCADE"), primary_key=True),
    Column('modul_id', Integer, ForeignKey('modulok.id', ondelete="CASCADE"), primary_key=True)
)

# 5. Felhasználók modul-hozzárendelése (a cég által engedélyezett modulokon belül,
# melyikhez fér hozzá KONKRÉTAN az adott felhasználó)
user_modulok = Table(
    'user_modulok', Base.metadata,
    Column('user_id', Integer, ForeignKey('users.id', ondelete="CASCADE"), primary_key=True),
    Column('modul_id', Integer, ForeignKey('modulok.id', ondelete="CASCADE"), primary_key=True)
)

# 6. EBK projekt - mely (céges katalógusból választott) területek tartoznak az adott
# kivitelezési munkahelyhez
ebk_projekt_teruletek = Table(
    'ebk_projekt_teruletek', Base.metadata,
    Column('projekt_id', Integer, ForeignKey('ebk_projektek.id', ondelete="CASCADE"), primary_key=True),
    Column('terulet_id', Integer, ForeignKey('ebk_teruletek.id', ondelete="CASCADE"), primary_key=True)
)

# 7. Egy projekt-alvállalkozó párosításhoz mely (céges katalógusból választott)
# tevékenységek tartoznak
ebk_projekt_alvallalkozo_tevekenysegek = Table(
    'ebk_projekt_alvallalkozo_tevekenysegek', Base.metadata,
    Column('projekt_alvallalkozo_id', Integer, ForeignKey('ebk_projekt_alvallalkozok.id', ondelete="CASCADE"), primary_key=True),
    Column('tevekenyseg_id', Integer, ForeignKey('ebk_tevekenysegek.id', ondelete="CASCADE"), primary_key=True)
)

# 8. Megtekintő szerepkörű felhasználók korlátozott hozzáférése - csak a hozzájuk rendelt
# projekt(ek) riportjait láthatják
user_ebk_projektek = Table(
    'user_ebk_projektek', Base.metadata,
    Column('user_id', Integer, ForeignKey('users.id', ondelete="CASCADE"), primary_key=True),
    Column('projekt_id', Integer, ForeignKey('ebk_projektek.id', ondelete="CASCADE"), primary_key=True)
)

# 9. EBK szerepkörű koordinátor felhasználók hozzárendelése - csak a hozzájuk rendelt
# projekte(ke)n végezhetnek helyszíni ellenőrzést, semmilyen beállítást nem érhetnek el.
ebk_projekt_koordinatorok = Table(
    'ebk_projekt_koordinatorok', Base.metadata,
    Column('user_id', Integer, ForeignKey('users.id', ondelete="CASCADE"), primary_key=True),
    Column('projekt_id', Integer, ForeignKey('ebk_projektek.id', ondelete="CASCADE"), primary_key=True)
)

# 10. Megtekintő szerepkörű felhasználók korlátozott hozzáférése a VIVÜ Megrendelőkhöz - csak a
# hozzájuk rendelt Megrendelő(k) telephelyeit/ellenőrzéseit láthatják (ugyanaz a minta, mint
# user_ebk_projektek, csak itt nincs köztes "Projekt" entitás - a Megrendelő maga a legfelső,
# önálló egység, alatta közvetlenül a telephelyek).
user_vivu_ugyfelek = Table(
    'user_vivu_ugyfelek', Base.metadata,
    Column('user_id', Integer, ForeignKey('users.id', ondelete="CASCADE"), primary_key=True),
    Column('ugyfel_id', Integer, ForeignKey('vivu_ugyfelek.id', ondelete="CASCADE"), primary_key=True)
)

# 11. Egy VIVÜ bejárás/dokumentáció-felülvizsgálat összesítve mely épülete(ke)t érintette -
# a "minden rendben" tételekhez tartozó, informális összegzés; a konkrét szabálytalanságok
# saját, egyedi épület+szint párost kapnak (VivuEllenorzesTetel.epulet_id/szint_id), FÜGGETLENÜL
# ettől az összegző listától.
vivu_ellenorzes_epuletek = Table(
    'vivu_ellenorzes_epuletek', Base.metadata,
    Column('ellenorzes_id', Integer, ForeignKey('vivu_ellenorzesek.id', ondelete="CASCADE"), primary_key=True),
    Column('epulet_id', Integer, ForeignKey('vivu_epuletek.id', ondelete="CASCADE"), primary_key=True)
)

# --- ADATBÁZIS TÁBLÁK ---


class Modul(Base):
    """Bővíthető modul-törzsadat (jelenleg Emelőgép és Tűzvédelem) - a rendszeradminisztrátor
    (Admin szerepkör, company_id==1) itt is bővítheti a listát később, kód nélkül."""
    __tablename__ = "modulok"
    id = Column(Integer, primary_key=True, index=True)
    kod = Column(String(50), unique=True, index=True)
    nev = Column(String(100))
    ikon = Column(String(50), nullable=True)
    aktiv = Column(Boolean, default=True)

class Company(Base):
    __tablename__ = "companies"
    id = Column(Integer, primary_key=True, index=True)
    nev = Column(String(255), index=True)
    adoszam = Column(String(50), nullable=True)
    aktiv = Column(Boolean, default=True)
    cim = Column(String(500), nullable=True)
    elerhetoseg = Column(String(255), nullable=True)

    # Licenc-limitek: NULL = korlátlan. Csak ÚJ felvitelt blokkolnak - visszaminősítéskor a
    # meglévő, limit fölötti gépek/felhasználók nem törlődnek, csak jelzésre kerülnek.
    licenc_max_gep = Column(Integer, nullable=True)
    licenc_max_dolgozo = Column(Integer, nullable=True)
    licenc_max_ugyintezo = Column(Integer, nullable=True)

    # KÉTLÉPCSŐS HITELESÍTÉS (2026-10-04, 2FA 1. fázis - docs/KETLEPCSOS_HITELESITES.md):
    # True = a cég MINDEN felhasználójának kötelező a TOTP (hitelesítő alkalmazás). A kapcsolót
    # KIZÁRÓLAG a rendszeradmin állíthatja (a rendszeradmin felület: /rendszeradmin/ketlepcsos, 4. fázis, v19).
    # NULL/False = nem kötelező. Az `mfa_politika_valtozott_at` a kapcsoló utolsó átbillentésének
    # ideje (naplózáshoz / későbbi "türelmi idő" funkcióhoz).
    ketlepcsos_hitelesites_kotelezo = Column(Boolean, default=False, nullable=True)
    mfa_politika_valtozott_at = Column(DateTime, nullable=True)
    # KARBANTARTÁS (2026-10-03-i biztonsági audit, 4. fázis): a korábbi
    # licenc_max_szuperfelhasznalo mező holt kód volt - sem a rendszeradmin felületen
    # (templates/rendszeradmin_cegek.html), sem a mentő végponton (routers/rendszeradmin.py),
    # sem a licenc-ellenőrzésben (licenc_utils.py, amely szándékosan csak a Felhasználó/EÜI
    # szerepkört licenceli - Admin/Emelőgép szakértő/Emelőgép vizsgáló fiókokat a
    # rendszeradmin hozza létre, licenc nélkül) nem volt sehol beállítva vagy kiolvasva.
    # A mezőt eltávolítottuk a modellből - a DB-ben esetlegesen megmaradt (mindig NULL) oszlop
    # ártalmatlan, nem töröltük a táblából (a projekt migrációs szkriptjei csak oszlopot
    # adnak hozzá, sosem távolítanak el).

    # ÚJ: bérbeadás/kihelyezés engedélyezése - nem minden cég ad bérbe gépet, ezért ez
    # egy rendszeradmin által cégenként bekapcsolható jog, alapból KIKAPCSOLVA.
    berbeadhat = Column(Boolean, default=False)

    # JELSZÓ-HÁZIREND (v36 - docs/JELSZO_HAZIREND.md): a cég Admin-ja állítja (/jelszo-hazirend); MINDEN opcionális, NULL/False = nincs érvényben
    # (a régi működés: legalább 6 karakter). Értelmezni kizárólag a jelszo_hazirend.py-on keresztül.
    #   jelszo_ervenyesseg_nap  - kötelező jelszócsere: ennyi naponként (30-180); NULL = nincs kötelező csere
    #   jelszo_min_hossz        - minimum hossz (6-32); NULL = 6
    #   jelszo_kell_*           - kötelező karakterfajták (kisbetű, nagybetű, szám, speciális)
    #   jelszo_elozmeny_db      - a legutóbbi ennyi jelszó (a jelenlegit is beleértve) nem használható újra; NULL/0 = ki
    #   jelszo_hazirend_valtozott_at - a szabályok utolsó módosítása (UTC, tz nélkül)
    jelszo_ervenyesseg_nap = Column(Integer, nullable=True)
    jelszo_min_hossz = Column(Integer, nullable=True)
    jelszo_kell_kisbetu = Column(Boolean, default=False, nullable=True)
    jelszo_kell_nagybetu = Column(Boolean, default=False, nullable=True)
    jelszo_kell_szam = Column(Boolean, default=False, nullable=True)
    jelszo_kell_specialis = Column(Boolean, default=False, nullable=True)
    jelszo_elozmeny_db = Column(Integer, nullable=True)
    jelszo_hazirend_valtozott_at = Column(DateTime, nullable=True)

    users = relationship("User", back_populates="ceg", foreign_keys="User.company_id")
    sites = relationship("Site", back_populates="ceg")
    machines = relationship("Machine", back_populates="ceg")
    dictionaries = relationship("Dictionary", back_populates="ceg")
    configs = relationship("MachineTypeConfig", back_populates="ceg")
    engedelyezett_modulok = relationship("Modul", secondary=company_modulok, backref="cegek")

class Site(Base):
    __tablename__ = "sites"
    id = Column(Integer, primary_key=True, index=True)
    company_id = Column(Integer, ForeignKey("companies.id"))
    nev = Column(String(255))
    cim = Column(String(500), nullable=True)

    ceg = relationship("Company", back_populates="sites")
    machines = relationship("Machine", back_populates="telephely")


class SzakertoMegbizatas(Base):
    """Egy Emelőgép szakértő ÖNKÉNT beállított jelzése, hogy egy adott cégnél a megbízatása
    (szerződése) melyik vizsgálat-típus(ok)ra szól - CSAK a szakerto-dashboard tartalmát
    szűri, a tényleges vizsgálat-rögzítést (routers/inspections.py) NEM korlátozza (2026-10-02-i
    user-döntés). Ha egy (user, company) párhoz nincs rekord, az "mindhárom típus" alapértelmezést
    jelenti (nem korlátozott, visszafelé kompatibilis)."""
    __tablename__ = "szakerto_megbizatasok"
    id = Column(Integer, primary_key=True, index=True)
    user_id = Column(Integer, ForeignKey("users.id"))
    company_id = Column(Integer, ForeignKey("companies.id"))
    szerkezeti = Column(Boolean, default=True)
    fovizsgalat = Column(Boolean, default=True)
    ibf = Column(Boolean, default=True)

    user = relationship("User")
    company = relationship("Company")


class TervezettVizsgalat(Base):
    """Egy szakértő saját, személyes munkaterve - egy adott gép adott (esedékes) vizsgálat-
    típusához rögzített tervezett dátum, ami eltérhet a jogszabályi esedékességtől. A cég
    Admin-ja is látja (nem privát adat), de csak a szakerto-dashboard ÜTEMEZŐ nézetéhez
    kapcsolódik - a tényleges vizsgálat rögzítésekor (routers/inspections.py general_jegyzokonyv)
    a megfelelő sor automatikusan törlődik, hiszen a feladat ezzel elkészült."""
    __tablename__ = "tervezett_vizsgalatok"
    id = Column(Integer, primary_key=True, index=True)
    machine_id = Column(Integer, ForeignKey("machines.id"))
    user_id = Column(Integer, ForeignKey("users.id"))
    vizsgalat_tipusa = Column(String(100))
    tervezett_datum = Column(Date)
    megjegyzes = Column(Text, nullable=True)
    letrehozva = Column(DateTime, default=lambda: datetime.now(timezone.utc))

    machine = relationship("Machine")
    user = relationship("User")


class User(Base):
    __tablename__ = "users"
    id = Column(Integer, primary_key=True, index=True)
    company_id = Column(Integer, ForeignKey("companies.id"))
    username = Column(String(255))
    email = Column(String(255), unique=True, index=True)
    hashed_password = Column(String(255))
    role = Column(String(50)) # Admin, Emelőgép ügyintéző, Emelőgép szakértő, Emelőgép vizsgáló, Felhasználó
    aktiv = Column(Boolean, default=True)  # Inaktivált fiók: bejelentkezés azonnal megszűnik

    # Hozzáférés szintje (CEG, TELEPHELY, GEP)
    hozzaferes_szint = Column(String(20), default="CEG")
    telephely_hozzaferes_id = Column(Integer, ForeignKey("sites.id"), nullable=True) # Kompatibilitás miatt megtartva

    # A legutóbb sikeresen kiválasztott Munkakörnyezet (cég) - tartósan, adatbázisban tárolva,
    # hogy bejelentkezés után és más eszközön is automatikusan ezt mutassa a rendszer, ne mindig
    # a felhasználó saját (company_id) cégére essen vissza. Csak a get_working_company_id-ben
    # (security.py) használt cookie-fallback második lépéseként jön szóba.
    utolso_ceg_id = Column(Integer, ForeignKey("companies.id"), nullable=True)

    # Szakértői adatok
    bizonyitvany_szam = Column(String(100), nullable=True)
    kamarai_azonosito = Column(String(100), nullable=True)
    engedely_szam = Column(String(100), nullable=True)
    tanusitvany_szam = Column(String(100), nullable=True) # ÚJ MEZŐ
    bizonyitvany_path = Column(String(500), nullable=True)
    
    # HR / EHS ADATOK (Gépkezelőknek) ---
    orvosi_alkalmassag_ervenyesseg = Column(Date, nullable=True)
    jogositvany_ervenyesseg = Column(Date, nullable=True)
    # -------------------------------------------
    
    # "Felhasználó" szint egyedi rögzítési jogai
    jog_uzemora_rogzites = Column(Boolean, default=False)
    jog_dokumentum_feltoltes = Column(Boolean, default=False)
    jog_gep_szerkesztes = Column(Boolean, default=False)  # Emelőgép szakértőnek/vizsgálónak egyedileg engedélyezett gép-adatlap szerkesztés
    jog_datum_szerkesztes = Column(Boolean, default=False)  # Admin/Emelőgép szakértő/vizsgáló/EÜI közül egyedileg engedélyezett dátum-kézi-szerkesztés meglévő gépeknél
    csak_olvasas = Column(Boolean, default=False)  # Read-only fiók: bármely szerepkörön felüli írás-tiltás (pl. könyvelő/auditor)

    # JWT-visszavonás (2026-10-03-i biztonsági audit, 3. fázis): a legutóbbi jelszóváltás
    # időpontja - a security.py get_current_user() ezt veti össze minden kérésnél a JWT "iat"
    # (kiállítás) mezőjével, hogy egy jelszóváltás előtt kiadott (pl. ellopott) token a
    # jelszóváltással azonnal, a lejáratáig (exp) várás nélkül érvénytelenné váljon. NULL =
    # a felhasználó még sosem váltott jelszót (vagy a migráció előtt létező sor) - ilyenkor
    # nincs mit visszavonni, minden régi token érvényes marad.
    jelszo_valtozott_at = Column(DateTime, nullable=True)

    # EGYIDEJŰ BELÉPÉS TILTÁSA (2026-10-05, v32 - docs/EGYIDEJU_BELEPES.md): egy fiók egyszerre csak EGY helyen lehet bejelentkezve
    # (licenc-védelem: a cég ne adhassa tovább a fiókot szimultán használatra). Minden belépéskor új véletlen munkamenet-azonosítót
    # (sid) generálunk: ez kerül a JWT-be ÉS ide. A security.get_current_user() a kettő egyezését kéri, így az ÚJ belépés a régit
    # azonnal érvénytelenné teszi ("az új belépés dobja ki a régit"). A rendszeradminisztrátorra nem vonatkozik (nincs sid-je).
    #   aktiv_munkamenet      - a jelenleg érvényes munkamenet azonosítója (NULL: nincs érvényes munkamenet / kilépett)
    #   munkamenet_kezdete_at - mikor indult (tz nélküli UTC)
    #   munkamenet_ip         - honnan indult (a napló és a nyomozás számára)
    aktiv_munkamenet = Column(String(64), nullable=True)
    munkamenet_kezdete_at = Column(DateTime, nullable=True)
    munkamenet_ip = Column(String(64), nullable=True)

    # SZABADSÁGON VAGYOK (v35 - docs/PROFIL_ES_SZABADSAG.md): amíg be van kapcsolva, a felhasználó nem kap e-mailt (a fiókot védő biztonsági
    # levelek kivételével); a kimaradt leveleket a szabadság végén EGY összegző levélben kapja meg. Kezelni kizárólag a szabadsag_utils.py-on keresztül.
    #   szabadsagon           - be van-e kapcsolva
    #   szabadsag_kezdete_at  - mikor kapcsolta be (tz nélküli UTC)
    #   szabadsag_visszateres - opcionális VISSZATÉRÉS NAPJA (helyi dátum): ezen a napon (helyi 00:00 után) a szabadság magától véget ér
    szabadsagon = Column(Boolean, default=False, nullable=True)
    szabadsag_kezdete_at = Column(DateTime, nullable=True)
    szabadsag_visszateres = Column(Date, nullable=True)

    # JELSZÓ-HÁZIREND (v36 - docs/JELSZO_HAZIREND.md): a jelszó lejárata (tz nélküli UTC; NULL = nincs lejárat) és az emlékeztető levél jelzője
    # (NULL = az erre a lejáratra még nem küldtünk). Kezelni kizárólag a jelszo_hazirend.py-on keresztül.
    jelszo_lejarat_at = Column(DateTime, nullable=True)
    jelszo_emlekezteto_at = Column(DateTime, nullable=True)

    # AKTIVÁLÁS (2026-10-04, E szelet - docs/AKTIVALAS.md): az új felhasználó aktiváló e-mailt kap, és
    # amíg a linken be nem állítja a jelszavát, nem léphet be (security.get_current_user is elutasítja).
    # False = aktiválásra vár; True vagy NULL = aktivált (a MEGLÉVŐ felhasználók az oszlop
    # hozzáadásakor a DEFAULT 1 miatt aktiváltak lesznek). NEM azonos az `aktiv` oszloppal (az az
    # admin által végzett inaktiválás).
    aktivalva = Column(Boolean, default=True, nullable=True)

    # KÉTLÉPCSŐS HITELESÍTÉS (2026-10-04, 2FA 1. fázis - docs/KETLEPCSOS_HITELESITES.md).
    # TILOS kiírni sablonba / naplóba / exportba! Kezelni kizárólag a mfa_utils.py-on keresztül.
    #   totp_secret          - a TOTP titok TITKOSÍTVA (Fernet, titkosito_utils), sosem nyersen
    #   totp_megerositve     - True: a felhasználó a kódját már egyszer sikeresen beírta (a beállítás kész);
    #                          False/NULL + van titok: a QR kiadva, de a megerősítés még hiányzik
    #   totp_utolso_lepes    - a legutóbb elfogadott 30 mp-es időlépés száma: ugyanaz a kód másodszor nem
    #                          fogadható el (visszajátszás elleni védelem)
    totp_secret = Column(String(255), nullable=True)
    totp_megerositve = Column(Boolean, default=False, nullable=True)
    totp_utolso_lepes = Column(Integer, nullable=True)

    ceg = relationship("Company", back_populates="users", foreign_keys=[company_id])
    
    # Többes kapcsolatok a jogosultságokhoz
    allowed_companies = relationship("Company", secondary=user_companies, backref="allowed_users")
    allowed_sites = relationship("Site", secondary=user_sites, backref="allowed_users")
    allowed_machines = relationship("Machine", secondary=user_machines, backref="allowed_users")
    sajat_modulok = relationship("Modul", secondary=user_modulok, backref="felhasznalok")

class Machine(Base):
    __tablename__ = "machines"
    id = Column(Integer, primary_key=True, index=True)
    company_id = Column(Integer, ForeignKey("companies.id"))
    site_id = Column(Integer, ForeignKey("sites.id"), nullable=True)
    
    megnevezes = Column(String(255), index=True)
    gyarto = Column(String(255))
    tipus = Column(String(255))
    gyari_szam = Column(String(100), index=True)
    leltari_szam = Column(String(100), nullable=True)
    geptipus = Column(String(255))
    teherbiras = Column(String(50))
    alapadat_megjegyzes = Column(Text, nullable=True)

    # TEHERFELVEVŐ ESZKÖZ KAPCSOLÓ ---
    is_teherfelvevo = Column(Boolean, default=False)
    # ----------------------------------------

    # TARTOZÉK / FŐ GÉP KAPCSOLAT (szigorú szülő-gyerek hierarchia, csak informatív) ---
    fo_gep_id = Column(Integer, ForeignKey("machines.id"), nullable=True)
    fo_gep = relationship("Machine", remote_side=[id], backref="tartozekok")
    # ----------------------------------------

    gyartas_datum = Column(Date, nullable=True)
    uzembe_helyezes_datum = Column(Date, nullable=True)
    szerkezeti_vizsgalat_datum = Column(Date, nullable=True)
    fovizsgalat_datum = Column(Date, nullable=True)
    biztonsagi_vizsgalat_datum = Column(Date, nullable=True)
    # MSZ 9750 1. táblázat: a szerkezeti/fővizsgálat időköze üzemórában ÉS hónapban is meg van
    # adva, amelyik előbb bekövetkezik, az a mérvadó - ehhez kell tudni, mennyi volt az üzemóra
    # az UTOLSÓ ilyen típusú vizsgálatkor (a dátum-mezőkkel párhuzamosan frissül).
    szerkezeti_vizsgalat_uzemora = Column(Float, nullable=True)
    fovizsgalat_uzemora = Column(Float, nullable=True)

    uzemora = Column(Float, default=0.0)
    napi_atlag_uzemido = Column(Float, default=0.0)
    matrix_kezdo_datum = Column(DateTime, nullable=True)
    matrix_kezdo_uzemora = Column(Float, nullable=True)
    uzemora_riasztas_szint = Column(String(10), nullable=True)
    teher_class = Column(String(10), nullable=True)
    nehez_korulmenyek = Column(Boolean, default=False)
    veszelyes_kornyezet = Column(Boolean, default=False)
    szigoritott_szabaly = Column(Boolean, default=False)
    ebsz_ciklus_honap = Column(Integer, default=60)

    # EBSZ 7.2.10 - a fővizsgálati/IBF jogosultság MÁSODIK feltétele (az első a teherbírás):
    # a kezelő a kezelőkocsival/munkahellyel együtt emelkedik-e, és milyen magasra. Korábban
    # csak egy figyelmeztető szövegben szerepelt, sosem volt ténylegesen ellenőrizve - lásd
    # msz_logic.eui_fovizsgalatra_jogosult_e().
    kezelo_egyutt_emelkedik = Column(Boolean, default=False)
    kezeloi_munkahely_magassaga = Column(Integer, nullable=True)  # mm
    
    # MSZ 9750 Kockázatalapú felülbírálat mezői
    veszelyes_teher_mozgatas = Column(Boolean, default=False)
    kockazatertekeles_pdf_path = Column(String(500), nullable=True)
    egyedi_csoportszam_kockazat_alapjan = Column(Boolean, default=False)
    # Vizsgálói csoportszám-felülbírálás (MSZ 9750) - a fentitől ELTÉRŐ, önálló jogkör: a vizsgáló
    # a vizsgálati lapon, egy adott vizsgálat során saját szakmai megítélése alapján módosíthatja a
    # csoportszámot. Csak azt védi, hogy egy KÉSŐBBI, ezzel nem összefüggő gép-szerkesztési mentés
    # (recompute_msz_classification) ne írja felül csendben - az üzemóra-alapú automatikus
    # szigorítást/figyelmeztetést (check_uzemora_drift_and_escalate) NEM némítja el, mert az egy
    # tőle független, folyamatos biztonsági ellenőrzés.
    vizsgaloi_csoportszam_felulbiralas = Column(Boolean, default=False)

    kozuti_forgalom = Column(Boolean, default=False)
    rendszam = Column(String(20), nullable=True)
    forgalmi_szam = Column(String(50), nullable=True)
    kozuti_vizsga_datum = Column(Date, nullable=True)

    calculated_m_fokozat = Column(String(10), nullable=True)
    calculated_csoportszam = Column(String(10), nullable=True)

    statusz = Column(String(50), default="Aktív")
    statusz_oka = Column(Text, nullable=True)
    kornyezet_megvaltozott = Column(Boolean, default=False)
        
    # Ipar 4.0 mezők (Smart QR és Napi ellenőrzés) ---
    uuid = Column(String(50), unique=True, index=True, default=lambda: str(uuid.uuid4()))
    letiltva_napi_hiba_miatt = Column(Boolean, default=False)
    # --------------------------------------------------------

    # BÉRELT ESZKÖZ (külső, a rendszert nem használó tulajdonostól bérelt gép) ---
    berelt_eszkoz = Column(Boolean, default=False)
    berbeado_neve = Column(String(255), nullable=True)
    berbeado_elerhetoseg = Column(String(255), nullable=True)
    berlet_lejarat_datum = Column(Date, nullable=True)
    # ----------------------------------------

    ceg = relationship("Company", back_populates="machines")
    telephely = relationship("Site", back_populates="machines")
    vizsgalatok = relationship("Inspection", back_populates="machine")
    fajlok = relationship("File", back_populates="machine")
    naplo_bejegyzesek = relationship("AuditLog", back_populates="machine")

        # Hibrid kiegészítő mezők
    emelesi_magassag = Column(String(100), nullable=True)
    fesztav_gemhossz = Column(String(100), nullable=True)
    meghajtas = Column(String(100), nullable=True)
    teljesitmeny = Column(String(100), nullable=True)
    
    # Joker mezők
    egyedi_1 = Column(String(255), nullable=True)
    egyedi_2 = Column(String(255), nullable=True)
    egyedi_3 = Column(String(255), nullable=True)


class BerletiIdoszak(Base):
    """Egy gép kihelyezésének időszaka a bérbeadó (a gép tényleges, változatlan tulajdonosa/
    nyilvántartója) és egy bérlő cég között. A gép NEM költözik át - a bérlő cég felhasználói
    a saját /lista listájukban is látják, amíg a bérlet aktív (vege == null)."""
    __tablename__ = "berleti_idoszakok"
    id = Column(Integer, primary_key=True, index=True)
    machine_id = Column(Integer, ForeignKey("machines.id"))
    berlo_company_id = Column(Integer, ForeignKey("companies.id"), nullable=True)
    # ÚJ: ha a bérlő NEM a rendszert használó, regisztrált cég, hanem egy külső, szabad
    # szöveggel rögzített fél - ilyenkor berlo_company_id NULL marad, ez csak egy
    # nyilvántartási feljegyzés, valódi hozzáférést NEM ad a bérlőnek (nincs is fiókja).
    berlo_nev_kulso = Column(String(255), nullable=True)
    berlo_cim_kulso = Column(String(500), nullable=True)
    berlo_elerhetoseg_kulso = Column(String(255), nullable=True)
    kezdete = Column(Date)
    vege = Column(Date, nullable=True)
    uzemeltetes_felelos = Column(String(20), default="Berbeado")  # "Berbeado" vagy "Berlo" - ki hívja a szerelőt
    # ÚJ: regisztrált (berlo_company_id) bérlőnél a valódi hozzáférés csak akkor él, ha a bérlő
    # cég egy Admin/Emelőgép ügyintéző jogú usere jóváhagyta - a bérbeadó nem kényszerítheti rá a
    # kapcsolatot a másik félre. Szabad szöveges (berlo_nev_kulso) bérlőnél nincs valódi
    # hozzáférés-átadás, ezért ott a létrehozáskor rögtön True-ra áll (nincs mit jóváhagyni).
    jovahagyva = Column(Boolean, default=True, nullable=False)
    # ÚJ (2026-10-10-i user-jelzés): a gép a kihelyezéskor a bérbeadó SAJÁT telephelyét és
    # "Készenléti hely" (megnevezes) adatát tartotta meg, ami a bérlő listájában értelmetlen
    # (idegen cég telephelye/elnevezése). Regisztrált bérlőnél a jóváhagyáskor kérjük el, hogy a
    # bérlő melyik SAJÁT telephelyén és milyen készenléti helyen lesz a gép - ez csak a MEGJELENÍTÉST
    # érinti (a Machine.site_id/megnevezes NEM módosul, a bérbeadó saját nyilvántartása változatlan
    # marad). Szabad szöveges (külső) bérlőnél nincs jóváhagyás, ezért ott mindig NULL marad.
    berlo_site_id = Column(Integer, ForeignKey("sites.id"), nullable=True)
    berlo_keszenleti_hely = Column(String(255), nullable=True)
    letrehozo_user_id = Column(Integer, ForeignKey("users.id"), nullable=True)
    letrehozva = Column(DateTime, default=lambda: datetime.now(timezone.utc))

    machine = relationship("Machine")
    berlo_ceg = relationship("Company")
    berlo_site = relationship("Site")
    letrehozo = relationship("User")


class Dictionary(Base):
    __tablename__ = "dictionaries"
    id = Column(Integer, primary_key=True, index=True)
    company_id = Column(Integer, ForeignKey("companies.id"))
    kategoria = Column(String(100), index=True)
    ertek = Column(String(500))

    ceg = relationship("Company", back_populates="dictionaries")

class MachineTypeConfig(Base):
    __tablename__ = "machine_type_configs"
    id = Column(Integer, primary_key=True, index=True)
    company_id = Column(Integer, ForeignKey("companies.id"), nullable=False)
    geptipus = Column(String(200), nullable=False)
    
    # Pipálós konfigurációk (amik már eddig is megvoltak)
    kotelezo_mezok = Column(Text, nullable=True)
    rejtett_mezok = Column(Text, nullable=True)

    # ÚJ: A 3 Joker mező megjelenítendő neve az adott géptípushoz
    egyedi_1_nev = Column(String(100), nullable=True)
    egyedi_2_nev = Column(String(100), nullable=True)
    egyedi_3_nev = Column(String(100), nullable=True)

    # ÚJ: MSZ 16226 üzemviteli dokumentum - géptípusonként kapcsolható, hogy szükséges-e
    # ehhez a géptípushoz (pl. targoncáknál igen, egy toronydarunál nem).
    msz16226_szukseges = Column(Boolean, default=False)

    # ÚJ: EBSZ 7.2.10 - a "kezelő együtt emelkedik a kocsival/munkahellyel" mező csak azoknál
    # a targoncatípusoknál értelmezhető, ahol egyáltalán van ilyen kezelői munkahely (pl.
    # vezetőüléses, autonóm komissiózó) - géptípusonként kapcsolható a gép adatlapon.
    kezeloi_munkahely_szukseges = Column(Boolean, default=False)

    ceg = relationship("Company", back_populates="configs")

class Inspection(Base):
    __tablename__ = "inspections"
    id = Column(Integer, primary_key=True, index=True)
    machine_id = Column(Integer, ForeignKey("machines.id"))
    user_id = Column(Integer, ForeignKey("users.id"))
    
    vizsgalat_tipusa = Column(String(100))
    datum = Column(Date)
    eredmeny = Column(String(255))
    megjegyzes = Column(Text, nullable=True)

    jegyzokonyv_pdf_path = Column(String(500), nullable=True)
    reszletes_eredmenyek = Column(Text, nullable=True)

    # ÚJ: MSZ 16226 3.10 (Időszakos vizsgálatok nyilvántartása) szakaszához - a vizsgálat
    # időpontjában érvényes üzemóra-állás (a gép élő uzemora mezője folyamatosan változik,
    # ezért ezt a pillanatfelvételt a vizsgálat mentésekor rögzítjük), valamint egy
    # opcionális, kézzel megadható jegyzőkönyv-szám (ha nincs bekapcsolva, a belső
    # adatbázis-azonosító jelenik meg "#<id>" formában).
    uzemora_a_vizsgalatkor = Column(Float, nullable=True)
    jegyzokonyv_szam_egyedi = Column(Boolean, default=False)
    jegyzokonyv_szam = Column(String(50), nullable=True)

    # ÚJ: az "Időszakos biztonsági felülvizsgálat" típus 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 (a régi, történeti "Rendkívüli vizsgálat" vizsgalat_tipusa értékű sorok
    # változatlanul megmaradnak, nincs visszamenőleges migráció).
    rendkivuli = Column(Boolean, default=False)
    rendkivuli_indoklas = Column(Text, nullable=True)

    # Ha a vizsgálat egy aktív bérleti időszak alatt készült, ide kerül annak azonosítója -
    # ez adja a bérbeadó "alnaplóját" (a bérlet alatti jegyzőkönyvek szűrt nézete).
    berleti_idoszak_id = Column(Integer, ForeignKey("berleti_idoszakok.id"), nullable=True)

    # ÚJ: a vizsgálat rögzítésének (jegyzőkönyv kiállításának) valódi pillanata, UTC-ben -
    # a "datum" a jegyzőkönyvön szereplő (akár visszadátumozott) vizsgálati NAP, időpont
    # nélkül. Ez az oszlop KIZÁRÓLAG a gépnaplóban jelenik meg (helyi időre váltva);
    # a generált jegyzőkönyv-PDF-ekre szándékosan NEM kerül - azokon csak dátum szerepel.
    # A korábbi sorokat a main.py egyszeri, idempotens visszatöltése a jegyzőkönyv
    # fájljának feltöltési idejéből (files.uploaded_at) pótolja, ahol az létezik.
    letrehozva = Column(DateTime, nullable=True, default=lambda: datetime.now(timezone.utc))

    machine = relationship("Machine", back_populates="vizsgalatok")
    user = relationship("User")
    berleti_idoszak = relationship("BerletiIdoszak")

class File(Base):
    __tablename__ = "files"
    id = Column(Integer, primary_key=True, index=True)
    machine_id = Column(Integer, ForeignKey("machines.id"))
    file_path = Column(String(500))
    file_type = Column(String(100))
    uploaded_at = Column(DateTime, default=lambda: datetime.now(timezone.utc))
    # ÚJ: rövid szöveges leírás feltöltéskor (pl. "Szervíz munkalap" dokumentumtípusnál,
    # az MSZ 16226 üzemviteli dokumentum javítási naplójához) - opcionális, a legtöbb
    # fájltípusnál üresen marad.
    megjegyzes = Column(Text, nullable=True)

    machine = relationship("Machine", back_populates="fajlok")


class Msz16226Dokumentum(Base):
    """MSZ 16226 (Gépi hajtású targonca üzemviteli dokumentuma) - gépenként 1:1 rekord.
    A legtöbb adat (checklist, telephely-történet, javítási napló, vizsgálat-nyilvántartás)
    élőben, a meglévő File/Inspection/MaintenanceTicket/AuditLog rekordokból számolódik -
    ez a tábla csak azokat az adatokat tárolja, amiknek sehol máshol nincs otthonuk."""
    __tablename__ = "msz16226_dokumentumok"
    id = Column(Integer, primary_key=True, index=True)
    machine_id = Column(Integer, ForeignKey("machines.id"), unique=True, nullable=False)

    # 3.1: "emelőtargonca / vontatótargonca / szállítótargonca" választás
    targonca_tipus = Column(String(30), nullable=True)

    # Minden más (3.2 hiányzó mezői, 3.3 műszaki jellemzők, 3.6/3.7 megbízott személyek,
    # egyedi dokumentumtípusok listája) - egy JSON-string, az Inspection.reszletes_eredmenyek
    # mintáját követve, mert semmi mást nem kell rajta kívülről lekérdezni/szűrni.
    adatok_json = Column(Text, nullable=True)

    letrehozo_user_id = Column(Integer, ForeignKey("users.id"), nullable=True)
    letrehozva = Column(DateTime, default=lambda: datetime.now(timezone.utc))
    utolso_modosito_user_id = Column(Integer, ForeignKey("users.id"), nullable=True)
    utolso_modositas = Column(DateTime, nullable=True, onupdate=lambda: datetime.now(timezone.utc))

    machine = relationship("Machine")
    letrehozo = relationship("User", foreign_keys=[letrehozo_user_id])
    utolso_modosito = relationship("User", foreign_keys=[utolso_modosito_user_id])


class MszTelephelyMegjegyzes(Base):
    """Az MSZ 16226 üzemviteli dokumentum 3.5 szakaszához (üzemeltetésre vonatkozó adatok) -
    NEM egy önálló telephely-történet napló, hanem a MÁR MEGLÉVŐ, generikus AuditLog
    site_id-változás bejegyzéseket egészíti ki azokkal a szöveges mezőkkel, amiknek
    máshol nincs otthonuk (működési terület megnevezése, felelős szervezet adatai)."""
    __tablename__ = "msz_telephely_megjegyzesek"
    id = Column(Integer, primary_key=True, index=True)
    machine_id = Column(Integer, ForeignKey("machines.id"), nullable=False)
    # NULL = az induló/jelenlegi telephelyhez tartozó megjegyzés (még nem volt site_id-váltás
    # az AuditLog-ban) - egyébként az adott AuditLog sorhoz (site_id-változáshoz) tartozik.
    audit_log_id = Column(Integer, ForeignKey("audit_logs.id"), unique=True, nullable=True)

    mukodesi_terulet_megnevezese = Column(String(255), nullable=True)
    felelos_szervezet_nev = Column(String(255), nullable=True)
    felelos_szervezet_vezetoje = Column(String(255), nullable=True)
    megjegyzes = Column(Text, nullable=True)

    machine = relationship("Machine")
    audit_log = relationship("AuditLog")

class AuditLog(Base):
    __tablename__ = "audit_logs"
    id = Column(Integer, primary_key=True, index=True)
    machine_id = Column(Integer, ForeignKey("machines.id"), nullable=True)
    company_id = Column(Integer, ForeignKey("companies.id"), nullable=True)  # Cég-/felhasználó-szintű jogosultsági események (gép nélkül)
    user_id = Column(Integer, ForeignKey("users.id"), nullable=True)
    field_name = Column(String(255))
    old_value = Column(Text)
    new_value = Column(Text)
    timestamp = Column(DateTime, default=lambda: datetime.now(timezone.utc))

    machine = relationship("Machine", back_populates="naplo_bejegyzesek")
    ceg = relationship("Company")
    user = relationship("User")
    
    # IPAR 4.0 NAPI ELLENŐRZÉS ÉS HIBAJEGY MODUL ---

class DailyCheckQuestion(Base):
    __tablename__ = "daily_check_questions"
    id = Column(Integer, primary_key=True, index=True)
    company_id = Column(Integer, ForeignKey("companies.id"))
    szoveg = Column(String(255))
    kovetkezmeny = Column(String(50)) # "FIGYELMEZTETES" vagy "LETILTAS"
    aktiv = Column(Boolean, default=True)
    # ÚJ: vesszővel elválasztott géptípus-lista (ugyanaz a minta, mint a MachineTypeConfig.kotelezo_mezok/
    # rejtett_mezok mezőké) - üresen/None = minden géptípusnál megjelenik (visszamenőleg minden meglévő
    # sornál is ez az alapértelmezett, tehát a jelenlegi működés nem változik).
    geptipus_lista = Column(Text, nullable=True)

class MaintenanceTicket(Base):
    __tablename__ = "maintenance_tickets"
    id = Column(Integer, primary_key=True, index=True)
    machine_id = Column(Integer, ForeignKey("machines.id"))
    bejelento_nev = Column(String(100)) # Aki a napi ellenőrzést csinálta
    nyitas_datum = Column(DateTime, default=lambda: datetime.now(timezone.utc))
    hiba_leirasa = Column(Text)
    fenykep_path = Column(String(255), nullable=True) # Napi ellenőrzésen lőtt fotó
    statusz = Column(String(50), default="Nyitott") # Nyitott, Lezárva
    sulyossag = Column(String(50)) # FIGYELMEZTETES, LETILTAS
    hatarido = Column(Date, nullable=True) # "Korlátozással alkalmas" minősítésnél a javítási határidő

    # Feloldáshoz/Lezáráshoz szükséges adatok
    lezaras_datum = Column(DateTime, nullable=True)
    lezaro_user = Column(String(100), nullable=True)
    javitas_indoklas = Column(Text, nullable=True)
    munkalap_path = Column(String(255), nullable=True)

    machine = relationship("Machine")

    # --- TŰZVÉDELMI MODUL (Tűzoltó készülékek nyilvántartása és üzemeltetési naplója) ---

class KarbantartoCeg(Base):
    """A karbantartó/felülvizsgáló cégek adatgazdánkénti (üzemeltető cégenkénti) katalógusa.
    Ha a karbantartó maga is rendszerhasználó, a tenant_company_id összeköti a saját Company
    rekordjával - így az ő felhasználói a meglévő allowed_companies mechanizmussal kaphatnak
    hozzáférést az üzemeltető adataihoz."""
    __tablename__ = "karbantarto_cegek"
    id = Column(Integer, primary_key=True, index=True)
    company_id = Column(Integer, ForeignKey("companies.id"))  # az üzemeltető (adatgazda) cég
    nev = Column(String(255))
    szekhely = Column(String(500), nullable=True)
    okf_azonosito_jel = Column(String(100), nullable=True)
    tenant_company_id = Column(Integer, ForeignKey("companies.id"), nullable=True)
    aktiv = Column(Boolean, default=True)

    ceg = relationship("Company", foreign_keys=[company_id])
    tenant_ceg = relationship("Company", foreign_keys=[tenant_company_id])


class KarbantartoSzerzodes(Base):
    """A karbantartó cég és az üzemeltető közötti szerződéses (megbízási) időszak - a bérleti
    időszak (BerletiIdoszak) mintájára: több, egymást követő időszak is rögzíthető
    history-val, nem csak egy örökös be/ki kapcsoló."""
    __tablename__ = "karbantarto_szerzodesek"
    id = Column(Integer, primary_key=True, index=True)
    karbantarto_ceg_id = Column(Integer, ForeignKey("karbantarto_cegek.id"))
    kezdete = Column(Date)
    vege = Column(Date, nullable=True)
    letrehozo_user_id = Column(Integer, ForeignKey("users.id"), nullable=True)
    letrehozva = Column(DateTime, default=lambda: datetime.now(timezone.utc))

    karbantarto_ceg = relationship("KarbantartoCeg")
    letrehozo = relationship("User")


class Szakvizsga(Base):
    """Felhasználóhoz kötött tűzvédelmi szakvizsga-bizonyítvány (45/2011. BM rendelet 1. melléklete
    szerinti kategóriák), lejárat-figyeléssel."""
    __tablename__ = "szakvizsgak"
    id = Column(Integer, primary_key=True, index=True)
    user_id = Column(Integer, ForeignKey("users.id"))
    kategoria_kod = Column(Integer)
    bizonyitvany_szam = Column(String(100), nullable=True)
    kiallito = Column(String(255), nullable=True)
    ervenyesseg_datuma = Column(Date, nullable=True)

    user = relationship("User")


class TuzvedelmiTelephely(Base):
    """A tűzvédelmi modul saját, az emelőgépes Site-tól teljesen független telephely-nyilvántartása
    (a két modul között nincs átjárás - még ha fizikailag ugyanaz a cím is, külön-külön rögzítendő)."""
    __tablename__ = "tuzvedelmi_telephelyek"
    id = Column(Integer, primary_key=True, index=True)
    company_id = Column(Integer, ForeignKey("companies.id"))
    nev = Column(String(255))
    cim = Column(String(500), nullable=True)
    aktiv = Column(Boolean, default=True)

    ceg = relationship("Company")


class TuzvedelmiEpulet(Base):
    """A telephelyen belüli épület szint - minden készenléti helynek épülethez kell
    tartoznia (a telephely_id a KeszenletiHely-en denormalizáltan, az épület alapján
    marad kitöltve, hogy a meglévő telephely-szintű lekérdezések ne törjenek el)."""
    __tablename__ = "tuzvedelmi_epuletek"
    id = Column(Integer, primary_key=True, index=True)
    telephely_id = Column(Integer, ForeignKey("tuzvedelmi_telephelyek.id"))
    nev = Column(String(255))
    leiras = Column(Text, nullable=True)
    aktiv = Column(Boolean, default=True)

    # Szintbeállítás - a készülék felvitelekor választható "Szint" legördülő ez alapján épül fel.
    pinceszintek = Column(Integer, default=0)
    foldszint_valtozat = Column(String(30), default="FOLDSZINT")
    emeletek = Column(Integer, default=0)

    telephely = relationship("TuzvedelmiTelephely", backref="epuletek")


class KeszenletiHely(Base):
    """A stabil, telephelyhez (és épülethez) kötött készenléti pont - a rajta lévő
    fizikai készülék karbantartás/csere miatt cserélődhet, a hely maga marad."""
    __tablename__ = "keszenleti_helyek"
    id = Column(Integer, primary_key=True, index=True)
    company_id = Column(Integer, ForeignKey("companies.id"))
    telephely_id = Column(Integer, ForeignKey("tuzvedelmi_telephelyek.id"))
    epulet_id = Column(Integer, ForeignKey("tuzvedelmi_epuletek.id"), nullable=True)
    szint = Column(String(50), nullable=True)
    hely_leiras = Column(String(500))
    alapterulet_m2 = Column(Float, nullable=True)
    robbanasveszelyes = Column(Boolean, default=False)
    aktiv = Column(Boolean, default=True)

    ceg = relationship("Company")
    telephely = relationship("TuzvedelmiTelephely")
    epulet = relationship("TuzvedelmiEpulet")


class TuzoltoKeszulek(Base):
    """A fizikai tűzoltó készülék - a jelenlegi_hely_id-n keresztül kapcsolódik a stabil
    készenléti ponthoz, de karbantartás/csere miatt máshova is kerülhet, vagy raktárba."""
    __tablename__ = "tuzoltokeszulekek"
    id = Column(Integer, primary_key=True, index=True)
    company_id = Column(Integer, ForeignKey("companies.id"))
    jelenlegi_hely_id = Column(Integer, ForeignKey("keszenleti_helyek.id"), nullable=True)

    gyarto = Column(String(255), nullable=True)
    tipus_nev = Column(String(255), nullable=True)
    gyari_szam = Column(String(100), nullable=True, index=True)
    gyartasi_szabvany = Column(String(50), nullable=True)
    oltoanyag_tipus = Column(String(50), nullable=True)
    oe_ertek = Column(String(20), nullable=True)
    toltettomeg_kg = Column(Float, nullable=True)
    gyartas_datum = Column(Date, nullable=True)

    gyartoi_ellenorzes = Column(Boolean, default=False)
    gyartoi_ellenorzes_kezdete = Column(Date, nullable=True)

    statusz = Column(String(50), default="Aktív")
    jovahagyva = Column(Boolean, default=True)
    letrehozo_user_id = Column(Integer, ForeignKey("users.id"), nullable=True)

    utolso_alap_karbantartas = Column(Date, nullable=True)
    utolso_kozep_karbantartas = Column(Date, nullable=True)
    utolso_teljes_korbe = Column(Date, nullable=True)
    nyp_ervenyesseg_datuma = Column(Date, nullable=True)

    karbantarto_ceg_id = Column(Integer, ForeignKey("karbantarto_cegek.id"), nullable=True)

    ceg = relationship("Company", foreign_keys=[company_id])
    jelenlegi_hely = relationship("KeszenletiHely", backref="jelenlegi_keszulek", foreign_keys=[jelenlegi_hely_id])
    karbantarto_ceg = relationship("KarbantartoCeg")
    letrehozo = relationship("User")


class TuzvedelemFajl(Base):
    """Készülékhez szabadon (nem csak ellenőrzés-rögzítéskor) csatolható fénykép/dokumentum -
    a gépes modul File modelljének tűzvédelmi megfelelője."""
    __tablename__ = "tuzvedelem_fajlok"
    id = Column(Integer, primary_key=True, index=True)
    keszulek_id = Column(Integer, ForeignKey("tuzoltokeszulekek.id"))
    file_path = Column(String(500))
    file_type = Column(String(100))
    uploaded_at = Column(DateTime, default=lambda: datetime.now(timezone.utc))

    keszulek = relationship("TuzoltoKeszulek", backref="fajlok")


class TuzoltoKeszulekTipus(Base):
    """Bővíthető készüléktípus-katalógus a gyors felvitelhez (kereső + automatikus
    adatkitöltés). A company_id=NULL sorok a globális, előre feltöltött katalógust
    jelentik (fireg.hu gyártói műszaki adatai alapján), a kitöltött company_id-jú sorok
    egy adott cég saját, egyedi felvitelű típusai."""
    __tablename__ = "tuzoltokeszulek_tipusok"
    id = Column(Integer, primary_key=True, index=True)
    company_id = Column(Integer, ForeignKey("companies.id"), nullable=True)
    gyarto = Column(String(255))
    tipus_nev = Column(String(255))
    oltoanyag_tipus = Column(String(50), nullable=True)
    gyartasi_szabvany = Column(String(50), nullable=True)
    oe_ertek = Column(String(20), nullable=True)
    toltettomeg_kg = Column(Float, nullable=True)
    aktiv = Column(Boolean, default=True)

    ceg = relationship("Company")


class KeszulekTortenet(Base):
    """Melyik készülék mikortól-meddig volt melyik készenléti helyen - audit-nyom a
    karbantartás miatti cserékhez (vege=null -> jelenleg is ott van)."""
    __tablename__ = "keszulek_tortenet"
    id = Column(Integer, primary_key=True, index=True)
    keszenleti_hely_id = Column(Integer, ForeignKey("keszenleti_helyek.id"))
    keszulek_id = Column(Integer, ForeignKey("tuzoltokeszulekek.id"))
    kezdete = Column(Date)
    vege = Column(Date, nullable=True)

    keszenleti_hely = relationship("KeszenletiHely")
    keszulek = relationship("TuzoltoKeszulek")


class KeszulekKolcsonzes(Base):
    """Egy karbantartó cég SAJÁT tulajdonú (a karbantarto_ceg tenant_company_id-jához tartozó)
    tűzoltó készülékének kihelyezése egy üzemeltető készenléti helyéhez, amíg az üzemeltető
    saját készüléke szervizben (elszállítva karbantartásra) van - a bérleti időszak
    (BerletiIdoszak) mintájára. A készülék NEM kerül át az üzemeltető tulajdonába."""
    __tablename__ = "keszulek_kolcsonzesek"
    id = Column(Integer, primary_key=True, index=True)
    keszulek_id = Column(Integer, ForeignKey("tuzoltokeszulekek.id"))  # a karbantartó saját (kölcsönadott) készüléke
    keszenleti_hely_id = Column(Integer, ForeignKey("keszenleti_helyek.id"))  # hova lett kihelyezve
    eredeti_keszulek_id = Column(Integer, ForeignKey("tuzoltokeszulekek.id"), nullable=True)  # amit helyettesít
    kezdete = Column(Date)
    vege = Column(Date, nullable=True)
    letrehozo_user_id = Column(Integer, ForeignKey("users.id"), nullable=True)
    letrehozva = Column(DateTime, default=lambda: datetime.now(timezone.utc))

    keszulek = relationship("TuzoltoKeszulek", foreign_keys=[keszulek_id])
    keszenleti_hely = relationship("KeszenletiHely")
    eredeti_keszulek = relationship("TuzoltoKeszulek", foreign_keys=[eredeti_keszulek_id])
    letrehozo = relationship("User")


class ElettartamHosszabbitas(Base):
    """OTSZ 265. § (2): 25 kg feletti töltettömegű készülék élettartama szakvélemény
    birtokában alkalmanként 5 évvel hosszabbítható, legfeljebb kétszer."""
    __tablename__ = "elettartam_hosszabbitasok"
    id = Column(Integer, primary_key=True, index=True)
    keszulek_id = Column(Integer, ForeignKey("tuzoltokeszulekek.id"))
    szakvelemeny_datuma = Column(Date)
    szakerto_neve = Column(String(255))
    ervenyes_meddig = Column(Date)

    keszulek = relationship("TuzoltoKeszulek")


class TuzvedelmiEllenorzes(Base):
    """A tűzvédelmi üzemeltetési napló egy-egy bejegyzése: üzemeltetői ellenőrzés vagy
    karbantartás (alap/közép/teljes körű) esemény."""
    __tablename__ = "tuzvedelmi_ellenorzesek"
    id = Column(Integer, primary_key=True, index=True)
    keszulek_id = Column(Integer, ForeignKey("tuzoltokeszulekek.id"))
    tipus = Column(String(30))  # UZEMELTETOI_ELLENORZES / ALAP / KOZEP / TELJES_KORU
    datum = Column(Date)
    negyedev = Column(Integer, nullable=True)  # 1-4, csak üzemeltetői ellenőrzésnél

    karbantarto_ceg_id = Column(Integer, ForeignKey("karbantarto_cegek.id"), nullable=True)
    vegzo_neve = Column(String(255), nullable=True)
    szakvizsga_szam = Column(String(100), nullable=True)
    szakvizsga_ervenyesseg = Column(Date, nullable=True)
    is_egyben_ellenorzes_is = Column(Boolean, default=False)

    tapasztalt_hianyossag = Column(Text, nullable=True)
    intezkedes = Column(Text, nullable=True)
    megjegyzes = Column(Text, nullable=True)
    fenykep_path = Column(String(500), nullable=True)

    rogzito_user_id = Column(Integer, ForeignKey("users.id"), nullable=True)
    rogzitve = Column(DateTime, default=lambda: datetime.now(timezone.utc))

    keszulek = relationship("TuzoltoKeszulek")
    karbantarto_ceg = relationship("KarbantartoCeg")
    rogzito = relationship("User")


class TuzvedelmiNaplo(Base):
    """Évenkénti napló-időszak létesítményenként (site) - a 4 negyedéves ellenőrzés és az
    esedékes karbantartás megléte után az Admin lezárhatja."""
    __tablename__ = "tuzvedelmi_naplok"
    id = Column(Integer, primary_key=True, index=True)
    telephely_id = Column(Integer, ForeignKey("tuzvedelmi_telephelyek.id"))
    ev = Column(Integer)
    lezarva = Column(Boolean, default=False)
    lezaras_datuma = Column(Date, nullable=True)
    lezaro_user_id = Column(Integer, ForeignKey("users.id"), nullable=True)

    # Ha a napló hiányos bejegyzésekkel lett lezárva (elmaradt negyedéves ellenőrzés vagy
    # karbantartás), ez a jegyzés örökre rögzíti a hiányt - dátumbélyeggel, visszamenőleges
    # bejegyzés (hamisítás) nélkül, auditcélra.
    hianyosan_zarva = Column(Boolean, default=False)
    hianyossag_indoklas = Column(Text, nullable=True)

    telephely = relationship("TuzvedelmiTelephely")
    lezaro = relationship("User")


    # --- EBK MODUL (Biztonsági és egészségvédelmi koordinátor) ---

class EbkTerulet(Base):
    """A biztonsági koordinátor cégének megosztható, projektek között újrafelhasználható
    terület-katalógusa (pl. egy nagyobb ipari park különböző zónái)."""
    __tablename__ = "ebk_teruletek"
    id = Column(Integer, primary_key=True, index=True)
    company_id = Column(Integer, ForeignKey("companies.id"))
    nev = Column(String(255))
    cim = Column(String(500), nullable=True)
    aktiv = Column(Boolean, default=True)

    ceg = relationship("Company")


class EbkEpulet(Base):
    __tablename__ = "ebk_epuletek"
    id = Column(Integer, primary_key=True, index=True)
    terulet_id = Column(Integer, ForeignKey("ebk_teruletek.id"))
    nev = Column(String(255))
    leiras = Column(Text, nullable=True)
    aktiv = Column(Boolean, default=True)

    terulet = relationship("EbkTerulet", backref="epuletek")


class EbkSzint(Base):
    __tablename__ = "ebk_szintek"
    id = Column(Integer, primary_key=True, index=True)
    epulet_id = Column(Integer, ForeignKey("ebk_epuletek.id"))
    nev = Column(String(100))
    aktiv = Column(Boolean, default=True)

    epulet = relationship("EbkEpulet", backref="szintek")


class EbkAlvallalkozo(Base):
    """Céges törzsadat - a projektek között újrafelhasználható alvállalkozói lista."""
    __tablename__ = "ebk_alvallalkozok"
    id = Column(Integer, primary_key=True, index=True)
    company_id = Column(Integer, ForeignKey("companies.id"))
    nev = Column(String(255))
    felelos_vezeto = Column(String(255), nullable=True)
    kapcsolattarto_nev = Column(String(255), nullable=True)
    kapcsolattarto_elerhetoseg = Column(String(255), nullable=True)
    aktiv = Column(Boolean, default=True)

    ceg = relationship("Company")


class EbkTevekenyseg(Base):
    """Céges szintű, bővíthető tevékenység-katalógus (pl. "Állványozás", "Tetőfedés")."""
    __tablename__ = "ebk_tevekenysegek"
    id = Column(Integer, primary_key=True, index=True)
    company_id = Column(Integer, ForeignKey("companies.id"))
    nev = Column(String(255))
    aktiv = Column(Boolean, default=True)

    ceg = relationship("Company")


class EbkEllenorzesiTetel(Base):
    """Céges szintű ellenőrzési tétel-sablon (4/2002. Korm. rendelet 4. melléklete alapján
    állítható össze) - projektenként egyedileg ki/bekapcsolható (lásd EbkProjektTetel)."""
    __tablename__ = "ebk_ellenorzesi_tetelek"
    id = Column(Integer, primary_key=True, index=True)
    company_id = Column(Integer, ForeignKey("companies.id"))
    szoveg = Column(String(500))
    kotelezo = Column(Boolean, default=True)  # kötelező mező vagy szabad (opcionális)
    tipus = Column(String(20), default="NAPI")  # ATFOGO vagy NAPI
    aktiv = Column(Boolean, default=True)

    # Globális, egyedi tétel: a napi lista végén jelenik meg, és automatikusan szabálytalanná
    # vált, ha ugyanazon ellenőrzés bármely más tételénél be lett jelölve az "engedély nélkül
    # végzett munka" - így az engedély-hiány mindig önálló, külön követhető tételként is
    # rögzítésre kerül, nem csak egy másik szabálytalanság mellékkörülményeként.
    auto_engedely_osszesito = Column(Boolean, default=False)

    ceg = relationship("Company")


class EbkUgyfel(Base):
    """Céges törzsadat - az újrafelhasználható ügyfél (megbízó) katalógus. Egy projekt
    létrehozásakor ebből választva a projekt a megrendelő_* mezőkbe egy pillanatnyi
    másolatot ("snapshot") kap, hogy az ügyfél későbbi adatváltozása ne írja át
    visszamenőleg a már létrehozott projektek adatait."""
    __tablename__ = "ebk_ugyfelek"
    id = Column(Integer, primary_key=True, index=True)
    company_id = Column(Integer, ForeignKey("companies.id"))
    nev = Column(String(255))
    cim = Column(String(500), nullable=True)
    kapcsolattarto_nev = Column(String(255), nullable=True)
    kapcsolattarto_elerhetoseg = Column(String(255), nullable=True)
    aktiv = Column(Boolean, default=True)

    ceg = relationship("Company")


class EbkProjekt(Base):
    """Egy kivitelezési munkahely (Megrendelő szerinti projekt), amihez a koordinátor
    ellenőrzéseket rögzít. A vege mező kitöltése zárja le a projektet (aktív = vege is None)."""
    __tablename__ = "ebk_projektek"
    id = Column(Integer, primary_key=True, index=True)
    company_id = Column(Integer, ForeignKey("companies.id"))

    ugyfel_id = Column(Integer, ForeignKey("ebk_ugyfelek.id"), nullable=True)
    megrendelo_nev = Column(String(255))
    megrendelo_cim = Column(String(500), nullable=True)
    megrendelo_kapcsolattarto_nev = Column(String(255), nullable=True)
    megrendelo_kapcsolattarto_elerhetoseg = Column(String(255), nullable=True)
    kivitelezes_helyszine = Column(String(500), nullable=True)

    kezdete = Column(Date, nullable=True)
    vege = Column(Date, nullable=True)

    letrehozo_user_id = Column(Integer, ForeignKey("users.id"), nullable=True)
    letrehozva = Column(DateTime, default=lambda: datetime.now(timezone.utc))
    aktiv = Column(Boolean, default=True)

    ceg = relationship("Company")
    letrehozo = relationship("User")
    ugyfel = relationship("EbkUgyfel")
    teruletek = relationship("EbkTerulet", secondary=ebk_projekt_teruletek, backref="projektek")
    megrendelo_felhasznalok = relationship("User", secondary=user_ebk_projektek, backref="ebk_projektek")
    koordinator_felhasznalok = relationship("User", secondary=ebk_projekt_koordinatorok, backref="ebk_koordinalt_projektek")


class EbkProjektAlvallalkozo(Base):
    """Egy alvállalkozó adott projekthez rendelése - az ott végzett tevékenységeket az
    ebk_projekt_alvallalkozo_tevekenysegek kapcsolótábla sorolja fel."""
    __tablename__ = "ebk_projekt_alvallalkozok"
    id = Column(Integer, primary_key=True, index=True)
    projekt_id = Column(Integer, ForeignKey("ebk_projektek.id"))
    alvallalkozo_id = Column(Integer, ForeignKey("ebk_alvallalkozok.id"))

    projekt = relationship("EbkProjekt", backref="projekt_alvallalkozok")
    alvallalkozo = relationship("EbkAlvallalkozo")
    tevekenysegek = relationship("EbkTevekenyseg", secondary=ebk_projekt_alvallalkozo_tevekenysegek)


class EbkProjektTetel(Base):
    """Egy céges ellenőrzési tétel adott projektre vonatkozó ki/bekapcsolása - alapértelmezetten
    minden aktív tétel bekerül ide a projekt létrehozásakor, de admin kikapcsolhatja azt, ami az
    adott munkahelyen nem releváns (pl. nincs öltöző-igény)."""
    __tablename__ = "ebk_projekt_tetelek"
    id = Column(Integer, primary_key=True, index=True)
    projekt_id = Column(Integer, ForeignKey("ebk_projektek.id"))
    tetel_id = Column(Integer, ForeignKey("ebk_ellenorzesi_tetelek.id"))
    aktiv = Column(Boolean, default=True)

    projekt = relationship("EbkProjekt", backref="projekt_tetelek")
    tetel = relationship("EbkEllenorzesiTetel")


class EbkEllenorzes(Base):
    """Egy terepi bejárás (helyszíni ellenőrzés) egy adott projekt egy adott terület/épület/
    szint helyszínén, egy napon."""
    __tablename__ = "ebk_ellenorzesek"
    id = Column(Integer, primary_key=True, index=True)
    projekt_id = Column(Integer, ForeignKey("ebk_projektek.id"))
    terulet_id = Column(Integer, ForeignKey("ebk_teruletek.id"))
    epulet_id = Column(Integer, ForeignKey("ebk_epuletek.id"), nullable=True)
    szint_id = Column(Integer, ForeignKey("ebk_szintek.id"), nullable=True)
    # Ha az épületnek több szintje van és a bejárás mindegyikre kiterjedt, a fenti szint_id
    # üresen marad, és ehelyett minden egyes szabálytalanságnál (EbkEllenorzesTetel.szint_id)
    # külön-külön rögzítjük, melyik szinten történt.
    osszes_szint = Column(Boolean, default=False)

    datum = Column(Date)
    ellenorzo_user_id = Column(Integer, ForeignKey("users.id"), nullable=True)
    mindenrendben = Column(Boolean, default=False)
    letrehozva = Column(DateTime, default=lambda: datetime.now(timezone.utc))

    # Ha ez a bejárás egy adott témára (pl. "Egyéni védőeszközök") fókuszáló célellenőrzés volt -
    # a cégek ellenőrzési tétel-katalógusának meglévő kategorizálásából (a tétel szövegének a
    # kötőjel előtti része) választható, nem szabad szöveg.
    celellenorzes = Column(String(255), nullable=True)

    projekt = relationship("EbkProjekt", backref="ellenorzesek")
    terulet = relationship("EbkTerulet")
    epulet = relationship("EbkEpulet")
    szint = relationship("EbkSzint")
    ellenorzo = relationship("User")


class EbkEllenorzesTetel(Base):
    """Egy ellenőrzési tétel eredménye egy adott bejáráson belül - ha szabálytalanság, a
    részletei (alvállalkozó, tevékenység, munkavállaló, súlyosság, leírás, fénykép) és az
    elismerés/aláírás is itt kerül rögzítésre."""
    __tablename__ = "ebk_ellenorzes_tetelek"
    id = Column(Integer, primary_key=True, index=True)
    ellenorzes_id = Column(Integer, ForeignKey("ebk_ellenorzesek.id"))
    tetel_id = Column(Integer, ForeignKey("ebk_ellenorzesi_tetelek.id"))
    statusz = Column(String(20))  # RENDBEN vagy SZABALYTALANSAG

    alvallalkozo_id = Column(Integer, ForeignKey("ebk_alvallalkozok.id"), nullable=True)
    tevekenyseg_id = Column(Integer, ForeignKey("ebk_tevekenysegek.id"), nullable=True)
    # Csak akkor kap értéket, ha a bejárás (EbkEllenorzes.osszes_szint) az épület összes
    # szintjére kiterjedt - ilyenkor szabálytalanságonként külön kell megadni, melyik szinten
    # történt, mert az EbkEllenorzes.szint_id ekkor üresen marad.
    szint_id = Column(Integer, ForeignKey("ebk_szintek.id"), nullable=True)
    munkavallalo_neve = Column(String(255), nullable=True)
    sulyossag = Column(String(20), nullable=True)  # ENYHE / KOZEPES / SULYOS
    leiras = Column(Text, nullable=True)
    fenykep_path = Column(String(500), nullable=True)

    munkavegzesi_engedely_szam = Column(String(100), nullable=True)
    # Az engedély nélküli munkavégzés önmagában is szabálytalanság - ha ez be van jelölve,
    # a napi lista végén lévő "auto_engedely_osszesito" tétel automatikusan aktiválódik.
    engedely_nelkul = Column(Boolean, default=False)
    # Az engedély nélkül dolgozó cég azonosító adatai (gyakran nem is szerepel az
    # alvállalkozó-katalógusban, ezért ezek szabad szöveges mezők, nem választó lista).
    engedely_ceg_nev = Column(String(255), nullable=True)
    engedely_ceg_szekhely = Column(String(500), nullable=True)
    engedely_felelos_vezeto = Column(String(255), nullable=True)
    engedely_helyi_vezeto = Column(String(255), nullable=True)
    engedely_megrendelo_neve = Column(String(255), nullable=True)
    engedely_tevekenyseg = Column(String(500), nullable=True)

    elismerve = Column(Boolean, nullable=True)
    nem_elismeres_indoklas = Column(Text, nullable=True)
    alairas_path = Column(String(500), nullable=True)

    ellenorzes = relationship("EbkEllenorzes", backref="tetel_eredmenyek")
    tetel = relationship("EbkEllenorzesiTetel")
    alvallalkozo = relationship("EbkAlvallalkozo")
    tevekenyseg = relationship("EbkTevekenyseg")
    szint = relationship("EbkSzint")


    # --- VIVÜ MODUL (Veszélyes Ipari Védelmi Ügyintéző) ---
    # Az EBK modul mintájára, de: nincsenek alvállalkozók/tevékenységek, nincs engedély-blokk,
    # nincs aláírásos elismerés-mechanizmus, és cégenként PONTOSAN EGY VIVU-szerepkörű user lehet
    # (ezt a routers/users.py kényszeríti ki a User.role egyediségén - NINCS koordinátor-
    # kapcsolótábla, mert nem projektenkénti, hanem cégenkénti az ügyintéző-hozzárendelés).

class VivuTelephely(Base):
    """Egy Megrendelő saját telephelye - SZIGORÚAN egy Megrendelőhöz tartozik (1:N, nem
    megosztott/újrafelhasználható katalógus), hogy egyik Megrendelő telephelye se
    látszódhasson/keveredhessen egy másik Megrendelő adatai alatt."""
    __tablename__ = "vivu_telephelyek"
    id = Column(Integer, primary_key=True, index=True)
    ugyfel_id = Column(Integer, ForeignKey("vivu_ugyfelek.id"))
    nev = Column(String(255))
    cim = Column(String(500), nullable=True)
    aktiv = Column(Boolean, default=True)

    ugyfel = relationship("VivuUgyfel", backref="telephelyek")


class VivuEpulet(Base):
    __tablename__ = "vivu_epuletek"
    id = Column(Integer, primary_key=True, index=True)
    telephely_id = Column(Integer, ForeignKey("vivu_telephelyek.id"))
    nev = Column(String(255))
    leiras = Column(Text, nullable=True)
    aktiv = Column(Boolean, default=True)

    telephely = relationship("VivuTelephely", backref="epuletek")


class VivuSzint(Base):
    __tablename__ = "vivu_szintek"
    id = Column(Integer, primary_key=True, index=True)
    epulet_id = Column(Integer, ForeignKey("vivu_epuletek.id"))
    nev = Column(String(100))
    aktiv = Column(Boolean, default=True)

    epulet = relationship("VivuEpulet", backref="szintek")


class VivuUgyfel(Base):
    """A VIVÜ modul legfelső, önálló egysége: egy Megrendelő, akinek közvetlenül (Projekt
    köztes fogalom nélkül) saját telephelyei vannak (l. VivuTelephely.ugyfel_id)."""
    __tablename__ = "vivu_ugyfelek"
    id = Column(Integer, primary_key=True, index=True)
    company_id = Column(Integer, ForeignKey("companies.id"))
    nev = Column(String(255))
    cim = Column(String(500), nullable=True)
    kapcsolattarto_nev = Column(String(255), nullable=True)
    kapcsolattarto_elerhetoseg = Column(String(255), nullable=True)
    aktiv = Column(Boolean, default=True)

    ceg = relationship("Company")
    # Megtekintő szerepkörű felhasználók, akik csak ennél a Megrendelőnél láthatják a
    # telephelyeket/ellenőrzéseket - a User oldali backref neve "vivu_ugyfelek".
    megrendelo_felhasznalok = relationship("User", secondary=user_vivu_ugyfelek, backref="vivu_ugyfelek")


class VivuEllenorzesiTetel(Base):
    """Céges szintű ellenőrzési tétel-sablon - nincs per-Megrendelő be/kikapcsolás, minden
    aktív tétel mindig érvényes mindenhol. A tipus dönti el, melyik ellenőrzés-fajtánál
    (helyszíni bejárás vagy dokumentáció-felülvizsgálat) jelenik meg - a kettő KÜLÖN
    bejárás-típus, nem egy bejáráson belüli opcionális kiegészítés (ellentétben az EBK
    napi/átfogó bontásával)."""
    __tablename__ = "vivu_ellenorzesi_tetelek"
    id = Column(Integer, primary_key=True, index=True)
    company_id = Column(Integer, ForeignKey("companies.id"), nullable=True)  # NULL = globális tétel
    szoveg = Column(String(500))
    kotelezo = Column(Boolean, default=True)
    tipus = Column(String(20), default="BEJARAS")  # BEJARAS vagy DOKUMENTACIO
    aktiv = Column(Boolean, default=True)

    ceg = relationship("Company")


class VivuEllenorzes(Base):
    """Egy terepi bejárás VAGY dokumentáció-felülvizsgálat egy adott Megrendelő egy adott
    telephelyén, egy napon. NINCS egyetlen épület/szint mező - a "minden rendben" tételekhez
    tartozó, összesítő "mely épülete(ke)t érintette" lista az `epuletek` M:N relációban van,
    a konkrét szabálytalanságok pedig saját, egyedi épület+szint párost kapnak
    (VivuEllenorzesTetel.epulet_id/szint_id)."""
    __tablename__ = "vivu_ellenorzesek"
    id = Column(Integer, primary_key=True, index=True)
    telephely_id = Column(Integer, ForeignKey("vivu_telephelyek.id"))

    # "BEJARAS" (helyszíni bejárás) vagy "DOKUMENTACIO" (dokumentáció-felülvizsgálat) - eldönti,
    # melyik VivuEllenorzesiTetel-katalógus tételei kerültek ellenőrzésre ennél a rekordnál.
    tipus = Column(String(20))

    datum = Column(Date)
    ellenorzo_user_id = Column(Integer, ForeignKey("users.id"), nullable=True)
    mindenrendben = Column(Boolean, default=False)
    letrehozva = Column(DateTime, default=lambda: datetime.now(timezone.utc))

    # Ha ez a bejárás egy adott témára fókuszáló célellenőrzés volt - a cégek ellenőrzési
    # tétel-katalógusának meglévő kategorizálásából (a tétel szövegének a kötőjel előtti része)
    # választható, nem szabad szöveg.
    celellenorzes = Column(String(255), nullable=True)

    telephely = relationship("VivuTelephely", backref="ellenorzesek")
    epuletek = relationship("VivuEpulet", secondary=vivu_ellenorzes_epuletek, backref="vivu_ellenorzesek_erintve")
    ellenorzo = relationship("User")


class VivuEllenorzesTetel(Base):
    """Egy ellenőrzési tétel eredménye egy adott bejáráson/dokumentáció-felülvizsgálaton belül -
    ha szabálytalanság, a részletei (súlyosság, leírás) itt kerülnek rögzítésre. A fényképek
    KÜLÖN táblában (VivuTetelFenykep) tárolódnak, mert utólag is, tetszőleges számban
    csatolhatók (a helyszínen gyakran nem engedik a fényképezést, a képek csak később, más
    csatornán érkeznek)."""
    __tablename__ = "vivu_ellenorzes_tetelek"
    id = Column(Integer, primary_key=True, index=True)
    ellenorzes_id = Column(Integer, ForeignKey("vivu_ellenorzesek.id"))
    tetel_id = Column(Integer, ForeignKey("vivu_ellenorzesi_tetelek.id"))
    statusz = Column(String(20))  # RENDBEN / SZABALYTALANSAG / NEM_RELEVANS

    # Szabálytalanságnál MINDIG kitöltött - minden egyes eset saját, konkrét épület+szint
    # párost kap (a bejárás fejrekordján nincs egyetlen épület/szint mező, csak egy
    # összesítő "érintett épületek" lista, lásd VivuEllenorzes.epuletek).
    epulet_id = Column(Integer, ForeignKey("vivu_epuletek.id"), nullable=True)
    szint_id = Column(Integer, ForeignKey("vivu_szintek.id"), nullable=True)  # nem kötelező - nem minden épülethez van szint felvéve
    helyiseg = Column(String(200), nullable=True)  # szabadszöveges, nem kötelező kiegészítés a szint mellé
    sulyossag = Column(String(20), nullable=True)  # ENYHE / KOZEPES / SULYOS
    leiras = Column(Text, nullable=True)

    # Melyik szakterülethez (is) tartozik a konkrétan észlelt hiba - egyszerre több is
    # igaz lehet ugyanarra az esetre, és ugyanaz a tétel más bejáráson eltérő szakterületi
    # jelölést is kaphat, ezért ESETENKÉNT (nem a tétel-katalógusban) rögzítjük.
    szakterulet_iparbiztonsagi = Column(Boolean, default=False)
    szakterulet_tuzvedelmi = Column(Boolean, default=False)
    szakterulet_munkavedelmi = Column(Boolean, default=False)
    szakterulet_kornyezetvedelmi = Column(Boolean, default=False)

    ellenorzes = relationship("VivuEllenorzes", backref="tetel_eredmenyek")
    tetel = relationship("VivuEllenorzesiTetel")
    epulet = relationship("VivuEpulet")
    szint = relationship("VivuSzint")


class VivuTetelFenykep(Base):
    """Egy VivuEllenorzesTetel-hez (jellemzően szabálytalansághoz) tartozó fénykép - egy
    tételnek 0..N fényképe lehet, és bármikor, akár napokkal a bejárás után is bővíthető
    (VIVU vagy Admin töltheti fel, l. routers/vivu.py)."""
    __tablename__ = "vivu_tetel_fenykepek"
    id = Column(Integer, primary_key=True, index=True)
    tetel_id = Column(Integer, ForeignKey("vivu_ellenorzes_tetelek.id"))
    file_path = Column(String(500))
    feltoltve_datum = Column(DateTime, default=lambda: datetime.now(timezone.utc))
    feltolto_user_id = Column(Integer, ForeignKey("users.id"), nullable=True)

    tetel = relationship("VivuEllenorzesTetel", backref="fenykepek")
    feltolto = relationship("User")


class RendszerBeallitas(Base):
    """GLOBÁLIS (nem céghez kötött) rendszerbeállítások kulcs-érték tárolója (2026-10-04).

    MIÉRT NEM A MEGLÉVŐ `Dictionary` TÁBLA?
        A Dictionary minden sora egy CÉGHEZ (company_id) tartozik - cégenkénti kapcsolókra való
        (pl. EmailRiportGyakorisag). Az itt tárolt értékek viszont az EGÉSZ rendszerre vonatkoznak
        (pl. az egyetlen közös SMTP-fiók), és kizárólag a valódi rendszeradminisztrátor
        (security.is_rendszeradminisztrator) láthatja/írhatja őket. A két fogalmat szándékosan
        külön táblában tartjuk, hogy egy céges admin véletlenül se érhessen hozzá.

    OSZLOPOK:
        kulcs       - a beállítás neve, egyedi (pl. "smtp_server"); a lehetséges kulcsok listája a
                      email_beallitasok.py-ban van (nem szabad ide, a DB-be "szabadon" felvenni).
        ertek       - a beállítás értéke szövegként. Ha `titkositott` igaz, ez a titkosito_utils.py
                      által titkosított szöveg (NEM olvasható nyers jelszó).
        titkositott - igaz, ha az `ertek` titkosítva van (pl. smtp_jelszo).
        modositva_at / modosito_user_id - ki és mikor módosította utoljára (az érték változását
                      a Jogosultsági napló (AuditLog) is rögzíti, de a jelszó értékét SOHA nem).

    Új tábla, ezért a main.py init_db()-ban lévő create_all() induláskor automatikusan létrehozza -
    külön migrációs szkript a TÁBLÁHOZ nem kell (csak az opcionális .env->DB átültetéshez, l.
    migracio_smtp_env_to_db.py).
    """
    __tablename__ = "rendszer_beallitasok"
    id = Column(Integer, primary_key=True, index=True)
    kulcs = Column(String(100), unique=True, index=True, nullable=False)
    ertek = Column(Text, nullable=True)
    titkositott = Column(Boolean, default=False)
    modositva_at = Column(DateTime, default=lambda: datetime.now(timezone.utc))
    modosito_user_id = Column(Integer, ForeignKey("users.id"), nullable=True)

    modosito = relationship("User")


class EmailKimeno(Base):
    """KIMENŐ LEVELEK SORA (outbox) - 2026-10-04, e-mail rendszer B szelet.

    MIÉRT KELL?
        Korábban a rendszer a levelet azonnal, a kérés háttérszálán küldte el: ha az SMTP-szerver
        éppen nem volt elérhető, a levél örökre elveszett, és semmi nem korlátozta, hány levél megy ki
        egy óra alatt (egy hiba-áradat a feladó-címet spam-listára vihette). Mostantól minden levél
        ELŐSZÖR ebbe a táblába kerül (email_sor.sorba_allit), és egy percenként futó ütemezett
        feladat (email_sor.kiurites) küldi ki őket - a rendszeradmin által beállított óránkénti/napi
        korlátig, hiba esetén növekvő várakozással újrapróbálva.

    EGY SOR = EGY CÍMZETT. (Így egy hibás cím nem akadályoz másokat, és a címzettek nem látják
    egymás e-mail címét - a korábbi közös "To:" mező ezt nem tudta.)

    OSZLOPOK:
        cimzett            - a címzett e-mail címe.
        targy / torzs_html - a kész levél tárgya és HTML törzse (a törzsben a változó adatok
                             html.escape-pelve vannak - l. email_utils.py).
        kategoria          - "riasztas" | "napi_riport" | "rendszer" (a későbbi feliratkozás-kezelés
                             és a szűrés alapja).
        prioritas          - 0 = sürgős (kritikus riasztás), 1 = normál, 2 = alacsony (napi riport).
                             A kiürítő prioritás, majd beérkezési sorrendben küld.
        allapot            - "varakozik" | "kuldes_alatt" | "elkuldve" | "szimulalt" | "hibas" | "lejart"
                             ("szimulalt": nincs SMTP beállítva, a levelet csak a konzolra írtuk ki).
        probalkozasok      - eddigi sikertelen próbálkozások száma; a maximum után "hibas".
        kovetkezo_proba_at - ennél korábban nem próbáljuk újra (UTC).
        utolso_hiba        - a legutóbbi hiba rövid szövege (jelszót nem tartalmaz).
        dedup_kulcs        - riasztásoknál az ismétlés-szűrés kulcsa; ha a levél végleg "hibas" lesz, az
                             ehhez tartozó állapotbejegyzés törlődik (hogy a hiba újra jelezhető legyen).
        company_id         - melyik céghez tartozik (nem kötelező; áttekintéshez).
        letrehozva_at / elkuldve_at - UTC időpontok.
    """
    __tablename__ = "email_kimeno"
    id = Column(Integer, primary_key=True, index=True)
    cimzett = Column(String(255), nullable=False)
    targy = Column(String(500), nullable=False)
    # MariaDB-n a sima TEXT legfeljebb 65 535 bájt - egy nagy cég napi riportja ezt túllépheti: ott MEDIUMTEXT (16 MB)
    torzs_html = Column(Text().with_variant(MEDIUMTEXT(), "mysql"), nullable=False)
    kategoria = Column(String(50), default="riasztas")
    prioritas = Column(Integer, default=1)
    allapot = Column(String(20), default="varakozik", index=True)
    probalkozasok = Column(Integer, default=0)
    kovetkezo_proba_at = Column(DateTime, nullable=True)
    utolso_hiba = Column(String(500), nullable=True)
    dedup_kulcs = Column(String(190), nullable=True)  # az ismétlés-szűrés kulcsa (riasztásoknál) - l. email_sor.sorba_allit
    company_id = Column(Integer, ForeignKey("companies.id"), nullable=True)
    letrehozva_at = Column(DateTime, default=lambda: datetime.now(timezone.utc))
    elkuldve_at = Column(DateTime, nullable=True, index=True)


class EmailErtesitesAllapot(Base):
    """ISMÉTLŐDŐ HIBÁK SZŰRÉSE - mikor jeleztünk utoljára egy adott hibát (2026-10-04, B szelet).

    A kívánt működés: ha egy hiba (pl. egy gép lejárt vizsgálata) ma is, holnap is, azután is
    fennáll, a rendszer CSAK AZ ELSŐ alkalommal küld róla levelet, és csak X nap (alapból 7)
    elteltével emlékeztet újra, ha a hiba még mindig fennáll.

    EGY SOR = EGY (cég, hiba) PÁR:
        kulcs                - a hiba azonosítója, stabil szöveg (pl. "riport:12:gep:34:Fővizsgálat:lejart:2026-09-01"
                               vagy "riasztas:34:K:3fa9..."). Ugyanaz a hiba MINDIG ugyanazt a kulcsot adja.
        utolso_kikuldes_nap  - melyik napon (helyi dátum) került utoljára levélbe. Nap-alapú (nem
                               óra-alapú) összehasonlítás: egy heti riportnál a pontosan 7 nappal
                               korábbi 06:00:05-ös küldés ne tiltsa le a ma 06:00:00-s futást.
        utoljara_latva_nap   - melyik napon láttuk utoljára fennállni (csak a napi riport tölti ki;
                               amelyik tétel már nem szerepel, az megoldódott -> a sora törlődik,
                               így ha később újra előfordul, ismét "új hiba").
    A kulcs egyedi (UniqueConstraint): párhuzamos folyamatok ugyanazt a hibát nem tudják kétszer
    "elsőként" bejegyezni.
    """
    __tablename__ = "email_ertesites_allapot"
    id = Column(Integer, primary_key=True, index=True)
    kulcs = Column(String(190), nullable=False)  # 190 x 4 bajt (utf8mb4) < 767: régi MariaDB-indexhatárral is kompatibilis
    company_id = Column(Integer, nullable=True, index=True)
    utolso_kikuldes_nap = Column(Date, nullable=False)
    utoljara_latva_nap = Column(Date, nullable=True)
    __table_args__ = (UniqueConstraint("kulcs", name="uq_email_ertesites_allapot_kulcs"),)


class UtemezettFutas(Base):
    """EGYSZERI FUTÁS BIZTOSÍTÁSA az ütemezett feladatoknál (2026-10-04, B szelet).

    PROBLÉMA: az éles szerver 3 gunicorn workerrel fut, és a main.py minden workerben elindítja a
    saját APScheduler-ét - így a napi riport / ellenőrzések akár 3-szor is lefuthattak (3x annyi levél).
    MEGOLDÁS: minden futás előtt a feladat megpróbál beszúrni egy (feladat, kulcs) sort - pl.
    ("napi_riport", "2026-10-05"). A tábla (feladat, kulcs) párja egyedi, ezért az adatbázis
    pontosan EGY workernek engedi a beszúrást; a többi IntegrityError-t kap, és kihagyja a futást.
    Nincs szükség külső zárra (fájl, Redis), és a worker összeomlása sem akaszt meg semmit.
    A régi sorok az utemezo_utils.takaritas() hívással törlődnek.
    """
    __tablename__ = "utemezett_futasok"
    id = Column(Integer, primary_key=True, index=True)
    feladat = Column(String(50), nullable=False)
    kulcs = Column(String(50), nullable=False)  # (50+50) x 4 bajt (utf8mb4) < 767: régi MariaDB-indexhatárral is kompatibilis
    futott_at = Column(DateTime, default=lambda: datetime.now(timezone.utc))
    __table_args__ = (UniqueConstraint("feladat", "kulcs", name="uq_utemezett_futas_feladat_kulcs"),)


# =============================================================================================
# LOGIN-VÉDELEM (2026-10-04, D szelet) - docs/LOGIN_VEDELEM.md
# =============================================================================================
class LoginKiserlet(Base):
    """Egy SIKERTELEN bejelentkezési kísérlet. Egy kísérlet = egy sor.

    MIÉRT AZ ADATBÁZISBAN? Régen a számláló a folyamat memóriájában élt (security.py), így a 3
    gunicorn worker külön-külön számolt (a valódi határ akár 3x annyi volt), újraindításkor pedig
    nullázódott. Az adatbázisban minden worker ugyanazt látja.
    A számlálás: hány sor van az adott IP-hez / e-mailhez az elmúlt 5 percben (login_vedelem.py).
    A régi sorokat a napi takarítás törli."""
    __tablename__ = "login_kiserletek"
    id = Column(Integer, primary_key=True, index=True)
    ip = Column(String(64), index=True, nullable=False)
    email = Column(String(190), index=True, nullable=False)   # kisbetűsítve, levágva (a támadó bármit beírhat)
    idopont = Column(DateTime, index=True, nullable=False)    # tz nélküli UTC, mint a többi időpont


class LoginTiltas(Base):
    """Egy bejelentkezési TILTÁS (egy IP-re vagy egy fiókra/e-mailre).

    tipus       - 'ip' vagy 'email'
    azonosito   - az IP-cím, illetve a kisbetűsített e-mail cím
    lejar_at    - meddig tart; NULL = VÉGLEGES, amíg a rendszeradmin fel nem oldja
    valos       - igaz, ha VALÓS fiókról van szó (az e-mail létező felhasználóé, vagy az IP-ről
                  létező fiókot próbáltak). CSAK a valós tiltásról megy értesítő levél.
    erintett    - IP-tiltásnál: a valós fiókok e-mail címei, amelyeket arról az IP-ről próbáltak
    ertesites   - 'elkuldve' | 'korlat' (túl sok értesítő volt az órában) | 'nincs_valos' | 'nincs_cimzett' | 'hiba'
    feloldva_at - ha a rendszeradmin kézzel feloldotta (a lejárat nem "feloldás")
    """
    __tablename__ = "login_tiltasok"
    id = Column(Integer, primary_key=True, index=True)
    tipus = Column(String(10), nullable=False)
    azonosito = Column(String(190), nullable=False)
    letrehozva_at = Column(DateTime, nullable=False)
    lejar_at = Column(DateTime, nullable=True)
    vegleges = Column(Boolean, default=False, nullable=False)
    probalkozasok = Column(Integer, default=0, nullable=False)
    ip_cim = Column(String(64))
    user_id = Column(Integer, ForeignKey("users.id", ondelete="SET NULL"), nullable=True)
    company_id = Column(Integer, ForeignKey("companies.id", ondelete="SET NULL"), nullable=True)
    valos = Column(Boolean, default=False, nullable=False)
    erintett = Column(Text)
    ertesites = Column(String(20))
    ertesitve_at = Column(DateTime, nullable=True)
    feloldva_at = Column(DateTime, nullable=True)
    felolto_user_id = Column(Integer, ForeignKey("users.id", ondelete="SET NULL"), nullable=True)
    # EGYEDISÉGI ŐR: amíg a tiltás aktív, értéke "<tipus>:<azonosito>", különben NULL. Az egyedi index
    # (a NULL-ok nem ütköznek) az ADATBÁZIS szintjén zárja ki, hogy két worker egyszerre két aktív
    # tiltást hozzon létre ugyanarra az azonosítóra (párhuzamos kérések / támadás-roham esetén).
    aktiv_kulcs = Column(String(200), unique=True, nullable=True)

    user = relationship("User", foreign_keys=[user_id])
    felolto = relationship("User", foreign_keys=[felolto_user_id])
    __table_args__ = (Index("ix_login_tiltasok_tipus_azonosito", "tipus", "azonosito"),)


class AktivaloToken(Base):
    """Egyszer használatos, időkorlátos link-token (jelenleg: fiók-aktiválás; később a 2FA
    "elveszett második faktor" jelszócseréje is ezt használja a `cel` oszloppal).

    BIZTONSÁG: az adatbázisban CSAK a token SHA-256 lenyomata van (`token_hash`) - a nyers token
    egyedül a kiküldött levélben (és a linkben) létezik. Így egy adatbázis-kiszivárgás (mentés)
    önmagában nem ad használható aktiváló linket. A token 256 bites véletlen, ezért találgatni nem
    lehet."""
    __tablename__ = "aktivalo_tokenek"
    id = Column(Integer, primary_key=True, index=True)
    user_id = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True)
    token_hash = Column(String(64), unique=True, nullable=False)   # SHA-256 hex
    cel = Column(String(30), nullable=False, default="aktivalas")
    letrehozva_at = Column(DateTime, nullable=False)
    lejar_at = Column(DateTime, nullable=False)
    felhasznalva_at = Column(DateTime, nullable=True)

    user = relationship("User", foreign_keys=[user_id])


class MfaMentokod(Base):
    """2FA MENTŐKÓD (v34): egyszer használható tartalék belépő kód arra az esetre, ha a felhasználó telefonja (hitelesítő alkalmazása)
    nem érhető el. Egy felhasználónak egyszerre egy KÉSZLETE (10 db) van; új készlet kérésekor a régi sorok törlődnek.

    BIZTONSÁG: az adatbázisban CSAK a kód HMAC-SHA256 lenyomata van (`kod_hash`), a nyers kód egyedül a felhasználó kezében létezik
    (a készlet készítésekor egyszer jelenik meg). A felhasználás atomi: `felhasznalva_at` NULL -> időpont. Részletek: mentokod_utils.py,
    docs/KETLEPCSOS_HITELESITES.md."""
    __tablename__ = "mfa_mentokodok"
    id = Column(Integer, primary_key=True, index=True)
    user_id = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True)
    kod_hash = Column(String(64), nullable=False)          # HMAC-SHA256 hex
    letrehozva_at = Column(DateTime, nullable=False)
    felhasznalva_at = Column(DateTime, nullable=True)      # NULL = még felhasználható


class EmailFeliratkozasSzabaly(Base):
    """Levél-feliratkozás SZABÁLY (2026-10-04, C szelet): a CÉGES Admin állítja be, hogy egy adott
    SZEREPKÖRNEK egy adott levélkategóriát mennyire lehet/kell kapnia. (Lásd email_feliratkozas.py és
    docs/FELIRATKOZASOK.md.)

    mod értékei:
        kotelezo   - mindig megkapja, a felhasználó NEM kapcsolhatja ki
        alapbol_be - alapból megkapja, de a felhasználó kikapcsolhatja
        alapbol_ki - alapból nem kapja, de a felhasználó bekapcsolhatja
        tiltott    - nem kaphatja meg (a felhasználó nem kapcsolhatja be)
    Ha egy (cég, szerepkör, kategória) hármashoz NINCS sor, a program alapértelmezése érvényes
    (Admin és Emelőgép ügyintéző: alapbol_be - ahogy a korábbi működés; minden más szerepkör: tiltott)."""
    __tablename__ = "email_feliratkozas_szabalyok"
    id = Column(Integer, primary_key=True, index=True)
    company_id = Column(Integer, ForeignKey("companies.id", ondelete="CASCADE"), nullable=False, index=True)
    szerepkor = Column(String(50), nullable=False)
    kategoria = Column(String(50), nullable=False)
    mod = Column(String(20), nullable=False)
    modositva_at = Column(DateTime, nullable=True)
    modosito_user_id = Column(Integer, nullable=True)   # csak tájékoztató (nincs FK: a felhasználó törölhető)

    __table_args__ = (UniqueConstraint("company_id", "szerepkor", "kategoria", name="uq_feliratkozas_szabaly"),)


class EmailFeliratkozas(Base):
    """Egy FELHASZNÁLÓ saját választása egy levélkategóriára (2026-10-04, C szelet). Csak akkor van
    hatása, ha a céges szabály (EmailFeliratkozasSzabaly) alapbol_be / alapbol_ki - kötelező és tiltott
    szabálynál a tárolt választás nem számít (de megmarad, ha a szabály később lazul)."""
    __tablename__ = "email_feliratkozasok"
    id = Column(Integer, primary_key=True, index=True)
    user_id = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True)
    kategoria = Column(String(50), nullable=False)
    bekapcsolva = Column(Boolean, nullable=False, default=True)
    modositva_at = Column(DateTime, nullable=True)

    __table_args__ = (UniqueConstraint("user_id", "kategoria", name="uq_feliratkozas_user_kategoria"),)


class JelszoElozmeny(Base):
    """JELSZÓ-ELŐZMÉNY (v36): a felhasználó korábbi jelszavainak bcrypt-lenyomata (NEM a jelszó), hogy a cég jelszó-házirendje (jelszo_elozmeny_db)
    meg tudja akadályozni egy régi jelszó újra beállítását. Csak akkor készül új sor, ha a cégnél az előzmény >= 2 (1 = csak a jelenlegi jelszót
    vetjük össze, ahhoz nem kell előzmény); felhasználónként legfeljebb ELOZMENY_MAX (10) sor marad. Részletek: jelszo_hazirend.py."""
    __tablename__ = "jelszo_elozmenyek"
    id = Column(Integer, primary_key=True, index=True)
    user_id = Column(Integer, ForeignKey("users.id", ondelete="CASCADE"), nullable=False, index=True)
    hashed_password = Column(String(255), nullable=False)
    letrehozva_at = Column(DateTime, nullable=False)


class CegMeghivoKod(Base):
    """PARTNER-CÉGEK (2026-10-06): meghívókód, amivel egy cég egy MÁSIK, általa név szerint nem
    felkínált céggel partnerséget köthet (l. CegPartnerseg) - így a bérbeadás/kihelyezés
    bérlő-választója nem az ÖSSZES rendszerben lévő céget sorolja fel (korábbi, a user által
    jelzett adatszivárgási probléma), hanem csak a már összekapcsolt partnereket.

    BIZTONSÁG: az adatbázisban CSAK a kód HMAC-SHA256 lenyomata van (`kod_hash`, kulcs: SECRET_KEY) -
    a nyers kód egyedül a generáló cég képernyőjén jelenik meg egyszer. Egyszer használatos
    (`felhasznalva_at`) és időkorlátos (`lejar_at`). Részletek: partner_ceg_utils.py."""
    __tablename__ = "ceg_meghivo_kodok"
    id = Column(Integer, primary_key=True, index=True)
    ceg_id = Column(Integer, ForeignKey("companies.id", ondelete="CASCADE"), nullable=False, index=True)
    kod_hash = Column(String(64), unique=True, nullable=False)   # HMAC-SHA256 hex
    letrehozo_user_id = Column(Integer, ForeignKey("users.id"), nullable=True)
    letrehozva_at = Column(DateTime, nullable=False)
    lejar_at = Column(DateTime, nullable=False)
    felhasznalva_at = Column(DateTime, nullable=True)
    felhasznalo_ceg_id = Column(Integer, ForeignKey("companies.id"), nullable=True)
    felhasznalo_user_id = Column(Integer, ForeignKey("users.id"), nullable=True)

    ceg = relationship("Company", foreign_keys=[ceg_id])
    felhasznalo_ceg = relationship("Company", foreign_keys=[felhasznalo_ceg_id])


class CegPartnerseg(Base):
    """PARTNER-CÉGEK (2026-10-06): két cég közötti, kölcsönös hozzájárulással (meghívókód-csere)
    létrehozott, tartós kapcsolat - ez NEM ad automatikus hozzáférést semmihez, csak azt jelenti,
    hogy a két cég "látja" egymást a bérbeadás/kihelyezés bérlő-választójában
    (routers/machines.py, berlo_cegek_valaszthato). A konkrét gép-kihelyezést a bérlőnek
    továbbra is EGYEDILEG kell jóváhagynia (BerletiIdoszak.jovahagyva) - a partnerség csak a
    választási kört szűkíti, nem helyettesíti az egyedi jóváhagyást."""
    __tablename__ = "ceg_partnersegek"
    id = Column(Integer, primary_key=True, index=True)
    ceg_a_id = Column(Integer, ForeignKey("companies.id", ondelete="CASCADE"), nullable=False, index=True)
    ceg_b_id = Column(Integer, ForeignKey("companies.id", ondelete="CASCADE"), nullable=False, index=True)
    allapot = Column(String(20), nullable=False, default="Aktív")   # "Aktív" / "Visszavonva"
    letrehozva_at = Column(DateTime, nullable=False)
    visszavonva_at = Column(DateTime, nullable=True)
    letrehozo_user_id = Column(Integer, ForeignKey("users.id"), nullable=True)
    elfogado_user_id = Column(Integer, ForeignKey("users.id"), nullable=True)
    visszavono_user_id = Column(Integer, ForeignKey("users.id"), nullable=True)

    ceg_a = relationship("Company", foreign_keys=[ceg_a_id])
    ceg_b = relationship("Company", foreign_keys=[ceg_b_id])
