package com.social.media.domain.socialnetwork;

import com.social.media.domain.shared.BaseValueObject;
import com.social.media.domain.shared.enums.SocialPlatform;

import java.util.Map;
import java.util.Objects;

/**
 * Value object representing rate limits for a social network platform.
 * Contains various limits imposed by the platform API.
 */
public final class RateLimits extends BaseValueObject {
    
    private final Integer requestsPerMinute;
    private final Integer requestsPerHour;
    private final Integer requestsPerDay;
    private final Integer postsPerHour;
    private final Integer postsPerDay;
    private final Integer followsPerHour;
    private final Integer likesPerHour;
    private final Integer commentsPerHour;
    private final Map<String, Integer> customLimits;
    
    public RateLimits(
            Integer requestsPerMinute,
            Integer requestsPerHour, 
            Integer requestsPerDay,
            Integer postsPerHour,
            Integer postsPerDay,
            Integer followsPerHour,
            Integer likesPerHour,
            Integer commentsPerHour,
            Map<String, Integer> customLimits) {
        
        this.requestsPerMinute = validateLimit(requestsPerMinute, "requestsPerMinute");
        this.requestsPerHour = validateLimit(requestsPerHour, "requestsPerHour");
        this.requestsPerDay = validateLimit(requestsPerDay, "requestsPerDay");
        this.postsPerHour = validateLimit(postsPerHour, "postsPerHour");
        this.postsPerDay = validateLimit(postsPerDay, "postsPerDay");
        this.followsPerHour = validateLimit(followsPerHour, "followsPerHour");
        this.likesPerHour = validateLimit(likesPerHour, "likesPerHour");
        this.commentsPerHour = validateLimit(commentsPerHour, "commentsPerHour");
        this.customLimits = customLimits != null ? Map.copyOf(customLimits) : Map.of();
        
        validate();
    }
    
    private Integer validateLimit(Integer limit, String fieldName) {
        if (limit != null && limit < 0) {
            throw new IllegalArgumentException(fieldName + " cannot be negative");
        }
        return limit;
    }
    
    @Override
    public void validate() {
        // Validate hierarchy consistency
        if (requestsPerHour != null && requestsPerMinute != null && 
            requestsPerHour < requestsPerMinute * 60) {
            throw new IllegalArgumentException("Hourly limit cannot be less than minute limit * 60");
        }
        
        if (requestsPerDay != null && requestsPerHour != null && 
            requestsPerDay < requestsPerHour * 24) {
            throw new IllegalArgumentException("Daily limit cannot be less than hourly limit * 24");
        }
        
        if (postsPerDay != null && postsPerHour != null && 
            postsPerDay < postsPerHour * 24) {
            throw new IllegalArgumentException("Daily post limit cannot be less than hourly post limit * 24");
        }
    }
    
    /**
     * Creates Instagram-specific rate limits.
     */
    public static RateLimits forInstagram() {
        return new RateLimits(
            200,        // requests per minute
            200,        // requests per hour (Instagram uses rolling window)
            null,       // no daily limit specified
            25,         // posts per hour
            100,        // posts per day
            60,         // follows per hour
            1000,       // likes per hour
            60,         // comments per hour
            Map.of()
        );
    }
    
    /**
     * Creates Facebook-specific rate limits.
     */
    public static RateLimits forFacebook() {
        return new RateLimits(
            600,        // requests per minute
            null,       // no hourly limit
            null,       // no daily limit
            null,       // no post limit per hour
            null,       // no post limit per day
            null,       // no follow limit
            null,       // no like limit
            null,       // no comment limit
            Map.of("app_calls", 200) // App-level rate limit
        );
    }
    
    /**
     * Creates Twitter/X-specific rate limits.
     */
    public static RateLimits forTwitter() {
        return new RateLimits(
            null,       // no minute limit
            300,        // requests per hour (varies by endpoint)
            null,       // no daily limit
            null,       // posts managed separately
            2400,       // posts per day (varies by account type)
            400,        // follows per day (converted to hourly)
            null,       // likes managed separately
            null,       // replies managed separately
            Map.of(
                "tweets_per_hour", 100,
                "user_lookup", 300,
                "followers", 15
            )
        );
    }
    
    /**
     * Creates LinkedIn-specific rate limits.
     */
    public static RateLimits forLinkedIn() {
        return new RateLimits(
            null,       // no minute limit
            500,        // requests per hour
            100000,     // requests per day
            null,       // no post limit per hour
            25,         // posts per day
            null,       // no follow limit
            null,       // no like limit
            null,       // no comment limit
            Map.of()
        );
    }
    
    /**
     * Creates default rate limits for unknown platforms.
     */
    public static RateLimits defaultLimits() {
        return new RateLimits(
            60,         // conservative default
            1000,       // conservative default
            10000,      // conservative default
            10,         // conservative default
            50,         // conservative default
            20,         // conservative default
            100,        // conservative default
            20,         // conservative default
            Map.of()
        );
    }
    
    /**
     * Checks if a request would exceed the rate limit.
     */
    public boolean wouldExceedLimit(String limitType, int currentCount) {
        Integer limit = switch (limitType.toLowerCase()) {
            case "requests_per_minute" -> requestsPerMinute;
            case "requests_per_hour" -> requestsPerHour;
            case "requests_per_day" -> requestsPerDay;
            case "posts_per_hour" -> postsPerHour;
            case "posts_per_day" -> postsPerDay;
            case "follows_per_hour" -> followsPerHour;
            case "likes_per_hour" -> likesPerHour;
            case "comments_per_hour" -> commentsPerHour;
            default -> customLimits.get(limitType);
        };
        
        return limit != null && currentCount >= limit;
    }
    
    /**
     * Gets the remaining requests for a specific limit type.
     */
    public Integer getRemainingRequests(String limitType, int currentCount) {
        Integer limit = switch (limitType.toLowerCase()) {
            case "requests_per_minute" -> requestsPerMinute;
            case "requests_per_hour" -> requestsPerHour;
            case "requests_per_day" -> requestsPerDay;
            case "posts_per_hour" -> postsPerHour;
            case "posts_per_day" -> postsPerDay;
            case "follows_per_hour" -> followsPerHour;
            case "likes_per_hour" -> likesPerHour;
            case "comments_per_hour" -> commentsPerHour;
            default -> customLimits.get(limitType);
        };
        
        return limit != null ? Math.max(0, limit - currentCount) : null;
    }
    
    // Getters
    public Integer getRequestsPerMinute() { return requestsPerMinute; }
    public Integer getRequestsPerHour() { return requestsPerHour; }
    public Integer getRequestsPerDay() { return requestsPerDay; }
    public Integer getPostsPerHour() { return postsPerHour; }
    public Integer getPostsPerDay() { return postsPerDay; }
    public Integer getFollowsPerHour() { return followsPerHour; }
    public Integer getLikesPerHour() { return likesPerHour; }
    public Integer getCommentsPerHour() { return commentsPerHour; }
    public Map<String, Integer> getCustomLimits() { return customLimits; }
    
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        RateLimits that = (RateLimits) o;
        return Objects.equals(requestsPerMinute, that.requestsPerMinute) &&
               Objects.equals(requestsPerHour, that.requestsPerHour) &&
               Objects.equals(requestsPerDay, that.requestsPerDay) &&
               Objects.equals(postsPerHour, that.postsPerHour) &&
               Objects.equals(postsPerDay, that.postsPerDay) &&
               Objects.equals(followsPerHour, that.followsPerHour) &&
               Objects.equals(likesPerHour, that.likesPerHour) &&
               Objects.equals(commentsPerHour, that.commentsPerHour) &&
               Objects.equals(customLimits, that.customLimits);
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(requestsPerMinute, requestsPerHour, requestsPerDay,
                          postsPerHour, postsPerDay, followsPerHour,
                          likesPerHour, commentsPerHour, customLimits);
    }
    
    @Override
    public String toString() {
        return "RateLimits{" +
               "requestsPerMinute=" + requestsPerMinute +
               ", requestsPerHour=" + requestsPerHour +
               ", requestsPerDay=" + requestsPerDay +
               ", postsPerHour=" + postsPerHour +
               ", postsPerDay=" + postsPerDay +
               ", followsPerHour=" + followsPerHour +
               ", likesPerHour=" + likesPerHour +
               ", commentsPerHour=" + commentsPerHour +
               ", customLimits=" + customLimits +
               '}';
    }
}
