package com.social.media.domain.socialaccount;

import com.social.media.domain.shared.BaseValueObject;

import java.time.LocalDateTime;
import java.util.Objects;

/**
 * Value object representing metrics and statistics for a social media account.
 * Tracks follower counts, engagement rates, and other performance indicators.
 */
public final class AccountMetrics extends BaseValueObject {
    
    private final Long followersCount;
    private final Long followingCount;
    private final Long postsCount;
    private final Long likesCount;
    private final Long commentsCount;
    private final Long sharesCount;
    private final Long impressionsCount;
    private final Long reachCount;
    private final Double engagementRate;
    private final Double growthRate;
    private final LocalDateTime lastUpdated;
    private final String profileViews;
    private final String websiteClicks;
    private final String emailClicks;
    private final String phoneClicks;
    private final String directionsClicks;
    private final Long storiesViews;
    private final Long reelsViews;
    private final Long videosViews;
    
    public AccountMetrics(
            Long followersCount,
            Long followingCount,
            Long postsCount,
            Long likesCount,
            Long commentsCount,
            Long sharesCount,
            Long impressionsCount,
            Long reachCount,
            Double engagementRate,
            Double growthRate,
            LocalDateTime lastUpdated,
            String profileViews,
            String websiteClicks,
            String emailClicks,
            String phoneClicks,
            String directionsClicks,
            Long storiesViews,
            Long reelsViews,
            Long videosViews) {
        
        this.followersCount = validateCount(followersCount, "followersCount");
        this.followingCount = validateCount(followingCount, "followingCount");
        this.postsCount = validateCount(postsCount, "postsCount");
        this.likesCount = validateCount(likesCount, "likesCount");
        this.commentsCount = validateCount(commentsCount, "commentsCount");
        this.sharesCount = validateCount(sharesCount, "sharesCount");
        this.impressionsCount = validateCount(impressionsCount, "impressionsCount");
        this.reachCount = validateCount(reachCount, "reachCount");
        this.engagementRate = validateRate(engagementRate, "engagementRate");
        this.growthRate = growthRate; // Can be negative
        this.lastUpdated = lastUpdated != null ? lastUpdated : LocalDateTime.now();
        this.profileViews = profileViews;
        this.websiteClicks = websiteClicks;
        this.emailClicks = emailClicks;
        this.phoneClicks = phoneClicks;
        this.directionsClicks = directionsClicks;
        this.storiesViews = validateCount(storiesViews, "storiesViews");
        this.reelsViews = validateCount(reelsViews, "reelsViews");
        this.videosViews = validateCount(videosViews, "videosViews");
        
        validate();
    }
    
    private Long validateCount(Long count, String fieldName) {
        if (count != null && count < 0) {
            throw new IllegalArgumentException(fieldName + " cannot be negative");
        }
        return count;
    }
    
    private Double validateRate(Double rate, String fieldName) {
        if (rate != null && (rate < 0.0 || rate > 100.0)) {
            throw new IllegalArgumentException(fieldName + " must be between 0 and 100");
        }
        return rate;
    }
    
    @Override
    public void validate() {
        // Reach should not exceed impressions
        if (reachCount != null && impressionsCount != null && reachCount > impressionsCount) {
            throw new IllegalArgumentException("Reach count cannot exceed impressions count");
        }
        
        // Following count should be reasonable compared to followers
        if (followersCount != null && followingCount != null && 
            followersCount > 0 && followingCount > followersCount * 10) {
            // This is a warning, not a strict rule, but suspicious
        }
        
        // Engagement rate should make sense with the follower count
        if (engagementRate != null && followersCount != null && 
            followersCount > 1000 && engagementRate > 20.0) {
            // High engagement rate for large accounts might be suspicious
        }
    }
    
    /**
     * Creates empty metrics for a new account.
     */
    public static AccountMetrics empty() {
        return new AccountMetrics(
            0L, 0L, 0L, 0L, 0L, 0L, 0L, 0L,
            0.0, 0.0, LocalDateTime.now(),
            null, null, null, null, null,
            0L, 0L, 0L
        );
    }
    
    /**
     * Creates metrics with basic follower data.
     */
    public static AccountMetrics withBasicData(
            Long followersCount, 
            Long followingCount, 
            Long postsCount) {
        return new AccountMetrics(
            followersCount, followingCount, postsCount,
            null, null, null, null, null,
            null, null, LocalDateTime.now(),
            null, null, null, null, null,
            null, null, null
        );
    }
    
    /**
     * Updates the metrics with new data.
     */
    public AccountMetrics withUpdatedCounts(
            Long newFollowersCount,
            Long newFollowingCount,
            Long newPostsCount) {
        
        Double newGrowthRate = calculateGrowthRate(newFollowersCount);
        
        return new AccountMetrics(
            newFollowersCount,
            newFollowingCount,
            newPostsCount,
            likesCount,
            commentsCount,
            sharesCount,
            impressionsCount,
            reachCount,
            engagementRate,
            newGrowthRate,
            LocalDateTime.now(),
            profileViews,
            websiteClicks,
            emailClicks,
            phoneClicks,
            directionsClicks,
            storiesViews,
            reelsViews,
            videosViews
        );
    }
    
    /**
     * Updates engagement metrics.
     */
    public AccountMetrics withEngagementData(
            Long newLikesCount,
            Long newCommentsCount,
            Long newSharesCount,
            Long newImpressionsCount,
            Long newReachCount) {
        
        Double newEngagementRate = calculateEngagementRate(
            newLikesCount, newCommentsCount, newSharesCount, followersCount);
        
        return new AccountMetrics(
            followersCount,
            followingCount,
            postsCount,
            newLikesCount,
            newCommentsCount,
            newSharesCount,
            newImpressionsCount,
            newReachCount,
            newEngagementRate,
            growthRate,
            LocalDateTime.now(),
            profileViews,
            websiteClicks,
            emailClicks,
            phoneClicks,
            directionsClicks,
            storiesViews,
            reelsViews,
            videosViews
        );
    }
    
    /**
     * Updates story and video metrics.
     */
    public AccountMetrics withContentMetrics(
            Long newStoriesViews,
            Long newReelsViews,
            Long newVideosViews) {
        
        return new AccountMetrics(
            followersCount,
            followingCount,
            postsCount,
            likesCount,
            commentsCount,
            sharesCount,
            impressionsCount,
            reachCount,
            engagementRate,
            growthRate,
            LocalDateTime.now(),
            profileViews,
            websiteClicks,
            emailClicks,
            phoneClicks,
            directionsClicks,
            newStoriesViews,
            newReelsViews,
            newVideosViews
        );
    }
    
    /**
     * Calculates growth rate based on follower change.
     */
    private Double calculateGrowthRate(Long newFollowersCount) {
        if (followersCount == null || newFollowersCount == null || followersCount == 0) {
            return 0.0;
        }
        
        double growth = ((double) (newFollowersCount - followersCount) / followersCount) * 100;
        return Math.round(growth * 100.0) / 100.0; // Round to 2 decimal places
    }
    
    /**
     * Calculates engagement rate.
     */
    private Double calculateEngagementRate(Long likes, Long comments, Long shares, Long followers) {
        if (followers == null || followers == 0 || 
            (likes == null && comments == null && shares == null)) {
            return 0.0;
        }
        
        long totalEngagement = (likes != null ? likes : 0) +
                              (comments != null ? comments : 0) +
                              (shares != null ? shares : 0);
        
        double rate = ((double) totalEngagement / followers) * 100;
        return Math.round(rate * 100.0) / 100.0; // Round to 2 decimal places
    }
    
    /**
     * Gets the follower-to-following ratio.
     */
    public Double getFollowerToFollowingRatio() {
        if (followingCount == null || followingCount == 0) {
            return null;
        }
        if (followersCount == null) {
            return 0.0;
        }
        
        double ratio = (double) followersCount / followingCount;
        return Math.round(ratio * 100.0) / 100.0;
    }
    
    /**
     * Gets the average likes per post.
     */
    public Double getAverageLikesPerPost() {
        if (postsCount == null || postsCount == 0 || likesCount == null) {
            return 0.0;
        }
        
        double average = (double) likesCount / postsCount;
        return Math.round(average * 100.0) / 100.0;
    }
    
    /**
     * Gets the average comments per post.
     */
    public Double getAverageCommentsPerPost() {
        if (postsCount == null || postsCount == 0 || commentsCount == null) {
            return 0.0;
        }
        
        double average = (double) commentsCount / postsCount;
        return Math.round(average * 100.0) / 100.0;
    }
    
    /**
     * Checks if the account metrics are recent.
     */
    public boolean isRecent(int hours) {
        return lastUpdated.isAfter(LocalDateTime.now().minusHours(hours));
    }
    
    /**
     * Checks if the account has good engagement.
     */
    public boolean hasGoodEngagement() {
        if (engagementRate == null) {
            return false;
        }
        
        // Different thresholds based on follower count
        if (followersCount == null || followersCount < 1000) {
            return engagementRate >= 3.0; // Micro-influencers should have higher engagement
        } else if (followersCount < 10000) {
            return engagementRate >= 2.0;
        } else if (followersCount < 100000) {
            return engagementRate >= 1.5;
        } else {
            return engagementRate >= 1.0; // Large accounts typically have lower engagement rates
        }
    }
    
    /**
     * Checks if the account is growing.
     */
    public boolean isGrowing() {
        return growthRate != null && growthRate > 0;
    }
    
    /**
     * Gets a summary of the account performance.
     */
    public String getPerformanceSummary() {
        StringBuilder summary = new StringBuilder();
        
        if (followersCount != null) {
            summary.append(String.format("Followers: %,d", followersCount));
        }
        
        if (engagementRate != null) {
            summary.append(String.format(" | Engagement: %.2f%%", engagementRate));
        }
        
        if (growthRate != null) {
            summary.append(String.format(" | Growth: %+.2f%%", growthRate));
        }
        
        return summary.toString();
    }
    
    // Getters
    public Long getFollowersCount() { return followersCount; }
    public Long getFollowingCount() { return followingCount; }
    public Long getPostsCount() { return postsCount; }
    public Long getLikesCount() { return likesCount; }
    public Long getCommentsCount() { return commentsCount; }
    public Long getSharesCount() { return sharesCount; }
    public Long getImpressionsCount() { return impressionsCount; }
    public Long getReachCount() { return reachCount; }
    public Double getEngagementRate() { return engagementRate; }
    public Double getGrowthRate() { return growthRate; }
    public LocalDateTime getLastUpdated() { return lastUpdated; }
    public String getProfileViews() { return profileViews; }
    public String getWebsiteClicks() { return websiteClicks; }
    public String getEmailClicks() { return emailClicks; }
    public String getPhoneClicks() { return phoneClicks; }
    public String getDirectionsClicks() { return directionsClicks; }
    public Long getStoriesViews() { return storiesViews; }
    public Long getReelsViews() { return reelsViews; }
    public Long getVideosViews() { return videosViews; }
    
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        AccountMetrics that = (AccountMetrics) o;
        return Objects.equals(followersCount, that.followersCount) &&
               Objects.equals(followingCount, that.followingCount) &&
               Objects.equals(postsCount, that.postsCount) &&
               Objects.equals(likesCount, that.likesCount) &&
               Objects.equals(commentsCount, that.commentsCount) &&
               Objects.equals(sharesCount, that.sharesCount) &&
               Objects.equals(impressionsCount, that.impressionsCount) &&
               Objects.equals(reachCount, that.reachCount) &&
               Objects.equals(engagementRate, that.engagementRate) &&
               Objects.equals(growthRate, that.growthRate) &&
               Objects.equals(lastUpdated, that.lastUpdated) &&
               Objects.equals(storiesViews, that.storiesViews) &&
               Objects.equals(reelsViews, that.reelsViews) &&
               Objects.equals(videosViews, that.videosViews);
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(followersCount, followingCount, postsCount,
                          likesCount, commentsCount, sharesCount,
                          impressionsCount, reachCount, engagementRate,
                          growthRate, lastUpdated, storiesViews,
                          reelsViews, videosViews);
    }
    
    @Override
    public String toString() {
        return "AccountMetrics{" +
               "followersCount=" + followersCount +
               ", followingCount=" + followingCount +
               ", postsCount=" + postsCount +
               ", engagementRate=" + engagementRate +
               ", growthRate=" + growthRate +
               ", lastUpdated=" + lastUpdated +
               '}';
    }
}
