package com.social.media.domain.content;

import com.social.media.domain.shared.BaseEntity;
import com.social.media.domain.shared.enums.PostStatus;
import com.social.media.domain.shared.enums.PostType;
import com.social.media.domain.shared.enums.SocialPlatform;

import java.time.LocalDateTime;
import java.util.Set;
import java.util.HashSet;
import java.util.UUID;
import java.util.Objects;
import java.util.List;
import java.util.ArrayList;

/**
 * Post aggregate root representing a social media post.
 * Manages content, scheduling, publishing, and cross-platform posting.
 */
public class Post extends BaseEntity {
    
    private UUID companyId;
    private UUID userId;
    private UUID contentCategoryId;
    private PostType postType;
    private PostStatus status;
    private String content;
    private String caption;
    private String hashtags;
    private Set<UUID> mediaIds;
    private Set<SocialPlatform> targetPlatforms;
    private LocalDateTime scheduledAt;
    private LocalDateTime publishedAt;
    private LocalDateTime expiresAt;
    private boolean isPromoted;
    private String promotionBudget;
    private String targetAudience;
    private String location;
    private String link;
    private String callToAction;
    private boolean enableComments;
    private boolean enableSharing;
    private String approvalStatus;
    private UUID approvedByUserId;
    private LocalDateTime approvedAt;
    private String rejectionReason;
    private Integer priority;
    private String campaignId;
    private String notes;
    private List<String> mentions;
    private String sourceUrl;
    private boolean isRepost;
    private UUID originalPostId;
    
    // Platform-specific data (JSON or separate entities)
    private String instagramData;
    private String facebookData;
    private String twitterData;
    private String linkedinData;
    
    // Analytics and engagement (usually separate aggregate)
    private Long totalLikes;
    private Long totalComments;
    private Long totalShares;
    private Long totalViews;
    private Double engagementRate;
    
    // Default constructor for JPA
    protected Post() {
        super();
    }
    
    public Post(
            UUID companyId,
            UUID userId,
            PostType postType,
            String content,
            Set<SocialPlatform> targetPlatforms) {
        
        super();
        this.companyId = validateCompanyId(companyId);
        this.userId = validateUserId(userId);
        this.postType = validatePostType(postType);
        this.content = validateContent(content);
        this.targetPlatforms = validateTargetPlatforms(targetPlatforms);
        this.status = PostStatus.DRAFT;
        this.mediaIds = new HashSet<>();
        this.mentions = new ArrayList<>();
        this.enableComments = true;
        this.enableSharing = true;
        this.isPromoted = false;
        this.isRepost = false;
        this.priority = 5; // Medium priority
        this.approvalStatus = "PENDING";
        this.totalLikes = 0L;
        this.totalComments = 0L;
        this.totalShares = 0L;
        this.totalViews = 0L;
        this.engagementRate = 0.0;
    }
    
    // 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 PostType validatePostType(PostType postType) {
        if (postType == null) {
            throw new IllegalArgumentException("Post type cannot be null");
        }
        return postType;
    }
    
    private String validateContent(String content) {
        if (content == null || content.trim().isEmpty()) {
            throw new IllegalArgumentException("Post content cannot be null or empty");
        }
        if (content.length() > 10000) {
            throw new IllegalArgumentException("Post content cannot exceed 10,000 characters");
        }
        return content.trim();
    }
    
    private Set<SocialPlatform> validateTargetPlatforms(Set<SocialPlatform> platforms) {
        if (platforms == null || platforms.isEmpty()) {
            throw new IllegalArgumentException("At least one target platform must be specified");
        }
        return new HashSet<>(platforms);
    }
    
    // Business methods
    
    /**
     * Updates the post content.
     */
    public void updateContent(String content, String caption) {
        boolean changed = false;
        
        if (content != null) {
            String validatedContent = validateContent(content);
            if (!this.content.equals(validatedContent)) {
                this.content = validatedContent;
                changed = true;
            }
        }
        
        if (caption != null) {
            if (caption.length() > 2200) { // Instagram limit
                throw new IllegalArgumentException("Caption cannot exceed 2200 characters");
            }
            String newCaption = caption.trim();
            if (!Objects.equals(this.caption, newCaption)) {
                this.caption = newCaption.isEmpty() ? null : newCaption;
                changed = true;
            }
        }
        
        if (changed) {
            validateCanModify();
            this.markAsModified();
        }
    }
    
    /**
     * Updates the hashtags.
     */
    public void updateHashtags(String hashtags) {
        if (hashtags != null && hashtags.length() > 1000) {
            throw new IllegalArgumentException("Hashtags cannot exceed 1000 characters");
        }
        
        String newHashtags = hashtags != null ? hashtags.trim() : null;
        if (!Objects.equals(this.hashtags, newHashtags)) {
            validateCanModify();
            this.hashtags = newHashtags;
            this.markAsModified();
        }
    }
    
    /**
     * Adds media to the post.
     */
    public void addMedia(UUID mediaId) {
        if (mediaId == null) {
            throw new IllegalArgumentException("Media ID cannot be null");
        }
        
        validateCanModify();
        
        if (mediaIds.size() >= 10) { // Instagram carousel limit
            throw new IllegalStateException("Cannot add more than 10 media items to a post");
        }
        
        if (mediaIds.add(mediaId)) {
            this.markAsModified();
        }
    }
    
    /**
     * Removes media from the post.
     */
    public void removeMedia(UUID mediaId) {
        if (mediaId != null && mediaIds.remove(mediaId)) {
            validateCanModify();
            this.markAsModified();
        }
    }
    
    /**
     * Updates target platforms.
     */
    public void updateTargetPlatforms(Set<SocialPlatform> platforms) {
        Set<SocialPlatform> validatedPlatforms = validateTargetPlatforms(platforms);
        if (!this.targetPlatforms.equals(validatedPlatforms)) {
            validateCanModify();
            this.targetPlatforms = validatedPlatforms;
            this.markAsModified();
        }
    }
    
    /**
     * Schedules the post for future publishing.
     */
    public void schedule(LocalDateTime scheduledAt) {
        if (scheduledAt == null) {
            throw new IllegalArgumentException("Scheduled time cannot be null");
        }
        if (scheduledAt.isBefore(LocalDateTime.now().plusMinutes(5))) {
            throw new IllegalArgumentException("Scheduled time must be at least 5 minutes in the future");
        }
        
        validateCanModify();
        this.scheduledAt = scheduledAt;
        this.status = PostStatus.SCHEDULED;
        this.markAsModified();
    }
    
    /**
     * Publishes the post immediately.
     */
    public void publishNow() {
        validateCanPublish();
        this.status = PostStatus.PUBLISHED;
        this.publishedAt = LocalDateTime.now();
        this.scheduledAt = null;
        this.markAsModified();
    }
    
    /**
     * Marks the post as published (used by the publishing service).
     */
    public void markAsPublished() {
        this.status = PostStatus.PUBLISHED;
        this.publishedAt = LocalDateTime.now();
        this.markAsModified();
    }
    
    /**
     * Marks the post as failed to publish.
     */
    public void markAsPublishFailed(String reason) {
        this.status = PostStatus.FAILED;
        this.rejectionReason = reason;
        this.markAsModified();
    }
    
    /**
     * Cancels a scheduled post.
     */
    public void cancel() {
        if (status != PostStatus.SCHEDULED) {
            throw new IllegalStateException("Only scheduled posts can be cancelled");
        }
        
        this.status = PostStatus.DRAFT;
        this.scheduledAt = null;
        this.markAsModified();
    }
    
    /**
     * Archives the post.
     */
    public void archive() {
        this.status = PostStatus.ARCHIVED;
        this.markAsModified();
    }
    
    /**
     * Restores an archived post to draft.
     */
    public void restore() {
        if (status != PostStatus.ARCHIVED) {
            throw new IllegalStateException("Only archived posts can be restored");
        }
        
        this.status = PostStatus.DRAFT;
        this.markAsModified();
    }
    
    /**
     * Submits the post for approval.
     */
    public void submitForApproval() {
        validateCanModify();
        this.approvalStatus = "PENDING";
        this.markAsModified();
    }
    
    /**
     * Approves the post.
     */
    public void approve(UUID approvedByUserId) {
        if (approvedByUserId == null) {
            throw new IllegalArgumentException("Approver user ID cannot be null");
        }
        
        this.approvalStatus = "APPROVED";
        this.approvedByUserId = approvedByUserId;
        this.approvedAt = LocalDateTime.now();
        this.rejectionReason = null;
        this.markAsModified();
    }
    
    /**
     * Rejects the post.
     */
    public void reject(String reason) {
        if (reason == null || reason.trim().isEmpty()) {
            throw new IllegalArgumentException("Rejection reason cannot be null or empty");
        }
        
        this.approvalStatus = "REJECTED";
        this.rejectionReason = reason.trim();
        this.approvedByUserId = null;
        this.approvedAt = null;
        this.markAsModified();
    }
    
    /**
     * Updates the content category.
     */
    public void updateCategory(UUID contentCategoryId) {
        if (!Objects.equals(this.contentCategoryId, contentCategoryId)) {
            validateCanModify();
            this.contentCategoryId = contentCategoryId;
            this.markAsModified();
        }
    }
    
    /**
     * Updates post settings.
     */
    public void updateSettings(
            boolean enableComments,
            boolean enableSharing,
            String location,
            String link,
            String callToAction) {
        
        boolean changed = false;
        
        if (this.enableComments != enableComments) {
            this.enableComments = enableComments;
            changed = true;
        }
        
        if (this.enableSharing != enableSharing) {
            this.enableSharing = enableSharing;
            changed = true;
        }
        
        if (!Objects.equals(this.location, location)) {
            this.location = location;
            changed = true;
        }
        
        if (!Objects.equals(this.link, link)) {
            this.link = link;
            changed = true;
        }
        
        if (!Objects.equals(this.callToAction, callToAction)) {
            this.callToAction = callToAction;
            changed = true;
        }
        
        if (changed) {
            validateCanModify();
            this.markAsModified();
        }
    }
    
    /**
     * Updates promotion settings.
     */
    public void updatePromotion(
            boolean isPromoted,
            String promotionBudget,
            String targetAudience) {
        
        boolean changed = false;
        
        if (this.isPromoted != isPromoted) {
            this.isPromoted = isPromoted;
            changed = true;
        }
        
        if (!Objects.equals(this.promotionBudget, promotionBudget)) {
            this.promotionBudget = promotionBudget;
            changed = true;
        }
        
        if (!Objects.equals(this.targetAudience, targetAudience)) {
            this.targetAudience = targetAudience;
            changed = true;
        }
        
        if (changed) {
            this.markAsModified();
        }
    }
    
    /**
     * Updates engagement metrics.
     */
    public void updateEngagementMetrics(
            Long likes,
            Long comments,
            Long shares,
            Long views) {
        
        boolean changed = false;
        
        if (likes != null && !likes.equals(this.totalLikes)) {
            this.totalLikes = likes;
            changed = true;
        }
        
        if (comments != null && !comments.equals(this.totalComments)) {
            this.totalComments = comments;
            changed = true;
        }
        
        if (shares != null && !shares.equals(this.totalShares)) {
            this.totalShares = shares;
            changed = true;
        }
        
        if (views != null && !views.equals(this.totalViews)) {
            this.totalViews = views;
            changed = true;
        }
        
        if (changed) {
            this.engagementRate = calculateEngagementRate();
            this.markAsModified();
        }
    }
    
    /**
     * Calculates engagement rate.
     */
    private Double calculateEngagementRate() {
        if (totalViews == null || totalViews == 0) {
            return 0.0;
        }
        
        long totalEngagement = (totalLikes != null ? totalLikes : 0) +
                              (totalComments != null ? totalComments : 0) +
                              (totalShares != null ? totalShares : 0);
        
        double rate = ((double) totalEngagement / totalViews) * 100;
        return Math.round(rate * 100.0) / 100.0;
    }
    
    // Validation methods
    
    private void validateCanModify() {
        if (status == PostStatus.PUBLISHED || status == PostStatus.PUBLISHING) {
            throw new IllegalStateException("Cannot modify published or publishing posts");
        }
    }
    
    private void validateCanPublish() {
        if (status == PostStatus.PUBLISHED) {
            throw new IllegalStateException("Post is already published");
        }
        if (!"APPROVED".equals(approvalStatus) && !"PENDING".equals(approvalStatus)) {
            throw new IllegalStateException("Post must be approved before publishing");
        }
        if (content == null || content.trim().isEmpty()) {
            throw new IllegalStateException("Post content is required for publishing");
        }
    }
    
    // Query methods
    
    /**
     * Checks if the post is ready to publish.
     */
    public boolean isReadyToPublish() {
        return status == PostStatus.SCHEDULED &&
               "APPROVED".equals(approvalStatus) &&
               scheduledAt != null &&
               scheduledAt.isBefore(LocalDateTime.now());
    }
    
    /**
     * Checks if the post is published.
     */
    public boolean isPublished() {
        return status == PostStatus.PUBLISHED;
    }
    
    /**
     * Checks if the post is scheduled.
     */
    public boolean isScheduled() {
        return status == PostStatus.SCHEDULED && scheduledAt != null;
    }
    
    /**
     * Checks if the post needs approval.
     */
    public boolean needsApproval() {
        return "PENDING".equals(approvalStatus);
    }
    
    /**
     * Checks if the post is approved.
     */
    public boolean isApproved() {
        return "APPROVED".equals(approvalStatus);
    }
    
    /**
     * Checks if the post targets a specific platform.
     */
    public boolean targetsPlatform(SocialPlatform platform) {
        return targetPlatforms.contains(platform);
    }
    
    /**
     * Gets the time until scheduled publishing.
     */
    public Long getMinutesUntilPublish() {
        if (scheduledAt == null) {
            return null;
        }
        
        long minutes = java.time.Duration.between(LocalDateTime.now(), scheduledAt).toMinutes();
        return Math.max(0, minutes);
    }
    
    /**
     * Checks if the post has good engagement.
     */
    public boolean hasGoodEngagement() {
        return engagementRate != null && engagementRate >= 2.0;
    }
    
    // Getters
    public UUID getCompanyId() { return companyId; }
    public UUID getUserId() { return userId; }
    public UUID getContentCategoryId() { return contentCategoryId; }
    public PostType getPostType() { return postType; }
    public PostStatus getStatus() { return status; }
    public String getContent() { return content; }
    public String getCaption() { return caption; }
    public String getHashtags() { return hashtags; }
    public Set<UUID> getMediaIds() { return new HashSet<>(mediaIds); }
    public Set<SocialPlatform> getTargetPlatforms() { return new HashSet<>(targetPlatforms); }
    public LocalDateTime getScheduledAt() { return scheduledAt; }
    public LocalDateTime getPublishedAt() { return publishedAt; }
    public LocalDateTime getExpiresAt() { return expiresAt; }
    public boolean isPromoted() { return isPromoted; }
    public String getPromotionBudget() { return promotionBudget; }
    public String getTargetAudience() { return targetAudience; }
    public String getLocation() { return location; }
    public String getLink() { return link; }
    public String getCallToAction() { return callToAction; }
    public boolean isEnableComments() { return enableComments; }
    public boolean isEnableSharing() { return enableSharing; }
    public String getApprovalStatus() { return approvalStatus; }
    public UUID getApprovedByUserId() { return approvedByUserId; }
    public LocalDateTime getApprovedAt() { return approvedAt; }
    public String getRejectionReason() { return rejectionReason; }
    public Integer getPriority() { return priority; }
    public String getCampaignId() { return campaignId; }
    public String getNotes() { return notes; }
    public List<String> getMentions() { return new ArrayList<>(mentions); }
    public String getSourceUrl() { return sourceUrl; }
    public boolean isRepost() { return isRepost; }
    public UUID getOriginalPostId() { return originalPostId; }
    public Long getTotalLikes() { return totalLikes; }
    public Long getTotalComments() { return totalComments; }
    public Long getTotalShares() { return totalShares; }
    public Long getTotalViews() { return totalViews; }
    public Double getEngagementRate() { return engagementRate; }
    
    @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;
        Post post = (Post) o;
        return Objects.equals(companyId, post.companyId) &&
               Objects.equals(content, post.content) &&
               Objects.equals(scheduledAt, post.scheduledAt);
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(super.hashCode(), companyId, content, scheduledAt);
    }
    
    @Override
    public String toString() {
        return "Post{" +
               "id=" + getId() +
               ", companyId=" + companyId +
               ", postType=" + postType +
               ", status=" + status +
               ", targetPlatforms=" + targetPlatforms +
               ", scheduledAt=" + scheduledAt +
               ", publishedAt=" + publishedAt +
               '}';
    }
}
