﻿# Rozwiązanie zadania 1: Ochrona wieku użytkownika (Walidacja przez setter)
# Używamy języka angielskiego w kodzie, ale polskich komentarzy z szerokimi wyjaśnieniami dla studenta.

class User:
    """
    Klasa reprezentująca użytkownika w systemie.
    Demonstruje koncepcję hermetyzacji (enkapsulacji) oraz użycie dekoratora @property 
    do ochrony integralności danych (w tym przypadku wieku użytkownika).
    """

    def __init__(self, age):
        """
        Konstruktor klasy User.
        Zamiast ustawiać wiek bezpośrednio w zmiennej (np. self._age = age), 
        używamy publicznej właściwości 'age', aby zainicjalizować obiekt.
        Dzięki temu nawet przy tworzeniu obiektu wartość przejdzie przez setter z walidacją.
        """
        # Ustawiamy wiek początkowy na 0, aby upewnić się, że istnieje przed użyciem settera.
        self._age = 0
        # Wywołujemy setter dla 'age' (przekazując argument konstruktora)
        self.age = age

    @property
    def age(self):
        """
        Getter właściwości 'age'. 
        Wywoływany zawsze, gdy próbujemy odczytać wiek użytkownika (np. print(u.age)).
        Zwraca wartość wewnętrznego atrybutu chronionego '_age'.
        Pojedyncze podkreślenie przed '_age' to konwencja w Pythonie informująca:
        "Ten atrybut jest wewnętrzny, nie modyfikuj go bezpośrednio!".
        """
        return self._age

    @age.setter
    def age(self, new_value):
        """
        Setter właściwości 'age'.
        Wywoływany zawsze, gdy przypisujemy nową wartość (np. u.age = 25).
        Zapewnia walidację - nie można przypisać użytkownikowi np. wieku ujemnego.
        """
        # Sprawdzamy czy nowa wartość mieści się w akceptowalnym zakresie biologicznych granic
        if 0 <= new_value <= 150:
            self._age = new_value
        else:
            # Informacja o błędzie walidacji bez zatrzymywania działania całego programu 
            # (choć w aplikacjach produkcyjnych użyto by podniesienia wyjątku np. ValueError)
            print("Error: Age must be between 0 and 150!")

# Blok testowy: sprawdzamy, czy nasze zabezpieczenia faktycznie działają.
if __name__ == '__main__':
    print("--- Tworzenie poprawnego użytkownika ---")
    # Tworzymy użytkownika, który na wejściu ma poprawny wiek
    user1 = User(25)
    print(f"Początkowy wiek: {user1.age}")  # Działa getter

    print("\n--- Próba poprawnej zmiany wieku ---")
    user1.age = 30  # Zmiana wartości (działa setter)
    print(f"Wiek po zmianie: {user1.age}")  # Wartość została zaktualizowana do 30

    print("\n--- Próba wprowadzenia wieku ujemnego ---")
    # Ten kod wywoła blok else w naszym setterze i wypisze stosowny komunikat błędu
    user1.age = -5
    
    print("\n--- Próba wprowadzenia zbyt wysokiego wieku ---")
    # Podobnie - ten kod wywoła błąd walidacji
    user1.age = 200

    print("\n--- Sprawdzenie integralności stanu obiektu ---")
    # Zwróć uwagę, że z racji tego, że przypisanie -5 i 200 zakończyło się błędem,
    # w obiekcie powinen zostać stary poprawny wiek (czyli 30)
    print(f"Wiek po błędnych próbach (powinno być 30): {user1.age}")
