﻿class Portfel:
    """
    Klasa Portfel reprezentująca stan środków finansowych.
    Demonstruje przeciążanie operatorów arytmetycznych w Pythonie.
    """
    def __init__(self, srodki: float = 0.0):
        # Walidacja początkowych środków
        if srodki < 0:
            raise ValueError("Początkowy stan środków nie może być ujemny.")
        self.srodki = float(srodki)

    def __str__(self) -> str:
        """
        Zwraca czytelny stan portfela sformatowany wraz z walutą.
        """
        return f"Portfel: {self.srodki:.2f} zł"

    def __add__(self, other) -> 'Portfel':
        """
        Przeciążenie operatora dodawania (+).
        Umożliwia dodawanie dwóch portfeli lub kwoty do portfela.
        Zawsze zwraca nową instancję, gwarantując niemutowalność.
        """
        if isinstance(other, Portfel):
            nowa_kwota = self.srodki + other.srodki
        elif isinstance(other, (int, float)):
            nowa_kwota = self.srodki + other
        else:
            # Wyrzucenie wyjątku NotImplemented pozwala na próbę użycia __radd__ u drugiego obiektu
            return NotImplemented
        
        return Portfel(nowa_kwota)
        
    def __radd__(self, other) -> 'Portfel':
        """
        Zapewnia przemienność operacji dodawania. 
        Dzięki tej metodzie działanie '50 + portfel' zadziała bez błędów.
        """
        return self.__add__(other)

    def __sub__(self, other) -> 'Portfel':
        """
        Przeciążenie operatora odejmowania (-).
        Pozwala na odejmowanie portfela lub konkretnej kwoty z zabezpieczeniem
        przed powstaniem debetu (ujemnego salda). Zwraca nową instancję.
        """
        kwota_do_odjecia = 0.0
        if isinstance(other, Portfel):
            kwota_do_odjecia = other.srodki
        elif isinstance(other, (int, float)):
            kwota_do_odjecia = other
        else:
            return NotImplemented
            
        # Sprawdzamy czy na koncie są wystarczające środki
        if self.srodki < kwota_do_odjecia:
            raise ValueError(f"Brak środków. Próba odjęcia {kwota_do_odjecia:.2f} zł, a na koncie jest {self.srodki:.2f} zł.")
            
        return Portfel(self.srodki - kwota_do_odjecia)

if __name__ == "__main__":
    print("--- Tworzenie portfeli ---")
    p1 = Portfel(100)
    p2 = Portfel(50.50)
    print("p1:", p1)
    print("p2:", p2)
    
    print("\n--- Dodawanie portfeli (p3 = p1 + p2) ---")
    p3 = p1 + p2
    print(p3)
    
    print("\n--- Dodawanie liczb i przemienność ---")
    p4 = p3 + 20
    print(f"p3 + 20 = {p4}")
    
    p5 = 10.50 + p4
    print(f"10.50 + p4 = {p5}")
    
    print("\n--- Łańcuchowanie operacji (p1 + p2 - 30) ---")
    p_wynik = p1 + p2 - 30
    print(f"Wynik łańcucha: {p_wynik}")
    
    print("\n--- Testowanie zabezpieczenia przed debetem ---")
    try:
        p_blad = p1 - 200
    except ValueError as e:
        print(f"Złapano błąd (prawidłowo): {e}")

    print("\n--- Testowanie reakcji na nieobsługiwany typ (np. string) ---")
    try:
        p1 + "napis"
    except TypeError as e:
        print(f"Złapano TypeError (prawidłowo): {e}")
