﻿import functools

# --- DEFINICJA WŁASNEGO DEKORATORA WALIDUJĄCEGO ---
# Dekorator ten ma za zadanie wyłapywać sytuacje, w których wprowadzana
# lub wypłacana kwota jest niepoprawna (np. ujemna), zanim jeszcze faktyczna
# metoda klasy zostanie wykonana. Oddziela to walidację wejścia od logiki biznesowej.
def waliduj_kwote(func):
    @functools.wraps(func)
    def wrapper(self, kwota, *args, **kwargs):
        if kwota <= 0:
            print(f"Błąd operacji '{func.__name__}': Kwota musi być wartością dodatnią!")
            return
        return func(self, kwota, *args, **kwargs)
    return wrapper


class KontoBankowe:
    """
    Klasa obsługująca bezpieczeństwo finansowe operacji bankowych użytkownika.
    Prezentuje wykorzystanie prywatnych atrybutów oraz dedykowanych dekoratorów biznesowych.
    """
    def __init__(self, wlasciciel: str, saldo_poczatkowe: float):
        self.wlasciciel = wlasciciel
        # Saldo jest atrybutem "prywatnym" - w Pythonie oznaczanym pojedynczym podkreśleniem.
        # Informujemy innych programistów, że tego pola nie należy modyfikować bezpośrednio.
        self._saldo = saldo_poczatkowe

    # @property daje bezpieczny wgląd (tylko do odczytu) na atrybut _saldo.
    # Brak settera sprawia, że nie można zrobić konto.saldo = 1000000 z zewnątrz.
    @property
    def saldo(self) -> float:
        """Odczytuje aktualny stan środków na koncie."""
        return self._saldo

    # Dekorator uruchamia się przed właściwą metodą 'wplata'.
    @waliduj_kwote
    def wplata(self, kwota: float):
        """Metoda zwiększająca bezpiecznie stan konta bankowego."""
        self._saldo += kwota
        # Zgodnie z wymaganiami moglibyśmy tu informować o wpłacie, ale polecenia tego jawnie nie wymagają,
        # jednak w odpowiedzi na "natychmiastową aktualizację stanu" wypiszmy potwierdzenie.
        print(f"Wpłacono: {kwota}. Saldo: {self.saldo}")

    # Dekorator najpierw upewni się, że kwota wypłaty jest dodatnia.
    @waliduj_kwote
    def wyplata(self, kwota: float):
        """Metoda wypłacająca środki, o ile nie spowoduje to debetu."""
        if kwota <= self._saldo:
            self._saldo -= kwota
            print(f"Operacja pomyślna. Saldo: {self.saldo}")
        else:
            # Reagujemy na próbę utworzenia debetu
            print("Błąd: Niewystarczające środki.")

    def sprawdz_saldo(self):
        """Wyświetla szybki podgląd konta."""
        print(f"Konto użytkownika '{self.wlasciciel}'. Saldo: {self.saldo}")


if __name__ == "__main__":
    print("--- ZADANIE 03 ---")
    moje_konto = KontoBankowe("Jan Kowalski", 1000)
    
    # Symulacja standardowych operacji
    moje_konto.wplata(500)
    moje_konto.wyplata(2000) # Tu zadziała logika chroniąca przed debetem
    moje_konto.wyplata(300)  # Pomyślna wypłata
    
    # Próby oszukania systemu przechwytywane przez dekorator walidujący @waliduj_kwote
    print("\n[Eksperyment] Próba wpłaty/wypłaty ujemnych kwot:")
    moje_konto.wplata(-50)
    moje_konto.wyplata(-1000)
