package com.social.media.domain.socialaccount;

import com.social.media.domain.shared.BaseEntity;
import com.social.media.domain.shared.enums.SocialPlatform;

import java.time.LocalDateTime;
import java.util.UUID;
import java.util.Objects;

/**
 * Social Account aggregate root representing a connected social media account.
 * Manages the connection, authentication, and metadata for a specific social platform account.
 */
public class SocialAccount extends BaseEntity {
    
    private UUID companyId;
    private UUID userId;
    private UUID socialNetworkId;
    private SocialPlatform platform;
    private String platformAccountId;
    private String username;
    private String displayName;
    private String email;
    private String profilePictureUrl;
    private String profileUrl;
    private String bio;
    private String location;
    private String website;
    private String phoneNumber;
    private String businessCategory;
    private boolean isBusinessAccount;
    private boolean isVerified;
    private boolean isActive;
    private AuthTokens authTokens;
    private ConnectionStatus connectionStatus;
    private AccountMetrics metrics;
    private LocalDateTime lastSyncAt;
    private LocalDateTime connectedAt;
    private String timeZone;
    private String language;
    private String currency;
    
    // Default constructor for JPA
    protected SocialAccount() {
        super();
    }
    
    public SocialAccount(
            UUID companyId,
            UUID userId,
            UUID socialNetworkId,
            SocialPlatform platform,
            String platformAccountId,
            String username,
            String displayName,
            String email,
            AuthTokens authTokens) {
        
        super();
        this.companyId = validateCompanyId(companyId);
        this.userId = validateUserId(userId);
        this.socialNetworkId = validateSocialNetworkId(socialNetworkId);
        this.platform = validatePlatform(platform);
        this.platformAccountId = validatePlatformAccountId(platformAccountId);
        this.username = validateUsername(username);
        this.displayName = validateDisplayName(displayName);
        this.email = email; // Optional
        this.authTokens = validateAuthTokens(authTokens);
        this.connectionStatus = ConnectionStatus.connected();
        this.metrics = AccountMetrics.empty();
        this.isActive = true;
        this.isBusinessAccount = false;
        this.isVerified = false;
        this.connectedAt = LocalDateTime.now();
        this.lastSyncAt = LocalDateTime.now();
    }
    
    // Validation methods
    private UUID validateCompanyId(UUID companyId) {
        if (companyId == null) {
            throw new IllegalArgumentException("Company ID cannot be null");
        }
        return companyId;
    }
    
    private UUID validateUserId(UUID userId) {
        if (userId == null) {
            throw new IllegalArgumentException("User ID cannot be null");
        }
        return userId;
    }
    
    private UUID validateSocialNetworkId(UUID socialNetworkId) {
        if (socialNetworkId == null) {
            throw new IllegalArgumentException("Social Network ID cannot be null");
        }
        return socialNetworkId;
    }
    
    private SocialPlatform validatePlatform(SocialPlatform platform) {
        if (platform == null) {
            throw new IllegalArgumentException("Platform cannot be null");
        }
        return platform;
    }
    
    private String validatePlatformAccountId(String platformAccountId) {
        if (platformAccountId == null || platformAccountId.trim().isEmpty()) {
            throw new IllegalArgumentException("Platform account ID cannot be null or empty");
        }
        if (platformAccountId.length() > 100) {
            throw new IllegalArgumentException("Platform account ID cannot exceed 100 characters");
        }
        return platformAccountId.trim();
    }
    
    private String validateUsername(String username) {
        if (username == null || username.trim().isEmpty()) {
            throw new IllegalArgumentException("Username cannot be null or empty");
        }
        if (username.length() > 100) {
            throw new IllegalArgumentException("Username cannot exceed 100 characters");
        }
        return username.trim();
    }
    
    private String validateDisplayName(String displayName) {
        if (displayName == null || displayName.trim().isEmpty()) {
            throw new IllegalArgumentException("Display name cannot be null or empty");
        }
        if (displayName.length() > 150) {
            throw new IllegalArgumentException("Display name cannot exceed 150 characters");
        }
        return displayName.trim();
    }
    
    private AuthTokens validateAuthTokens(AuthTokens authTokens) {
        if (authTokens == null) {
            throw new IllegalArgumentException("Auth tokens cannot be null");
        }
        return authTokens;
    }
    
    // Business methods
    
    /**
     * Updates the authentication tokens.
     */
    public void updateAuthTokens(AuthTokens newTokens) {
        AuthTokens validatedTokens = validateAuthTokens(newTokens);
        if (!this.authTokens.equals(validatedTokens)) {
            this.authTokens = validatedTokens;
            this.connectionStatus = ConnectionStatus.connected();
            this.lastSyncAt = LocalDateTime.now();
            this.markAsModified();
        }
    }
    
    /**
     * Updates the connection status.
     */
    public void updateConnectionStatus(ConnectionStatus newStatus) {
        if (newStatus == null) {
            throw new IllegalArgumentException("Connection status cannot be null");
        }
        
        if (!this.connectionStatus.equals(newStatus)) {
            this.connectionStatus = newStatus;
            this.lastSyncAt = LocalDateTime.now();
            this.markAsModified();
        }
    }
    
    /**
     * Updates the account metrics.
     */
    public void updateMetrics(AccountMetrics newMetrics) {
        if (newMetrics == null) {
            throw new IllegalArgumentException("Account metrics cannot be null");
        }
        
        if (!this.metrics.equals(newMetrics)) {
            this.metrics = newMetrics;
            this.lastSyncAt = LocalDateTime.now();
            this.markAsModified();
        }
    }
    
    /**
     * Updates the profile information.
     */
    public void updateProfile(
            String displayName,
            String bio,
            String location,
            String website,
            String profilePictureUrl) {
        
        boolean changed = false;
        
        if (displayName != null && !displayName.equals(this.displayName)) {
            this.displayName = validateDisplayName(displayName);
            changed = true;
        }
        
        if (bio != null && !bio.equals(this.bio)) {
            if (bio.length() > 500) {
                throw new IllegalArgumentException("Bio cannot exceed 500 characters");
            }
            this.bio = bio.trim();
            changed = true;
        }
        
        if (location != null && !location.equals(this.location)) {
            if (location.length() > 100) {
                throw new IllegalArgumentException("Location cannot exceed 100 characters");
            }
            this.location = location.trim();
            changed = true;
        }
        
        if (website != null && !website.equals(this.website)) {
            if (website.length() > 200) {
                throw new IllegalArgumentException("Website cannot exceed 200 characters");
            }
            this.website = website.trim();
            changed = true;
        }
        
        if (profilePictureUrl != null && !profilePictureUrl.equals(this.profilePictureUrl)) {
            if (profilePictureUrl.length() > 500) {
                throw new IllegalArgumentException("Profile picture URL cannot exceed 500 characters");
            }
            this.profilePictureUrl = profilePictureUrl.trim();
            changed = true;
        }
        
        if (changed) {
            this.lastSyncAt = LocalDateTime.now();
            this.markAsModified();
        }
    }
    
    /**
     * Updates the business account settings.
     */
    public void updateBusinessSettings(
            boolean isBusinessAccount,
            String businessCategory,
            String phoneNumber) {
        
        boolean changed = false;
        
        if (this.isBusinessAccount != isBusinessAccount) {
            this.isBusinessAccount = isBusinessAccount;
            changed = true;
        }
        
        if (businessCategory != null && !businessCategory.equals(this.businessCategory)) {
            if (businessCategory.length() > 100) {
                throw new IllegalArgumentException("Business category cannot exceed 100 characters");
            }
            this.businessCategory = businessCategory.trim();
            changed = true;
        }
        
        if (phoneNumber != null && !phoneNumber.equals(this.phoneNumber)) {
            if (phoneNumber.length() > 20) {
                throw new IllegalArgumentException("Phone number cannot exceed 20 characters");
            }
            this.phoneNumber = phoneNumber.trim();
            changed = true;
        }
        
        if (changed) {
            this.lastSyncAt = LocalDateTime.now();
            this.markAsModified();
        }
    }
    
    /**
     * Activates the account.
     */
    public void activate() {
        if (!isActive) {
            this.isActive = true;
            this.markAsModified();
        }
    }
    
    /**
     * Deactivates the account.
     */
    public void deactivate() {
        if (isActive) {
            this.isActive = false;
            this.markAsModified();
        }
    }
    
    /**
     * Marks the account as verified.
     */
    public void markAsVerified() {
        if (!isVerified) {
            this.isVerified = true;
            this.markAsModified();
        }
    }
    
    /**
     * Disconnects the account by clearing tokens and updating status.
     */
    public void disconnect() {
        this.connectionStatus = ConnectionStatus.disconnected("Account disconnected by user");
        this.isActive = false;
        this.lastSyncAt = LocalDateTime.now();
        this.markAsModified();
    }
    
    /**
     * Reconnects the account with new tokens.
     */
    public void reconnect(AuthTokens newTokens) {
        updateAuthTokens(newTokens);
        this.isActive = true;
        this.connectedAt = LocalDateTime.now();
    }
    
    /**
     * Updates the sync timestamp.
     */
    public void markAsSynced() {
        this.lastSyncAt = LocalDateTime.now();
        this.markAsModified();
    }
    
    /**
     * Handles authentication token expiration.
     */
    public void handleTokenExpiration() {
        this.connectionStatus = ConnectionStatus.expired();
        this.lastSyncAt = LocalDateTime.now();
        this.markAsModified();
    }
    
    /**
     * Handles authentication error.
     */
    public void handleAuthError(String errorMessage, String errorCode) {
        this.connectionStatus = ConnectionStatus.error(errorMessage, errorCode);
        this.lastSyncAt = LocalDateTime.now();
        this.markAsModified();
    }
    
    // Query methods
    
    /**
     * Checks if the account is ready for use.
     */
    public boolean isReady() {
        return isActive && connectionStatus.isReady() && !authTokens.isExpired();
    }
    
    /**
     * Checks if the account needs token refresh.
     */
    public boolean needsTokenRefresh() {
        return authTokens.willExpireWithin(30) && authTokens.canBeRefreshed();
    }
    
    /**
     * Checks if the account requires user attention.
     */
    public boolean requiresUserAttention() {
        return connectionStatus.requiresUserAction() || 
               (authTokens.isExpired() && !authTokens.canBeRefreshed());
    }
    
    /**
     * Checks if the account data is stale.
     */
    public boolean isDataStale(int hours) {
        return lastSyncAt.isBefore(LocalDateTime.now().minusHours(hours));
    }
    
    /**
     * Gets the account health status.
     */
    public String getHealthStatus() {
        if (!isActive) {
            return "INACTIVE";
        }
        if (authTokens.isExpired()) {
            return "EXPIRED";
        }
        if (!connectionStatus.isReady()) {
            return "CONNECTION_ISSUE";
        }
        if (isDataStale(24)) {
            return "STALE";
        }
        return "HEALTHY";
    }
    
    /**
     * Gets a summary of the account.
     */
    public String getAccountSummary() {
        return String.format("%s (@%s) - %s - %s",
            displayName,
            username,
            platform.getDisplayName(),
            metrics.getPerformanceSummary()
        );
    }
    
    // Getters
    public UUID getCompanyId() { return companyId; }
    public UUID getUserId() { return userId; }
    public UUID getSocialNetworkId() { return socialNetworkId; }
    public SocialPlatform getPlatform() { return platform; }
    public String getPlatformAccountId() { return platformAccountId; }
    public String getUsername() { return username; }
    public String getDisplayName() { return displayName; }
    public String getEmail() { return email; }
    public String getProfilePictureUrl() { return profilePictureUrl; }
    public String getProfileUrl() { return profileUrl; }
    public String getBio() { return bio; }
    public String getLocation() { return location; }
    public String getWebsite() { return website; }
    public String getPhoneNumber() { return phoneNumber; }
    public String getBusinessCategory() { return businessCategory; }
    public boolean isBusinessAccount() { return isBusinessAccount; }
    public boolean isVerified() { return isVerified; }
    public boolean isActive() { return isActive; }
    public AuthTokens getAuthTokens() { return authTokens; }
    public ConnectionStatus getConnectionStatus() { return connectionStatus; }
    public AccountMetrics getMetrics() { return metrics; }
    public LocalDateTime getLastSyncAt() { return lastSyncAt; }
    public LocalDateTime getConnectedAt() { return connectedAt; }
    public String getTimeZone() { return timeZone; }
    public String getLanguage() { return language; }
    public String getCurrency() { return currency; }
    
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        if (!super.equals(o)) return false;
        SocialAccount that = (SocialAccount) o;
        return Objects.equals(companyId, that.companyId) &&
               Objects.equals(platformAccountId, that.platformAccountId) &&
               platform == that.platform;
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(super.hashCode(), companyId, platformAccountId, platform);
    }
    
    @Override
    public String toString() {
        return "SocialAccount{" +
               "id=" + getId() +
               ", companyId=" + companyId +
               ", platform=" + platform +
               ", username='" + username + '\'' +
               ", displayName='" + displayName + '\'' +
               ", isActive=" + isActive +
               ", connectionStatus=" + connectionStatus.getStatus() +
               ", connectedAt=" + connectedAt +
               '}';
    }
}
