﻿# Rozwiązanie zadania 2: Bezpieczne saldo konta (Zmienne chronione _)
# Używamy języka angielskiego w kodzie, ale polskich komentarzy z szerokimi wyjaśnieniami dla studenta.

class Account:
    """
    Klasa reprezentująca konto bankowe.
    Pokazuje, jak zablokować możliwość bezpośredniej zmiany atrybutu poprzez odrzucenie settera.
    Zmiany wartości są dozwolone jedynie przy użyciu odpowiednich biznesowych metod (wpłata/wypłata).
    """

    def __init__(self, initial_balance=0.0):
        """
        Konstruktor klasy Account.
        Inicjalizuje wewnętrzny atrybut chroniony '_balance'.
        Użycie '_' sugeruje brak bezpośredniego dostępu.
        """
        self._balance = float(initial_balance)

    @property
    def balance(self):
        """
        Getter właściwości 'balance'.
        Zwraca wartość na koncie. Zauważ, że brakuje tu odpowiednika @balance.setter.
        Dzięki temu z zewnątrz można jedynie odczytać stan konta: np. print(konto.balance),
        ale nie da się zrobić: konto.balance = 500. Zabezpiecza to przed dowolną 
        niekontrolowaną zmianą kluczowych dla nas danych finansowych.
        """
        return self._balance

    def deposit(self, amount):
        """
        Metoda służąca do wpłaty środków na konto (biznesowy sposób modyfikacji salda).
        Zabezpiecza przed wpłatą kwot mniejszych lub równych zero.
        """
        if amount > 0:
            # Tu możemy bezpiecznie modyfikować zmienną _balance, bo operujemy we wnętrzu klasy
            self._balance += amount
            print(f"Deposited: {amount}. Current balance: {self.balance}")
        else:
            print("Error: Deposit amount must be positive.")

    def withdraw(self, amount):
        """
        Metoda służąca do wypłaty środków z konta.
        Zabezpiecza przed sytuacją wypłacenia więcej niż mamy (debet) lub kwoty ujemnej.
        """
        if amount <= 0:
            print("Error: Withdrawal amount must be positive.")
        elif amount <= self._balance:
            # Ponownie: tylko tu dochodzi do zmiany stanu _balance
            self._balance -= amount
            print(f"Withdrawn: {amount}. Current balance: {self.balance}")
        else:
            print("Error: Insufficient funds!")

# Blok testowy klasy
if __name__ == '__main__':
    print("--- Utworzenie konta i sprawdzenie salda ---")
    account = Account(100.0)
    # Własciwość zadziała jak zwykły atrybut (bez nawiasów)
    print(f"Początkowe saldo: {account.balance}")

    print("\n--- Próba nieautoryzowanej zmiany salda ---")
    try:
        # Ta linijka wywoła AttributeError, ponieważ nie zdefiniowaliśmy settera @balance.setter
        account.balance = 5000.0
    except AttributeError as e:
        print(f"AttributeError przechwycony! Zgodnie z planem nie można nadpisać salda:")
        print(f"Komunikat błędu: {e}")

    print("\n--- Poprawne operacje na koncie ---")
    account.deposit(50.0)      # Wpłata
    account.withdraw(20.0)     # Wypłata
    account.withdraw(500.0)    # Próba wypłaty ponad stan (brak środków)

    print("\n--- Sprawdzenie integralności danych ---")
    # Zmiana salda mogła nastąpić tylko poprzez zatwierdzone metody
    print(f"Końcowe saldo: {account.balance}")
