package com.social.media.domain.content;

import com.social.media.domain.shared.BaseEntity;
import com.social.media.domain.shared.enums.MediaType;

import java.time.LocalDateTime;
import java.util.UUID;
import java.util.Objects;

/**
 * Media aggregate root representing uploaded media files for social media posts.
 * Handles file storage, metadata, and processing status.
 */
public class Media extends BaseEntity {
    
    private UUID companyId;
    private UUID userId;
    private String originalFilename;
    private String filename;
    private String filePath;
    private String fileUrl;
    private String thumbnailUrl;
    private MediaType mediaType;
    private String mimeType;
    private Long fileSize; // in bytes
    private Integer width;
    private Integer height;
    private Integer duration; // in seconds for videos
    private String altText;
    private String description;
    private String tags;
    private boolean isProcessed;
    private boolean isPublic;
    private String processingStatus;
    private String processingError;
    private LocalDateTime uploadedAt;
    private String storageProvider; // S3, CloudFlare, etc.
    private String storageBucket;
    private String storageKey;
    private String checksum;
    private String originalUrl;
    
    // Default constructor for JPA
    protected Media() {
        super();
    }
    
    public Media(
            UUID companyId,
            UUID userId,
            String originalFilename,
            String filename,
            String filePath,
            MediaType mediaType,
            String mimeType,
            Long fileSize) {
        
        super();
        this.companyId = validateCompanyId(companyId);
        this.userId = validateUserId(userId);
        this.originalFilename = validateOriginalFilename(originalFilename);
        this.filename = validateFilename(filename);
        this.filePath = validateFilePath(filePath);
        this.mediaType = validateMediaType(mediaType);
        this.mimeType = validateMimeType(mimeType);
        this.fileSize = validateFileSize(fileSize);
        this.isProcessed = false;
        this.isPublic = false;
        this.processingStatus = "PENDING";
        this.uploadedAt = LocalDateTime.now();
    }
    
    // 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 String validateOriginalFilename(String originalFilename) {
        if (originalFilename == null || originalFilename.trim().isEmpty()) {
            throw new IllegalArgumentException("Original filename cannot be null or empty");
        }
        if (originalFilename.length() > 255) {
            throw new IllegalArgumentException("Original filename cannot exceed 255 characters");
        }
        return originalFilename.trim();
    }
    
    private String validateFilename(String filename) {
        if (filename == null || filename.trim().isEmpty()) {
            throw new IllegalArgumentException("Filename cannot be null or empty");
        }
        if (filename.length() > 255) {
            throw new IllegalArgumentException("Filename cannot exceed 255 characters");
        }
        return filename.trim();
    }
    
    private String validateFilePath(String filePath) {
        if (filePath == null || filePath.trim().isEmpty()) {
            throw new IllegalArgumentException("File path cannot be null or empty");
        }
        if (filePath.length() > 500) {
            throw new IllegalArgumentException("File path cannot exceed 500 characters");
        }
        return filePath.trim();
    }
    
    private MediaType validateMediaType(MediaType mediaType) {
        if (mediaType == null) {
            throw new IllegalArgumentException("Media type cannot be null");
        }
        return mediaType;
    }
    
    private String validateMimeType(String mimeType) {
        if (mimeType == null || mimeType.trim().isEmpty()) {
            throw new IllegalArgumentException("MIME type cannot be null or empty");
        }
        if (mimeType.length() > 100) {
            throw new IllegalArgumentException("MIME type cannot exceed 100 characters");
        }
        return mimeType.trim().toLowerCase();
    }
    
    private Long validateFileSize(Long fileSize) {
        if (fileSize == null || fileSize <= 0) {
            throw new IllegalArgumentException("File size must be positive");
        }
        if (fileSize > 5L * 1024 * 1024 * 1024) { // 5GB limit
            throw new IllegalArgumentException("File size cannot exceed 5GB");
        }
        return fileSize;
    }
    
    // Business methods
    
    /**
     * Updates the file URLs after upload.
     */
    public void updateUrls(String fileUrl, String thumbnailUrl) {
        if (fileUrl == null || fileUrl.trim().isEmpty()) {
            throw new IllegalArgumentException("File URL cannot be null or empty");
        }
        
        if (!fileUrl.equals(this.fileUrl)) {
            this.fileUrl = fileUrl.trim();
            this.markAsModified();
        }
        
        if (thumbnailUrl != null && !thumbnailUrl.equals(this.thumbnailUrl)) {
            this.thumbnailUrl = thumbnailUrl.trim();
            this.markAsModified();
        }
    }
    
    /**
     * Updates the media dimensions.
     */
    public void updateDimensions(Integer width, Integer height, Integer duration) {
        boolean changed = false;
        
        if (width != null && width > 0 && !width.equals(this.width)) {
            this.width = width;
            changed = true;
        }
        
        if (height != null && height > 0 && !height.equals(this.height)) {
            this.height = height;
            changed = true;
        }
        
        if (duration != null && duration > 0 && !duration.equals(this.duration)) {
            this.duration = duration;
            changed = true;
        }
        
        if (changed) {
            this.markAsModified();
        }
    }
    
    /**
     * Updates the alt text for accessibility.
     */
    public void updateAltText(String altText) {
        if (altText != null && altText.length() > 200) {
            throw new IllegalArgumentException("Alt text cannot exceed 200 characters");
        }
        
        String newAltText = altText != null ? altText.trim() : null;
        if (!Objects.equals(this.altText, newAltText)) {
            this.altText = newAltText;
            this.markAsModified();
        }
    }
    
    /**
     * Updates the description.
     */
    public void updateDescription(String description) {
        if (description != null && description.length() > 1000) {
            throw new IllegalArgumentException("Description cannot exceed 1000 characters");
        }
        
        String newDescription = description != null ? description.trim() : null;
        if (!Objects.equals(this.description, newDescription)) {
            this.description = newDescription;
            this.markAsModified();
        }
    }
    
    /**
     * Updates the tags.
     */
    public void updateTags(String tags) {
        if (tags != null && tags.length() > 500) {
            throw new IllegalArgumentException("Tags cannot exceed 500 characters");
        }
        
        String newTags = tags != null ? tags.trim() : null;
        if (!Objects.equals(this.tags, newTags)) {
            this.tags = newTags;
            this.markAsModified();
        }
    }
    
    /**
     * Marks the media as processed.
     */
    public void markAsProcessed() {
        if (!isProcessed) {
            this.isProcessed = true;
            this.processingStatus = "COMPLETED";
            this.processingError = null;
            this.markAsModified();
        }
    }
    
    /**
     * Marks the media processing as failed.
     */
    public void markAsProcessingFailed(String error) {
        this.isProcessed = false;
        this.processingStatus = "FAILED";
        this.processingError = error;
        this.markAsModified();
    }
    
    /**
     * Starts processing.
     */
    public void startProcessing() {
        this.processingStatus = "PROCESSING";
        this.processingError = null;
        this.markAsModified();
    }
    
    /**
     * Makes the media public.
     */
    public void makePublic() {
        if (!isPublic) {
            this.isPublic = true;
            this.markAsModified();
        }
    }
    
    /**
     * Makes the media private.
     */
    public void makePrivate() {
        if (isPublic) {
            this.isPublic = false;
            this.markAsModified();
        }
    }
    
    /**
     * Updates storage information.
     */
    public void updateStorageInfo(String storageProvider, String storageBucket, String storageKey) {
        boolean changed = false;
        
        if (storageProvider != null && !storageProvider.equals(this.storageProvider)) {
            this.storageProvider = storageProvider;
            changed = true;
        }
        
        if (storageBucket != null && !storageBucket.equals(this.storageBucket)) {
            this.storageBucket = storageBucket;
            changed = true;
        }
        
        if (storageKey != null && !storageKey.equals(this.storageKey)) {
            this.storageKey = storageKey;
            changed = true;
        }
        
        if (changed) {
            this.markAsModified();
        }
    }
    
    /**
     * Updates the checksum for integrity verification.
     */
    public void updateChecksum(String checksum) {
        if (checksum != null && !checksum.equals(this.checksum)) {
            this.checksum = checksum;
            this.markAsModified();
        }
    }
    
    // Query methods
    
    /**
     * Checks if the media is ready for use.
     */
    public boolean isReady() {
        return isProcessed && fileUrl != null && !fileUrl.isEmpty();
    }
    
    /**
     * Checks if the media is an image.
     */
    public boolean isImage() {
        return mediaType == MediaType.IMAGE;
    }
    
    /**
     * Checks if the media is a video.
     */
    public boolean isVideo() {
        return mediaType == MediaType.VIDEO;
    }
    
    /**
     * Checks if the media is audio.
     */
    public boolean isAudio() {
        return mediaType == MediaType.AUDIO;
    }
    
    /**
     * Gets the file extension.
     */
    public String getFileExtension() {
        if (filename == null || !filename.contains(".")) {
            return "";
        }
        return filename.substring(filename.lastIndexOf(".") + 1).toLowerCase();
    }
    
    /**
     * Gets the aspect ratio.
     */
    public Double getAspectRatio() {
        if (width == null || height == null || height == 0) {
            return null;
        }
        return (double) width / height;
    }
    
    /**
     * Gets the file size in MB.
     */
    public Double getFileSizeInMB() {
        return fileSize != null ? fileSize / (1024.0 * 1024.0) : null;
    }
    
    /**
     * Gets the duration in minutes for videos.
     */
    public Double getDurationInMinutes() {
        return duration != null ? duration / 60.0 : null;
    }
    
    /**
     * Checks if the media file is large.
     */
    public boolean isLargeFile() {
        return fileSize != null && fileSize > 50 * 1024 * 1024; // > 50MB
    }
    
    /**
     * Checks if the media is suitable for Instagram.
     */
    public boolean isSuitableForInstagram() {
        if (isImage()) {
            return fileSize <= 30 * 1024 * 1024 && // <= 30MB
                   (getFileExtension().equals("jpg") || getFileExtension().equals("jpeg") || 
                    getFileExtension().equals("png"));
        } else if (isVideo()) {
            return fileSize <= 100 * 1024 * 1024 && // <= 100MB
                   duration != null && duration <= 60 && // <= 60 seconds
                   getFileExtension().equals("mp4");
        }
        return false;
    }
    
    /**
     * Gets a display name for the media.
     */
    public String getDisplayName() {
        return description != null && !description.isEmpty() ? 
               description : originalFilename;
    }
    
    // Getters
    public UUID getCompanyId() { return companyId; }
    public UUID getUserId() { return userId; }
    public String getOriginalFilename() { return originalFilename; }
    public String getFilename() { return filename; }
    public String getFilePath() { return filePath; }
    public String getFileUrl() { return fileUrl; }
    public String getThumbnailUrl() { return thumbnailUrl; }
    public MediaType getMediaType() { return mediaType; }
    public String getMimeType() { return mimeType; }
    public Long getFileSize() { return fileSize; }
    public Integer getWidth() { return width; }
    public Integer getHeight() { return height; }
    public Integer getDuration() { return duration; }
    public String getAltText() { return altText; }
    public String getDescription() { return description; }
    public String getTags() { return tags; }
    public boolean isProcessed() { return isProcessed; }
    public boolean isPublic() { return isPublic; }
    public String getProcessingStatus() { return processingStatus; }
    public String getProcessingError() { return processingError; }
    public LocalDateTime getUploadedAt() { return uploadedAt; }
    public String getStorageProvider() { return storageProvider; }
    public String getStorageBucket() { return storageBucket; }
    public String getStorageKey() { return storageKey; }
    public String getChecksum() { return checksum; }
    public String getOriginalUrl() { return originalUrl; }
    
    @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;
        Media media = (Media) o;
        return Objects.equals(companyId, media.companyId) &&
               Objects.equals(filename, media.filename) &&
               Objects.equals(checksum, media.checksum);
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(super.hashCode(), companyId, filename, checksum);
    }
    
    @Override
    public String toString() {
        return "Media{" +
               "id=" + getId() +
               ", companyId=" + companyId +
               ", originalFilename='" + originalFilename + '\'' +
               ", mediaType=" + mediaType +
               ", fileSize=" + fileSize +
               ", isProcessed=" + isProcessed +
               ", uploadedAt=" + uploadedAt +
               '}';
    }
}
