content: package com.nonononoki.alovoa.entity;
  
  import com.fasterxml.jackson.annotation.JsonIgnore;
  import com.nonononoki.alovoa.Tools;
  import com.nonononoki.alovoa.component.TextEncryptorConverter;
  import com.nonononoki.alovoa.config.SecurityConfig;
  import com.nonononoki.alovoa.entity.user.*;
  import jakarta.persistence.*;
  import lombok.*;
  import org.hibernate.annotations.Immutable;
  import org.springframework.security.core.GrantedAuthority;
  import org.springframework.security.core.authority.SimpleGrantedAuthority;
  import org.springframework.security.core.userdetails.UserDetails;
  import org.springframework.stereotype.Component;
  
  import java.io.IOException;
  import java.io.ObjectInputStream;
  import java.io.ObjectOutputStream;
  import java.io.Serial;
  import java.util.*;
  
  @Component
  @Getter
  @Setter
  @Entity
  public class User implements UserDetails {
  
      @Transient
      public static final int UNIT_SI = 0;
      @Transient
      public static final int UNIT_IMPERIAL = 1;
      @Column(nullable = false, unique = true)
      @Convert(converter = TextEncryptorConverter.class)
      @JsonIgnore
      @Immutable
      private final String email;
      @Id
      @GeneratedValue(strategy = GenerationType.IDENTITY)
      private Long id;
      @Column(unique=true)
      private UUID uuid;
      @JsonIgnore
      private String password;
      @Column(updatable = false)
      @Convert(converter = TextEncryptorConverter.class)
      @Immutable
      private String firstName;
      private String description;
      // used for emails
      @JsonIgnore
      private String language;
      @JsonIgnore
      private int units;
      @JsonIgnore
      private int numberReferred;
      @JsonIgnore
      private String referrerCode;
      @JsonIgnore
      private String verificationCode;
      @JsonIgnore
      private boolean showZodiac;
      private int preferedMinAge;
      private int preferedMaxAge;
      @JsonIgnore
      private Double locationLatitude;
      @JsonIgnore
      private Double locationLongitude;
      private double totalDonations;
      @JsonIgnore
      private boolean admin;
      @JsonIgnore
      private boolean confirmed;
      @JsonIgnore
      private boolean disabled;
      @JsonIgnore
      private String country;
      @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true)
      @JoinColumn
      @JsonIgnore
      private UserRegisterToken registerToken;
      @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true)
      @JoinColumn
      @JsonIgnore
      private UserPasswordToken passwordToken;
      @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true)
      @JoinColumn
      @JsonIgnore
      private UserDeleteToken deleteToken;
      @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true)
      @JoinColumn
      @JsonIgnore
      private UserDates dates;
      @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
      @JoinColumn
      private UserAudio audio;
      @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
      @JoinColumn
      private UserProfilePicture profilePicture;
      @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
      @JoinColumn
      private UserVerificationPicture verificationPicture;
  
      // Tables with multiple users
      @ManyToOne
      private Gender gender;
      @ManyToMany
      @JoinTable(name = "user2genders")
      private Set<Gender> preferedGenders;
      @ManyToMany
      private Set<UserMiscInfo> miscInfos;
      @ManyToOne
      private UserIntention intention;
      @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "user")
      private List<UserInterest> interests;
      @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "user")
      private List<UserPrompt> prompts;
      @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "user")
      private List<UserImage> images;
      @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "user")
      @JsonIgnore
      private List<UserDonation> donations;
      @OneToMany(cascade = CascadeType.PERSIST, orphanRemoval = true, mappedBy = "userFrom")
      @JsonIgnore
      private List<Message> messageSent;
      @OneToMany(orphanRemoval = true, mappedBy = "userTo")
      @JsonIgnore
      private List<Message> messageReceived;
      @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.REMOVE}, mappedBy = "users")
      @JsonIgnore
      private List<Conversation> conversations;
      @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "userFrom")
      @JsonIgnore
      private List<UserLike> likes;
      @OneToMany(orphanRemoval = true, mappedBy = "userTo")
      @JsonIgnore
      private List<UserLike> likedBy;
      @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "userTo")
      @JsonIgnore
      private List<UserNotification> notifications;
      @OneToMany(orphanRemoval = true, mappedBy = "userFrom")
      @JsonIgnore
      private List<UserNotification> notificationsFrom;
      @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "userFrom")
      private List<UserHide> hiddenUsers;
      @OneToMany(orphanRemoval = true, mappedBy = "userTo")
      @JsonIgnore
      private List<UserHide> hiddenByUsers;
      @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "userFrom")
      @JsonIgnore
      private List<UserBlock> blockedUsers;
      @OneToMany(orphanRemoval = true, mappedBy = "userTo")
      @JsonIgnore
      private List<UserBlock> blockedByUsers;
      @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "userFrom")
      @JsonIgnore
      private List<UserReport> reported;
      @OneToMany(orphanRemoval = true, mappedBy = "userTo")
      @JsonIgnore
      private List<UserReport> reportedByUsers;
      @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.REMOVE})
      @JoinTable
      @JsonIgnore
      private List<UserVerificationPicture> verificationNo;
      @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.REMOVE})
      @JoinTable
      @JsonIgnore
      private List<UserVerificationPicture> verificationYes;
      @OneToOne(cascade = CascadeType.ALL, orphanRemoval = true)
      private UserSettings userSettings;
  
      @Deprecated
      public User() {
          email = null;
      }
  
      public User(String email) {
          this.email = email;
      }
  
      @Override
      public Collection<? extends GrantedAuthority> getAuthorities() {
          List<GrantedAuthority> authorities = new ArrayList<>();
          String role;
          if (admin) {
              role = SecurityConfig.getRoleAdmin();
          } else {
              role = SecurityConfig.getRoleUser();
          }
          authorities.add(new SimpleGrantedAuthority(role));
  
          return authorities;
      }
  
      @Override
      public String getUsername() {
          return email;
      }
  
      @Override
      public boolean isAccountNonExpired() {
          return !disabled;
      }
  
      @Override
      public boolean isAccountNonLocked() {
          return !disabled;
      }
  
      @Override
      public boolean isCredentialsNonExpired() {
          return !disabled;
      }
  
      @Override
      public boolean isEnabled() {
          return !disabled;
      }
  
      public UserSettings getUserSettings() {
          return Objects.requireNonNullElseGet(userSettings, () -> new UserSettings(this));
      }
  
      public int getPreferedMinAge() {
          try {
              return Tools.convertPrefAgeToExactYear(this.getDates().getDateOfBirth(), preferedMinAge);
          } catch (Exception e) {
              return 0;
          }
      }
  
      public void setPreferedMinAge(int preferedMinAge) {
          try {
              this.preferedMinAge = Tools.convertPrefAgeToRelativeYear(this.getDates().getDateOfBirth(), preferedMinAge);
          } catch (Exception ignored) {
          }
      }
  
      public int getPreferedMaxAge() {
          try {
              return Tools.convertPrefAgeToExactYear(this.getDates().getDateOfBirth(), preferedMaxAge);
          } catch (Exception e) {
              return 0;
          }
      }
  
      public void setPreferedMaxAge(int preferedMaxAge) {
          try {
              this.preferedMaxAge = Tools.convertPrefAgeToRelativeYear(this.getDates().getDateOfBirth(), preferedMaxAge);
          } catch (Exception ignored) {
          }
      }
  
      public void setPreferedMinAge(Date dob, int preferedMinAge) {
          this.preferedMinAge = Tools.convertPrefAgeToRelativeYear(dob, preferedMinAge);
      }
  
      public void setPreferedMaxAge(Date dob, int preferedMaxAge) {
          this.preferedMaxAge = Tools.convertPrefAgeToRelativeYear(dob, preferedMaxAge);
      }
  
      @Serial
      private void writeObject(ObjectOutputStream out) throws IOException {
          throw new IOException();
      }
  
      @Serial
      private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
          throw new IOException();
      }
  
  }
  