package com.social.media.domain.content.aggregate;

import com.social.media.domain.content.valueobject.MediaId;
import com.social.media.domain.content.valueobject.MediaType;
import com.social.media.domain.company.valueobject.CompanyId;
import com.social.media.domain.user.valueobject.UserId;
import com.social.media.domain.shared.exception.BusinessRuleViolationException;
import com.social.media.domain.shared.kernel.AggregateRoot;

import java.time.LocalDateTime;
import java.util.Map;
import java.util.HashMap;

/**
 * Media aggregate representing media files (images, videos, etc.)
 */
public class Media extends AggregateRoot<MediaId> {
    
    private CompanyId companyId;
    private UserId uploadedBy;
    private String originalFileName;
    private String storedFileName;
    private MediaType mediaType;
    private String mimeType;
    private long fileSizeBytes;
    private String filePath;
    private String thumbnailPath;
    private Map<String, Object> metadata;
    private String altText;
    private boolean isPublic;
    private LocalDateTime uploadedAt;
    private LocalDateTime updatedAt;
    
    // Constructor for new media
    public Media(CompanyId companyId, UserId uploadedBy, String originalFileName,
                 String storedFileName, MediaType mediaType, String mimeType,
                 long fileSizeBytes, String filePath) {
        super(MediaId.generate());
        this.companyId = validateCompanyId(companyId);
        this.uploadedBy = validateUploadedBy(uploadedBy);
        this.originalFileName = validateFileName(originalFileName);
        this.storedFileName = validateFileName(storedFileName);
        this.mediaType = validateMediaType(mediaType);
        this.mimeType = validateMimeType(mimeType);
        this.fileSizeBytes = validateFileSize(fileSizeBytes);
        this.filePath = validateFilePath(filePath);
        this.metadata = new HashMap<>();
        this.isPublic = false;
        this.uploadedAt = LocalDateTime.now();
        this.updatedAt = LocalDateTime.now();
    }
    
    // Constructor for existing media
    public Media(MediaId id, CompanyId companyId, UserId uploadedBy, String originalFileName,
                 String storedFileName, MediaType mediaType, String mimeType,
                 long fileSizeBytes, String filePath, String thumbnailPath,
                 Map<String, Object> metadata, String altText, boolean isPublic,
                 LocalDateTime uploadedAt, LocalDateTime updatedAt) {
        super(id);
        this.companyId = companyId;
        this.uploadedBy = uploadedBy;
        this.originalFileName = originalFileName;
        this.storedFileName = storedFileName;
        this.mediaType = mediaType;
        this.mimeType = mimeType;
        this.fileSizeBytes = fileSizeBytes;
        this.filePath = filePath;
        this.thumbnailPath = thumbnailPath;
        this.metadata = metadata != null ? new HashMap<>(metadata) : new HashMap<>();
        this.altText = altText;
        this.isPublic = isPublic;
        this.uploadedAt = uploadedAt;
        this.updatedAt = updatedAt;
    }
    
    // Business methods
    public void updateMetadata(Map<String, Object> metadata) {
        this.metadata = metadata != null ? new HashMap<>(metadata) : new HashMap<>();
        this.updatedAt = LocalDateTime.now();
    }
    
    public void addMetadata(String key, Object value) {
        if (key == null || key.trim().isEmpty()) {
            throw new BusinessRuleViolationException("Metadata key cannot be empty");
        }
        this.metadata.put(key, value);
        this.updatedAt = LocalDateTime.now();
    }
    
    public void removeMetadata(String key) {
        this.metadata.remove(key);
        this.updatedAt = LocalDateTime.now();
    }
    
    public void updateAltText(String altText) {
        if (altText != null && altText.length() > 255) {
            throw new BusinessRuleViolationException("Alt text must not exceed 255 characters");
        }
        this.altText = altText;
        this.updatedAt = LocalDateTime.now();
    }
    
    public void setThumbnailPath(String thumbnailPath) {
        this.thumbnailPath = thumbnailPath;
        this.updatedAt = LocalDateTime.now();
    }
    
    public void makePublic() {
        this.isPublic = true;
        this.updatedAt = LocalDateTime.now();
    }
    
    public void makePrivate() {
        this.isPublic = false;
        this.updatedAt = LocalDateTime.now();
    }
    
    public boolean isImage() {
        return this.mediaType.isImage();
    }
    
    public boolean isVideo() {
        return this.mediaType.isVideo();
    }
    
    public boolean isAudio() {
        return this.mediaType.isAudio();
    }
    
    public boolean hasThumbnail() {
        return this.thumbnailPath != null && !this.thumbnailPath.trim().isEmpty();
    }
    
    public boolean belongsToCompany(CompanyId companyId) {
        return this.companyId.equals(companyId);
    }
    
    public boolean wasUploadedBy(UserId userId) {
        return this.uploadedBy.equals(userId);
    }
    
    public String getFileExtension() {
        if (this.originalFileName.contains(".")) {
            return this.originalFileName.substring(this.originalFileName.lastIndexOf(".") + 1).toLowerCase();
        }
        return "";
    }
    
    public double getFileSizeMB() {
        return this.fileSizeBytes / (1024.0 * 1024.0);
    }
    
    // Validation methods
    private CompanyId validateCompanyId(CompanyId companyId) {
        if (companyId == null) {
            throw new BusinessRuleViolationException("Company ID is required");
        }
        return companyId;
    }
    
    private UserId validateUploadedBy(UserId uploadedBy) {
        if (uploadedBy == null) {
            throw new BusinessRuleViolationException("Uploaded by user ID is required");
        }
        return uploadedBy;
    }
    
    private String validateFileName(String fileName) {
        if (fileName == null || fileName.trim().isEmpty()) {
            throw new BusinessRuleViolationException("File name is required");
        }
        if (fileName.length() > 255) {
            throw new BusinessRuleViolationException("File name must not exceed 255 characters");
        }
        return fileName.trim();
    }
    
    private MediaType validateMediaType(MediaType mediaType) {
        if (mediaType == null) {
            throw new BusinessRuleViolationException("Media type is required");
        }
        return mediaType;
    }
    
    private String validateMimeType(String mimeType) {
        if (mimeType == null || mimeType.trim().isEmpty()) {
            throw new BusinessRuleViolationException("MIME type is required");
        }
        return mimeType.trim();
    }
    
    private long validateFileSize(long fileSizeBytes) {
        if (fileSizeBytes <= 0) {
            throw new BusinessRuleViolationException("File size must be positive");
        }
        // 100MB limit
        if (fileSizeBytes > 100 * 1024 * 1024) {
            throw new BusinessRuleViolationException("File size exceeds maximum limit of 100MB");
        }
        return fileSizeBytes;
    }
    
    private String validateFilePath(String filePath) {
        if (filePath == null || filePath.trim().isEmpty()) {
            throw new BusinessRuleViolationException("File path is required");
        }
        return filePath.trim();
    }
    
    // Getters
    public CompanyId getCompanyId() { return companyId; }
    public UserId getUploadedBy() { return uploadedBy; }
    public String getOriginalFileName() { return originalFileName; }
    public String getStoredFileName() { return storedFileName; }
    public MediaType getMediaType() { return mediaType; }
    public String getMimeType() { return mimeType; }
    public long getFileSizeBytes() { return fileSizeBytes; }
    public String getFilePath() { return filePath; }
    public String getThumbnailPath() { return thumbnailPath; }
    public Map<String, Object> getMetadata() { return new HashMap<>(metadata); }
    public String getAltText() { return altText; }
    public boolean isPublic() { return isPublic; }
    public LocalDateTime getUploadedAt() { return uploadedAt; }
    public LocalDateTime getUpdatedAt() { return updatedAt; }
}
