package com.social.media.domain.entity;

import jakarta.persistence.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;
import org.hibernate.annotations.DynamicUpdate;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;

import java.time.LocalDateTime;

/**
 * Entity representing the relationship between posts and media files
 * Maps to the core_business.post_media table
 */
@Entity
@Table(name = "post_media", schema = "core_business",
       uniqueConstraints = {
           @UniqueConstraint(name = "chk_post_media_post_media_unique", 
                           columnNames = {"post_id", "media_id"})
       },
       indexes = {
           @Index(name = "idx_post_media_post_id", columnList = "post_id"),
           @Index(name = "idx_post_media_media_id", columnList = "media_id"),
           @Index(name = "idx_post_media_display_order", columnList = "display_order"),
           @Index(name = "idx_post_media_is_primary", columnList = "is_primary")
       })
@Data
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = false)
@DynamicUpdate
@EntityListeners(AuditingEntityListener.class)
public class PostMedia {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @Column(name = "post_id", nullable = false)
    private Long postId;
    
    @Column(name = "media_id", nullable = false)
    private Long mediaId;
    
    @Column(name = "display_order", nullable = false, columnDefinition = "integer default 1")
    private Integer displayOrder = 1;
    
    @Column(name = "is_primary", nullable = false, columnDefinition = "boolean default false")
    private Boolean isPrimary = false;
    
    @CreatedDate
    @Column(name = "created_at", nullable = false, updatable = false)
    private LocalDateTime createdAt;
    
    // Relationships
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "post_id", referencedColumnName = "id", insertable = false, updatable = false)
    private Post post;
    
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "media_id", referencedColumnName = "id", insertable = false, updatable = false)
    private Media media;
    
    // Business logic methods
    
    /**
     * Check if this is the primary media for the post
     */
    public boolean isPrimaryMedia() {
        return isPrimary != null && isPrimary;
    }
    
    /**
     * Set as primary media (will trigger database constraint to ensure only one primary per post)
     */
    public void setAsPrimary() {
        this.isPrimary = true;
    }
    
    /**
     * Remove primary status
     */
    public void removePrimaryStatus() {
        this.isPrimary = false;
    }
    
    /**
     * Check if display order is valid
     */
    public boolean hasValidDisplayOrder() {
        return displayOrder != null && displayOrder > 0;
    }
    
    /**
     * Update display order with validation
     */
    public void updateDisplayOrder(Integer newOrder) {
        if (newOrder != null && newOrder > 0) {
            this.displayOrder = newOrder;
        } else {
            throw new IllegalArgumentException("Display order must be positive");
        }
    }
    
    /**
     * Check if this post-media relationship is valid
     */
    public boolean isValidRelationship() {
        return postId != null && mediaId != null && hasValidDisplayOrder();
    }
    
    /**
     * Get relationship description for logging/debugging
     */
    public String getRelationshipDescription() {
        return String.format("PostMedia[post=%d, media=%d, order=%d, primary=%s]", 
                           postId, mediaId, displayOrder, isPrimary);
    }
    
    /**
     * Check if this media can be set as primary
     */
    public boolean canSetAsPrimary() {
        return isValidRelationship();
    }
    
    /**
     * Move up in display order (decrease order number)
     */
    public void moveUp() {
        if (displayOrder != null && displayOrder > 1) {
            this.displayOrder = displayOrder - 1;
        }
    }
    
    /**
     * Move down in display order (increase order number)
     */
    public void moveDown() {
        if (displayOrder != null) {
            this.displayOrder = displayOrder + 1;
        }
    }
    
    /**
     * Set display order to first position
     */
    public void moveToFirst() {
        this.displayOrder = 1;
    }
    
    /**
     * Create a new PostMedia relationship
     */
    public static PostMedia create(Long postId, Long mediaId, Integer displayOrder, Boolean isPrimary) {
        PostMedia postMedia = new PostMedia();
        postMedia.setPostId(postId);
        postMedia.setMediaId(mediaId);
        postMedia.setDisplayOrder(displayOrder != null ? displayOrder : 1);
        postMedia.setIsPrimary(isPrimary != null ? isPrimary : false);
        return postMedia;
    }
    
    /**
     * Create a new primary PostMedia relationship
     */
    public static PostMedia createPrimary(Long postId, Long mediaId) {
        return create(postId, mediaId, 1, true);
    }
    
    /**
     * Create a new secondary PostMedia relationship with specific order
     */
    public static PostMedia createSecondary(Long postId, Long mediaId, Integer displayOrder) {
        return create(postId, mediaId, displayOrder, false);
    }
    
    @PrePersist
    public void prePersist() {
        if (createdAt == null) {
            createdAt = LocalDateTime.now();
        }
        if (displayOrder == null) {
            displayOrder = 1;
        }
        if (isPrimary == null) {
            isPrimary = false;
        }
        
        // Validate constraints
        if (displayOrder <= 0) {
            throw new IllegalStateException("Display order must be positive");
        }
    }
    
    @PreUpdate
    public void preUpdate() {
        // Validate constraints on update
        if (displayOrder != null && displayOrder <= 0) {
            throw new IllegalStateException("Display order must be positive");
        }
    }
}
