from dataclasses import dataclass, field
from datetime import datetime
from typing import Optional


@dataclass
class Pracownik:
    """Klasa reprezentująca pracownika biblioteki."""
    imie: str
    nazwisko: str
    stanowisko: str
    data_zatrudnienia: str
    pesel: str = field(default="")
    telefon: str = field(default="")
    _id_pracownika: int = field(default=0, repr=False)
    
    def __post_init__(self):
        if not self.pesel:
            self.pesel = "Nie podano"
        if not self.telefon:
            self.telefon = "Nie podano"
    
    @property
    def id_pracownika(self) -> int:
        return self._id_pracownika
    
    @property
    def pelne_dane(self) -> str:
        return f"{self.imie} {self.nazwisko}"
    
    def to_dict(self) -> dict:
        return {
            'imie': self.imie,
            'nazwisko': self.nazwisko,
            'stanowisko': self.stanowisko,
            'data_zatrudnienia': self.data_zatrudnienia,
            'pesel': self.pesel,
            'telefon': self.telefon,
            'id_pracownika': self._id_pracownika
        }
    
    @classmethod
    def from_dict(cls, data: dict):
        return cls(
            data['imie'], data['nazwisko'], data['stanowisko'],
            data['data_zatrudnienia'], data.get('pesel', ''), data.get('telefon', '')
        )


class KolekcjaPracownikow:
    """Kolekcja pracowników z iteratorem."""
    
    def __init__(self):
        self._pracownicy: list[Pracownik] = []
        self._nastepne_id: int = 1
    
    def dodaj(self, pracownik: Pracownik) -> Pracownik:
        pracownik._id_pracownika = self._nastepne_id
        self._nastepne_id += 1
        self._pracownicy.append(pracownik)
        return pracownik
    
    def usun(self, id_pracownika: int) -> bool:
        for i, p in enumerate(self._pracownicy):
            if p.id_pracownika == id_pracownika:
                self._pracownicy.pop(i)
                return True
        return False
    
    def znajdz(self, id_pracownika: int) -> Optional[Pracownik]:
        for p in self._pracownicy:
            if p.id_pracownika == id_pracownika:
                return p
        return None
    
    def znajdz_pesel(self, pesel: str) -> Optional[Pracownik]:
        for p in self._pracownicy:
            if p.pesel == pesel:
                return p
        return None
    
    def modyfikuj(self, id_pracownika: int, **kwargs) -> bool:
        pracownik = self.znajdz(id_pracownika)
        if not pracownik:
            return False
        for key, value in kwargs.items():
            if hasattr(pracownik, key):
                setattr(pracownik, key, value)
        return True
    
    def __iter__(self):
        return iter(self._pracownicy)
    
    def __len__(self):
        return len(self._pracownicy)
    
    def __getitem__(self, indeks: int) -> Pracownik:
        return self._pracownicy[indeks]


@dataclass
class Czytelnik:
    """Klasa reprezentująca czytelnika biblioteki."""
    imie: str
    nazwisko: str
    adres: str
    telefon: str
    email: str = field(default="")
    _id_czytelnika: int = field(default=0, repr=False)
    _wypozyczone: list = field(default_factory=list, repr=False)
    _zarezerwowane: list = field(default_factory=list, repr=False)
    
    @property
    def id_czytelnika(self) -> int:
        return self._id_czytelnika
    
    @property
    def pelne_dane(self) -> str:
        return f"{self.imie} {self.nazwisko}"
    
    @property
    def ilosc_wypozyczonych(self) -> int:
        return len(self._wypozyczone)
    
    def dodaj_wypozyczenie(self, kod: str):
        if kod not in self._wypozyczone:
            self._wypozyczone.append(kod)
    
    def usun_wypozyczenie(self, kod: str) -> bool:
        if kod in self._wypozyczone:
            self._wypozyczone.remove(kod)
            return True
        return False
    
    def dodaj_rezerwacje(self, kod: str):
        if kod not in self._zarezerwowane:
            self._zarezerwowane.append(kod)
    
    def usun_rezerwacje(self, kod: str) -> bool:
        if kod in self._zarezerwowane:
            self._zarezerwowane.remove(kod)
            return True
        return False
    
    def to_dict(self) -> dict:
        return {
            'imie': self.imie,
            'nazwisko': self.nazwisko,
            'adres': self.adres,
            'telefon': self.telefon,
            'email': self.email,
            'id_czytelnika': self._id_czytelnika,
            'wypozyczone': self._wypozyczone,
            'zarezerwowane': self._zarezerwowane
        }
    
    @classmethod
    def from_dict(cls, data: dict):
        czyt = cls(
            data['imie'], data['nazwisko'], data['adres'],
            data['telefon'], data.get('email', '')
        )
        czyt._id_czytelnika = data.get('id_czytelnika', 0)
        czyt._wypozyczone = data.get('wypozyczone', [])
        czyt._zarezerwowane = data.get('zarezerwowane', [])
        return czyt


class KolekcjaCzytelnikow:
    """Kolekcja czytelników z iteratorem."""
    
    def __init__(self):
        self._czytelnicy: list[Czytelnik] = []
        self._nastepne_id: int = 1
    
    def dodaj(self, czytelnik: Czytelnik) -> Czytelnik:
        czytelnik._id_czytelnika = self._nastepne_id
        self._nastepne_id += 1
        self._czytelnicy.append(czytelnik)
        return czytelnik
    
    def usun(self, id_czytelnika: int) -> bool:
        for i, c in enumerate(self._czytelnicy):
            if c.id_czytelnika == id_czytelnika:
                self._czytelnicy.pop(i)
                return True
        return False
    
    def znajdz(self, id_czytelnika: int) -> Optional[Czytelnik]:
        for c in self._czytelnicy:
            if c.id_czytelnika == id_czytelnika:
                return c
        return None
    
    def modyfikuj(self, id_czytelnika: int, **kwargs) -> bool:
        czytelnik = self.znajdz(id_czytelnika)
        if not czytelnik:
            return False
        for key, value in kwargs.items():
            if hasattr(czytelnik, key):
                setattr(czytelnik, key, value)
        return True
    
    def __iter__(self):
        return iter(self._czytelnicy)
    
    def __len__(self):
        return len(self._czytelnicy)
    
    def __getitem__(self, indeks: int) -> Czytelnik:
        return self._czytelnicy[indeks]


def dekorator_limit(max_limit: int):
    """Dekorator sprawdzający limit wypożyczeń."""
    def wrapper(func):
        def sprawdz(self, czytelnik_id: int, *args, **kwargs):
            czytelnik = self.czytelnicy.znajdz(czytelnik_id)
            if not czytelnik:
                return "Błąd: Nie znaleziono czytelnika"
            if czytelnik.ilosc_wypozyczonych >= max_limit:
                return f"Błąd: Osiągnięto limit {max_limit} wypożyczeń"
            return func(self, czytelnik, *args, **kwargs)
        return sprawdz
    return wrapper