using static System.Console;

namespace Biblioteka;

public class Osoba : object, IComparable<Osoba?>
{
  // pola
  public string? Nazwisko; // znak ? pozwala na wartość null
  public DateTime DataUrodzenia;
  public List<Osoba> Dzieci = new(); // C# 9 lub nowsze

  // metody
  public void WypiszWKonsoli()
  {
    WriteLine($"{Nazwisko}, data urodzenia {DataUrodzenia:dddd}.");
  }

  // statyczna metoda "rozmnażania"
  public static Osoba Prokreacja(Osoba o1, Osoba o2)
  {
    Osoba dziecko = new()
    {
      Nazwisko = $"Dziecko osób {o1.Nazwisko} i {o2.Nazwisko}"
    };

    o1.Dzieci.Add(dziecko);
    o2.Dzieci.Add(dziecko);

    return dziecko;
  }

  // "rozmnażająca" metoda obiektu
  public Osoba ProkreacjaZ(Osoba partner)
  {
    return Prokreacja(this, partner);
  }

  // operator "mnożenia"
  public static Osoba operator *(Osoba o1, Osoba o2)
  {
    return Prokreacja(o1, o2);
  }

  // metoda z funkcją lokalną
  public static int Silnia(int liczba)
  {
    if (liczba < 0)
    {
      throw new ArgumentException(
        $"{nameof(liczba)} nie może być mniejsza od zera.");
    }
    return lokalnaSilnia(liczba);

    int lokalnaSilnia(int lokalnaLiczba) // funkcja lokalna
    {
      if (lokalnaLiczba < 1) return 1;
      return lokalnaLiczba * lokalnaSilnia(lokalnaLiczba - 1);
    }
  }

  // zdarzenie
  public event EventHandler? Krzycz;

  // pole
  public int PoziomZlosci;

  // metoda 
  public void Szturchnij()
  {
    PoziomZlosci++;
    if (PoziomZlosci >= 3)
    {
      // jeżeli coś słucha zdarzenia... 
      if (Krzycz != null)
      {
        // ...to wywołaj zdarzenie
        Krzycz(this, EventArgs.Empty);
      }
    }
  }

  public int CompareTo(Osoba? inna)
  {
    if ((this is not null) && (inna is not null))
    {
      if (Nazwisko is null)
      {
        // Jeżeli ta i inna osoba mają wartość null
        // jako nazwisko, to uznajemy je za takie same
        if (inna.Nazwisko is null) return 0;

        // w przeciwnym wypadku ta osoba staje za inną
        return 1;
      }
      else
      {
        if (inna.Nazwisko is null)
        {
          return -1;
        }
      }

      // Jeżeli obie wartości Nazwiska nie są null,
      // to porównujemy je metodą CompareTo z typu string
      return Nazwisko.CompareTo(inna.Nazwisko);
    }
    else if ((this is not null) && (inna is null))
    {
      return -1; // ta osoba przed inną
    }
    else if ((this is null) && (inna is not null))
    {
      return 1; // ta osoba za inną
    }
    else
    {
      return 0; // obie osoby są osobie równe
    }
  }

  // metody pokrywane 
  public override string ToString()
  {
    return $"{Nazwisko} jest {base.ToString()}";
  }

  public void PodrozWCzasie(DateTime kiedy)
  {
    if (kiedy <= DataUrodzenia)
    {
      throw new WyjatekOsoba("Jeżeli przeniesiesz się w czasie do daty wcześniejszej niż Twoja data urodzenia, to cały wszechświat eksploduje!");
    }
      else
    {
      WriteLine($"Witamy w roku {kiedy:yyyy}!");
    }
  }
}
