package com.social.media.domain.post.entities;

import com.social.media.domain.company.valueobjects.CompanyId;
import com.social.media.domain.post.valueobjects.PostContent;
import com.social.media.domain.post.valueobjects.PostId;
import com.social.media.domain.shared.entities.BaseEntity;
import com.social.media.domain.shared.valueobjects.Text;
import com.social.media.domain.socialaccount.valueobjects.SocialAccountId;
import com.social.media.domain.user.valueobjects.UserId;

import jakarta.persistence.*;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Objects;

/**
 * Post aggregate root.
 * 
 * Represents a social media post that can be published to multiple platforms.
 * Posts can be scheduled, drafted, published, or failed.
 * 
 * @author Social Media Manager Team
 * @since 2.0.0
 */
@Entity
@Table(name = "posts", schema = "core_business")
@Getter
@Setter
@NoArgsConstructor
public class Post extends BaseEntity {
    
    @Column(name = "post_uuid", nullable = false, unique = true, updatable = false)
    private String postUuid;
    
    @Column(name = "company_id", nullable = false)
    private Long companyId;
    
    @Column(name = "created_by_user_id", nullable = false)
    private Long createdByUserId;
    
    @Embedded
    @AttributeOverride(name = "value", column = @Column(name = "title", length = 255))
    private Text title;
    
    @Embedded
    private PostContent content;
    
    @Column(name = "post_type", nullable = false, length = 20)
    @Enumerated(EnumType.STRING)
    private PostType postType;
    
    @Column(name = "post_status", nullable = false, length = 20)
    @Enumerated(EnumType.STRING)
    private PostStatus postStatus = PostStatus.DRAFT;
    
    @Column(name = "scheduled_for")
    private Instant scheduledFor;
    
    @Column(name = "published_at")
    private Instant publishedAt;
    
    @Column(name = "media_urls", length = 2000)
    private String mediaUrls;
    
    @Column(name = "media_type", length = 20)
    @Enumerated(EnumType.STRING)
    private MediaType mediaType;
    
    @Column(name = "link_url", length = 500)
    private String linkUrl;
    
    @Column(name = "link_title", length = 255)
    private String linkTitle;
    
    @Column(name = "link_description", length = 500)
    private String linkDescription;
    
    @Column(name = "link_image_url", length = 500)
    private String linkImageUrl;
    
    @Column(name = "campaign_id")
    private Long campaignId;
    
    @Column(name = "approval_required", nullable = false)
    private Boolean approvalRequired = false;
    
    @Column(name = "approved_by_user_id")
    private Long approvedByUserId;
    
    @Column(name = "approved_at")
    private Instant approvedAt;
    
    @Column(name = "rejection_reason", length = 500)
    private String rejectionReason;
    
    @Column(name = "auto_publish", nullable = false)
    private Boolean autoPublish = true;
    
    @Column(name = "priority", nullable = false)
    private Integer priority = 5;
    
    @Column(name = "tags", length = 1000)
    private String tags;
    
    @Column(name = "notes", length = 2000)
    private String notes;
    
    @Column(name = "analytics_enabled", nullable = false)
    private Boolean analyticsEnabled = true;
    
    @Column(name = "comment_enabled", nullable = false)
    private Boolean commentEnabled = true;
    
    @Column(name = "boost_eligible", nullable = false)
    private Boolean boostEligible = false;
    
    @Column(name = "boost_budget")
    private Double boostBudget;
    
    @Column(name = "boost_duration_days")
    private Integer boostDurationDays;
    
    @Column(name = "target_audience", length = 1000)
    private String targetAudience;
    
    @Column(name = "geo_targeting", length = 500)
    private String geoTargeting;
    
    @Column(name = "age_targeting", length = 100)
    private String ageTargeting;
    
    @Column(name = "total_reach")
    private Long totalReach = 0L;
    
    @Column(name = "total_impressions")
    private Long totalImpressions = 0L;
    
    @Column(name = "total_engagements")
    private Long totalEngagements = 0L;
    
    @Column(name = "total_clicks")
    private Long totalClicks = 0L;
    
    @Column(name = "total_shares")
    private Long totalShares = 0L;
    
    @Column(name = "total_comments")
    private Long totalComments = 0L;
    
    @Column(name = "total_likes")
    private Long totalLikes = 0L;
    
    public enum PostType {
        TEXT("Text post"),
        IMAGE("Image post"),
        VIDEO("Video post"),
        LINK("Link post"),
        POLL("Poll post"),
        STORY("Story post"),
        CAROUSEL("Carousel post"),
        REEL("Reel/Short video");
        
        private final String description;
        
        PostType(String description) {
            this.description = description;
        }
        
        public String getDescription() {
            return description;
        }
    }
    
    public enum PostStatus {
        DRAFT("Draft - not published"),
        SCHEDULED("Scheduled for publishing"),
        PENDING_APPROVAL("Pending approval"),
        APPROVED("Approved for publishing"),
        REJECTED("Rejected by approver"),
        PUBLISHING("Currently being published"),
        PUBLISHED("Successfully published"),
        FAILED("Publishing failed"),
        CANCELLED("Cancelled by user");
        
        private final String description;
        
        PostStatus(String description) {
            this.description = description;
        }
        
        public String getDescription() {
            return description;
        }
    }
    
    public enum MediaType {
        NONE("No media"),
        IMAGE("Images"),
        VIDEO("Videos"),
        GIF("GIF animation"),
        AUDIO("Audio files"),
        DOCUMENT("Documents");
        
        private final String description;
        
        MediaType(String description) {
            this.description = description;
        }
        
        public String getDescription() {
            return description;
        }
    }
    
    // Factory method for creating new posts
    public static Post create(Long companyId, Long createdByUserId, String title, String content, 
                            PostType postType, Boolean approvalRequired) {
        Post post = new Post();
        post.postUuid = PostId.newPostId().getStringValue();
        post.companyId = Objects.requireNonNull(companyId, "Company ID cannot be null");
        post.createdByUserId = Objects.requireNonNull(createdByUserId, "Created by user ID cannot be null");
        post.title = title != null ? Text.shortText(title) : null;
        post.content = PostContent.of(content);
        post.postType = Objects.requireNonNull(postType, "Post type cannot be null");
        post.approvalRequired = approvalRequired != null ? approvalRequired : false;
        post.postStatus = PostStatus.DRAFT;
        
        return post;
    }
    
    /**
     * Get the post ID as PostId value object
     */
    public PostId getPostId() {
        return PostId.of(postUuid);
    }
    
    /**
     * Get the company ID as CompanyId value object
     */
    public CompanyId getCompanyId() {
        return CompanyId.of(String.valueOf(companyId));
    }
    
    /**
     * Get the creator user ID as UserId value object
     */
    public UserId getCreatedByUserId() {
        return UserId.of(String.valueOf(createdByUserId));
    }
    
    /**
     * Update post content
     */
    public void updateContent(String title, String content, PostType postType) {
        this.title = title != null ? Text.shortText(title) : null;
        this.content = PostContent.of(content);
        this.postType = Objects.requireNonNull(postType, "Post type cannot be null");
        
        // Reset approval if content changed
        if (postStatus == PostStatus.APPROVED || postStatus == PostStatus.REJECTED) {
            this.postStatus = approvalRequired ? PostStatus.PENDING_APPROVAL : PostStatus.DRAFT;
            this.approvedByUserId = null;
            this.approvedAt = null;
            this.rejectionReason = null;
        }
    }
    
    /**
     * Update media information
     */
    public void updateMedia(String mediaUrls, MediaType mediaType) {
        this.mediaUrls = mediaUrls;
        this.mediaType = mediaType;
    }
    
    /**
     * Update link information
     */
    public void updateLink(String linkUrl, String linkTitle, String linkDescription, String linkImageUrl) {
        this.linkUrl = linkUrl;
        this.linkTitle = linkTitle;
        this.linkDescription = linkDescription;
        this.linkImageUrl = linkImageUrl;
    }
    
    /**
     * Schedule post for publishing
     */
    public void schedule(Instant scheduledFor) {
        if (scheduledFor.isBefore(Instant.now())) {
            throw new IllegalArgumentException("Cannot schedule post in the past");
        }
        
        if (approvalRequired && postStatus != PostStatus.APPROVED) {
            throw new IllegalStateException("Post must be approved before scheduling");
        }
        
        this.scheduledFor = scheduledFor;
        this.postStatus = PostStatus.SCHEDULED;
    }
    
    /**
     * Submit post for approval
     */
    public void submitForApproval() {
        if (!approvalRequired) {
            throw new IllegalStateException("Post does not require approval");
        }
        
        this.postStatus = PostStatus.PENDING_APPROVAL;
        this.approvedByUserId = null;
        this.approvedAt = null;
        this.rejectionReason = null;
    }
    
    /**
     * Approve post
     */
    public void approve(Long approvedByUserId) {
        if (!approvalRequired) {
            throw new IllegalStateException("Post does not require approval");
        }
        
        if (postStatus != PostStatus.PENDING_APPROVAL) {
            throw new IllegalStateException("Post is not pending approval");
        }
        
        this.postStatus = PostStatus.APPROVED;
        this.approvedByUserId = approvedByUserId;
        this.approvedAt = Instant.now();
        this.rejectionReason = null;
    }
    
    /**
     * Reject post
     */
    public void reject(String rejectionReason) {
        if (!approvalRequired) {
            throw new IllegalStateException("Post does not require approval");
        }
        
        if (postStatus != PostStatus.PENDING_APPROVAL) {
            throw new IllegalStateException("Post is not pending approval");
        }
        
        this.postStatus = PostStatus.REJECTED;
        this.rejectionReason = Objects.requireNonNull(rejectionReason, "Rejection reason cannot be null");
        this.approvedByUserId = null;
        this.approvedAt = null;
    }
    
    /**
     * Start publishing process
     */
    public void startPublishing() {
        if (!canBePublished()) {
            throw new IllegalStateException("Post cannot be published in current state");
        }
        
        this.postStatus = PostStatus.PUBLISHING;
    }
    
    /**
     * Mark post as successfully published
     */
    public void markAsPublished() {
        this.postStatus = PostStatus.PUBLISHED;
        this.publishedAt = Instant.now();
    }
    
    /**
     * Mark post as failed to publish
     */
    public void markAsFailed() {
        this.postStatus = PostStatus.FAILED;
    }
    
    /**
     * Cancel scheduled post
     */
    public void cancel() {
        if (postStatus != PostStatus.SCHEDULED) {
            throw new IllegalStateException("Only scheduled posts can be cancelled");
        }
        
        this.postStatus = PostStatus.CANCELLED;
        this.scheduledFor = null;
    }
    
    /**
     * Check if post can be published
     */
    public boolean canBePublished() {
        return (postStatus == PostStatus.DRAFT && !approvalRequired) ||
               (postStatus == PostStatus.APPROVED) ||
               (postStatus == PostStatus.SCHEDULED);
    }
    
    /**
     * Check if post is published
     */
    public boolean isPublished() {
        return postStatus == PostStatus.PUBLISHED;
    }
    
    /**
     * Check if post is scheduled
     */
    public boolean isScheduled() {
        return postStatus == PostStatus.SCHEDULED;
    }
    
    /**
     * Check if post is ready to publish now
     */
    public boolean isReadyToPublish() {
        return isScheduled() && scheduledFor != null && scheduledFor.isBefore(Instant.now());
    }
    
    /**
     * Update analytics data
     */
    public void updateAnalytics(Long reach, Long impressions, Long engagements, Long clicks, 
                              Long shares, Long comments, Long likes) {
        this.totalReach = reach != null ? reach : 0L;
        this.totalImpressions = impressions != null ? impressions : 0L;
        this.totalEngagements = engagements != null ? engagements : 0L;
        this.totalClicks = clicks != null ? clicks : 0L;
        this.totalShares = shares != null ? shares : 0L;
        this.totalComments = comments != null ? comments : 0L;
        this.totalLikes = likes != null ? likes : 0L;
    }
    
    /**
     * Configure boost settings
     */
    public void configureBoost(Double budget, Integer durationDays, String targetAudience, 
                             String geoTargeting, String ageTargeting) {
        this.boostEligible = true;
        this.boostBudget = budget;
        this.boostDurationDays = durationDays;
        this.targetAudience = targetAudience;
        this.geoTargeting = geoTargeting;
        this.ageTargeting = ageTargeting;
    }
    
    /**
     * Set tags
     */
    public void setTags(String tags) {
        this.tags = tags;
    }
    
    /**
     * Set notes
     */
    public void setNotes(String notes) {
        this.notes = notes;
    }
    
    /**
     * Set priority (1-10, where 10 is highest priority)
     */
    public void setPriority(Integer priority) {
        if (priority < 1 || priority > 10) {
            throw new IllegalArgumentException("Priority must be between 1 and 10");
        }
        this.priority = priority;
    }
    
    /**
     * Get display title (title or content preview)
     */
    public String getDisplayTitle() {
        if (title != null && !title.getValue().isEmpty()) {
            return title.getValue();
        }
        return content.getPreview(50);
    }
    
    /**
     * Get media URLs as array
     */
    public String[] getMediaUrlsArray() {
        return mediaUrls != null ? mediaUrls.split(",") : new String[0];
    }
    
    /**
     * Calculate engagement rate
     */
    public double getEngagementRate() {
        if (totalImpressions == 0) return 0.0;
        return (double) totalEngagements / totalImpressions * 100;
    }
    
    /**
     * Calculate click-through rate
     */
    public double getClickThroughRate() {
        if (totalImpressions == 0) return 0.0;
        return (double) totalClicks / totalImpressions * 100;
    }
    
    // Additional getter and setter methods for compatibility
    
    public String getPostUuid() {
        return postUuid;
    }
    
    public String getTitle() {
        return title != null ? title.getValue() : null;
    }
    
    public String getContent() {
        return content != null ? content.toString() : null;
    }
    
    public PostType getPostType() {
        return postType;
    }
    
    public PostStatus getPostStatus() {
        return postStatus;
    }
    
    public Boolean getApprovalRequired() {
        return approvalRequired;
    }
    
    public LocalDateTime getScheduledFor() {
        return scheduledFor != null ? 
            LocalDateTime.ofInstant(scheduledFor, ZoneId.systemDefault()) : null;
    }
    
    public Instant getScheduledForInstant() {
        return scheduledFor;
    }
    
    public void setCampaignId(Long campaignId) {
        this.campaignId = campaignId;
    }
    
    public void setAutoPublish(Boolean autoPublish) {
        this.autoPublish = autoPublish;
    }
    
    @Override
    public String toString() {
        return String.format("Post{id=%s, uuid='%s', title='%s', status=%s, type=%s, active=%s}", 
            getId(), postUuid, getDisplayTitle(), postStatus, postType, isActive());
    }
}
