package com.social.media.domain.user.aggregate;

import com.social.media.domain.user.valueobject.*;
import com.social.media.domain.company.valueobject.CompanyId;
import com.social.media.domain.shared.valueobject.Email;
import com.social.media.domain.shared.valueobject.Phone;
import com.social.media.domain.shared.enums.UserType;
import com.social.media.domain.shared.enums.UserStatus;

import java.time.LocalDateTime;
import java.util.Objects;

/**
 * User Aggregate Root
 * Represents a system user with authentication and authorization
 */
public class User {
    
    private UserId id;
    private CompanyId companyId;
    private String name;
    private Email email;
    private Cpf cpf;
    private Phone phone;
    private boolean whatsappEnabled;
    private String passwordHash;
    private String avatarUrl;
    private String position;
    private String department;
    private LocalDateTime registrationDate;
    private LocalDateTime lastAccessDate;
    private UserStatus status;
    private UserType type;
    private UserPermissions permissions;
    private boolean emailVerified;
    private String verificationToken;
    private String passwordResetToken;
    private LocalDateTime passwordResetExpiry;
    private UserId parentUserId;
    private UserConfiguration configuration;
    private boolean deleted;
    private LocalDateTime createdAt;
    private LocalDateTime updatedAt;
    
    // Private constructor for builder pattern
    private User() {}
    
    /**
     * Creates a new user (factory method)
     */
    public static User create(String name, Email email, String passwordHash, 
                            UserType type, CompanyId companyId) {
        User user = new User();
        user.name = validateName(name);
        user.email = Objects.requireNonNull(email, "Email cannot be null");
        user.passwordHash = Objects.requireNonNull(passwordHash, "Password hash cannot be null");
        user.type = Objects.requireNonNull(type, "User type cannot be null");
        user.companyId = companyId;
        user.status = UserStatus.PENDING;
        user.permissions = UserPermissions.empty();
        user.configuration = UserConfiguration.defaultConfig();
        user.whatsappEnabled = false;
        user.emailVerified = false;
        user.registrationDate = LocalDateTime.now();
        user.deleted = false;
        user.createdAt = LocalDateTime.now();
        user.updatedAt = LocalDateTime.now();
        
        return user;
    }
    
    /**
     * Reconstructs user from persistence (for repository)
     */
    public static User reconstruct(UserId id, CompanyId companyId, String name, Email email,
                                 Cpf cpf, Phone phone, boolean whatsappEnabled, String passwordHash,
                                 String avatarUrl, String position, String department,
                                 LocalDateTime registrationDate, LocalDateTime lastAccessDate,
                                 UserStatus status, UserType type, UserPermissions permissions,
                                 boolean emailVerified, String verificationToken, String passwordResetToken,
                                 LocalDateTime passwordResetExpiry, UserId parentUserId,
                                 UserConfiguration configuration, boolean deleted,
                                 LocalDateTime createdAt, LocalDateTime updatedAt) {
        User user = new User();
        user.id = id;
        user.companyId = companyId;
        user.name = name;
        user.email = email;
        user.cpf = cpf;
        user.phone = phone;
        user.whatsappEnabled = whatsappEnabled;
        user.passwordHash = passwordHash;
        user.avatarUrl = avatarUrl;
        user.position = position;
        user.department = department;
        user.registrationDate = registrationDate;
        user.lastAccessDate = lastAccessDate;
        user.status = status;
        user.type = type;
        user.permissions = permissions;
        user.emailVerified = emailVerified;
        user.verificationToken = verificationToken;
        user.passwordResetToken = passwordResetToken;
        user.passwordResetExpiry = passwordResetExpiry;
        user.parentUserId = parentUserId;
        user.configuration = configuration;
        user.deleted = deleted;
        user.createdAt = createdAt;
        user.updatedAt = updatedAt;
        
        return user;
    }
    
    // Business Methods
    
    public void activate() {
        if (deleted) {
            throw new UserDomainException("Cannot activate deleted user");
        }
        if (!status.canBeActivated()) {
            throw new UserDomainException("User cannot be activated from current status: " + status);
        }
        this.status = UserStatus.ACTIVE;
        this.updatedAt = LocalDateTime.now();
    }
    
    public void suspend() {
        if (deleted) {
            throw new UserDomainException("Cannot suspend deleted user");
        }
        if (!status.canBeSuspended()) {
            throw new UserDomainException("User cannot be suspended from current status: " + status);
        }
        this.status = UserStatus.SUSPENDED;
        this.updatedAt = LocalDateTime.now();
    }
    
    public void deactivate() {
        this.status = UserStatus.INACTIVE;
        this.updatedAt = LocalDateTime.now();
    }
    
    public void updateProfile(String name, Phone phone, String position, String department) {
        this.name = validateName(name);
        this.phone = phone;
        this.position = position;
        this.department = department;
        this.updatedAt = LocalDateTime.now();
    }
    
    public void changePassword(String newPasswordHash) {
        this.passwordHash = Objects.requireNonNull(newPasswordHash, "Password hash cannot be null");
        this.passwordResetToken = null;
        this.passwordResetExpiry = null;
        this.updatedAt = LocalDateTime.now();
    }
    
    public void verifyEmail() {
        this.emailVerified = true;
        this.verificationToken = null;
        if (status == UserStatus.PENDING) {
            this.status = UserStatus.ACTIVE;
        }
        this.updatedAt = LocalDateTime.now();
    }
    
    public void setPasswordResetToken(String token, LocalDateTime expiry) {
        this.passwordResetToken = token;
        this.passwordResetExpiry = expiry;
        this.updatedAt = LocalDateTime.now();
    }
    
    public void updateLastAccess() {
        this.lastAccessDate = LocalDateTime.now();
        this.updatedAt = LocalDateTime.now();
    }
    
    public void updatePermissions(UserPermissions permissions) {
        this.permissions = Objects.requireNonNull(permissions, "Permissions cannot be null");
        this.updatedAt = LocalDateTime.now();
    }
    
    public void updateConfiguration(UserConfiguration configuration) {
        this.configuration = Objects.requireNonNull(configuration, "Configuration cannot be null");
        this.updatedAt = LocalDateTime.now();
    }
    
    public void setAvatar(String avatarUrl) {
        this.avatarUrl = avatarUrl;
        this.updatedAt = LocalDateTime.now();
    }
    
    public void setCpf(Cpf cpf) {
        this.cpf = cpf;
        this.updatedAt = LocalDateTime.now();
    }
    
    public void enableWhatsapp() {
        this.whatsappEnabled = true;
        this.updatedAt = LocalDateTime.now();
    }
    
    public void disableWhatsapp() {
        this.whatsappEnabled = false;
        this.updatedAt = LocalDateTime.now();
    }
    
    public void softDelete() {
        this.deleted = true;
        this.status = UserStatus.INACTIVE;
        this.updatedAt = LocalDateTime.now();
    }
    
    /**
     * Restores a logically deleted user
     */
    public void restore() {
        this.deleted = false;
        this.status = UserStatus.ACTIVE;
        this.updatedAt = LocalDateTime.now();
    }
    
    public boolean canLogin() {
        return !deleted && status.canLogin() && emailVerified;
    }
    
    public boolean isPasswordResetTokenValid() {
        return passwordResetToken != null && 
               passwordResetExpiry != null && 
               passwordResetExpiry.isAfter(LocalDateTime.now());
    }
    
    public boolean hasPermission(String permission) {
        return permissions.hasPermission(permission);
    }
    
    public boolean canManageUser(User otherUser) {
        return type.canManageUser(otherUser.type) && 
               Objects.equals(companyId, otherUser.companyId);
    }
    
    public boolean belongsToCompany(CompanyId companyId) {
        return Objects.equals(this.companyId, companyId);
    }
    
    // Validation methods
    
    private static String validateName(String name) {
        if (name == null || name.trim().isEmpty()) {
            throw new UserDomainException("User name cannot be null or empty");
        }
        if (name.trim().length() < 2) {
            throw new UserDomainException("User name must have at least 2 characters");
        }
        if (name.trim().length() > 100) {
            throw new UserDomainException("User name must not exceed 100 characters");
        }
        return name.trim();
    }
    
    // Getters
    
    public UserId getId() { return id; }
    public CompanyId getCompanyId() { return companyId; }
    public String getName() { return name; }
    public Email getEmail() { return email; }
    public Cpf getCpf() { return cpf; }
    public Phone getPhone() { return phone; }
    public boolean isWhatsappEnabled() { return whatsappEnabled; }
    public String getPasswordHash() { return passwordHash; }
    public String getAvatarUrl() { return avatarUrl; }
    public String getPosition() { return position; }
    public String getDepartment() { return department; }
    public LocalDateTime getRegistrationDate() { return registrationDate; }
    public LocalDateTime getLastAccessDate() { return lastAccessDate; }
    public UserStatus getStatus() { return status; }
    public UserType getType() { return type; }
    public UserPermissions getPermissions() { return permissions; }
    public boolean isEmailVerified() { return emailVerified; }
    public String getVerificationToken() { return verificationToken; }
    public String getPasswordResetToken() { return passwordResetToken; }
    public LocalDateTime getPasswordResetExpiry() { return passwordResetExpiry; }
    public UserId getParentUserId() { return parentUserId; }
    public UserConfiguration getConfiguration() { return configuration; }
    public boolean isDeleted() { return deleted; }
    public LocalDateTime getCreatedAt() { return createdAt; }
    public LocalDateTime getUpdatedAt() { return updatedAt; }
    
    // Setters for reconstruction only
    void setId(UserId id) { this.id = id; }
    void setVerificationToken(String verificationToken) { this.verificationToken = verificationToken; }
    void setParentUserId(UserId parentUserId) { this.parentUserId = parentUserId; }
    
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        return Objects.equals(id, user.id);
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(id);
    }
    
    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", email=" + email +
                ", type=" + type +
                ", status=" + status +
                '}';
    }
    
    /**
     * Domain exception specific to User aggregate
     */
    public static class UserDomainException extends RuntimeException {
        public UserDomainException(String message) {
            super(message);
        }
    }
}
