package com.social.media.dto;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.social.media.domain.entity.Media.MediaFormat;
import com.social.media.domain.entity.Media.MediaValidationStatus;
import jakarta.validation.constraints.*;

import java.time.LocalDateTime;
import java.util.Map;
import java.util.Objects;

@JsonInclude(JsonInclude.Include.NON_NULL)
public class MediaDto {
    
    private Long id;
    
    @JsonProperty("media_code")
    private String mediaCode;
    
    @NotNull(message = "Company ID é obrigatório")
    @JsonProperty("company_id")
    private Long companyId;
    
    @NotNull(message = "Uploaded By é obrigatório")
    @JsonProperty("uploaded_by")
    private Long uploadedBy;
    
    @NotBlank(message = "Nome do arquivo original é obrigatório")
    @Size(max = 255, message = "Nome do arquivo original deve ter no máximo 255 caracteres")
    @JsonProperty("original_filename")
    private String originalFilename;
    
    @NotBlank(message = "Nome do arquivo armazenado é obrigatório")
    @Size(max = 255, message = "Nome do arquivo armazenado deve ter no máximo 255 caracteres")
    @JsonProperty("stored_filename")
    private String storedFilename;
    
    @Size(max = 1000, message = "Caminho do arquivo deve ter no máximo 1000 caracteres")
    @JsonProperty("file_path")
    private String filePath;
    
    @NotNull(message = "Tamanho do arquivo é obrigatório")
    @Min(value = 1, message = "Tamanho do arquivo deve ser maior que 0")
    @JsonProperty("file_size")
    private Long fileSize;
    
    @JsonProperty("file_size_formatted")
    private String fileSizeFormatted;
    
    @NotBlank(message = "Tipo MIME é obrigatório")
    @Size(max = 100, message = "Tipo MIME deve ter no máximo 100 caracteres")
    @JsonProperty("mime_type")
    private String mimeType;
    
    @NotNull(message = "Formato do arquivo é obrigatório")
    private MediaFormat format;
    
    @Min(value = 1, message = "Largura deve ser maior que 0")
    private Integer width;
    
    @Min(value = 1, message = "Altura deve ser maior que 0")
    private Integer height;
    
    @Min(value = 1, message = "Duração deve ser maior que 0")
    @JsonProperty("duration_seconds")
    private Integer durationSeconds;
    
    @JsonProperty("duration_formatted")
    private String durationFormatted;
    
    @JsonProperty("is_public")
    private Boolean isPublic;
    
    @Size(max = 500, message = "Descrição deve ter no máximo 500 caracteres")
    private String description;
    
    @Size(max = 255, message = "Texto alternativo deve ter no máximo 255 caracteres")
    @JsonProperty("alt_text")
    private String altText;
    
    private Map<String, Object> metadata;
    
    @Size(max = 128, message = "Checksum do arquivo deve ter no máximo 128 caracteres")
    @JsonProperty("file_checksum")
    private String fileChecksum;
    
    @Size(max = 50, message = "Provedor de armazenamento deve ter no máximo 50 caracteres")
    @JsonProperty("storage_provider")
    private String storageProvider;
    
    @NotNull(message = "Status de validação é obrigatório")
    @JsonProperty("validation_status")
    private MediaValidationStatus validationStatus;
    
    @Size(max = 1000, message = "Notas de validação devem ter no máximo 1000 caracteres")
    @JsonProperty("validation_notes")
    private String validationNotes;
    
    @JsonProperty("deleted_at")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime deletedAt;
    
    @JsonProperty("uploaded_at")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime uploadedAt;
    
    @JsonProperty("updated_at")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime updatedAt;
    
    // Additional computed fields
    @JsonProperty("file_extension")
    private String fileExtension;
    
    @JsonProperty("is_image")
    private Boolean isImage;
    
    @JsonProperty("is_video")
    private Boolean isVideo;
    
    @JsonProperty("is_audio")
    private Boolean isAudio;
    
    @JsonProperty("is_document")
    private Boolean isDocument;
    
    @JsonProperty("is_archive")
    private Boolean isArchive;
    
    @JsonProperty("is_deleted")
    private Boolean isDeleted;
    
    @JsonProperty("is_approved")
    private Boolean isApproved;
    
    @JsonProperty("is_pending")
    private Boolean isPending;
    
    @JsonProperty("is_rejected")
    private Boolean isRejected;
    
    // User information (when needed)
    @JsonProperty("uploader_name")
    private String uploaderName;
    
    @JsonProperty("uploader_email")
    private String uploaderEmail;
    
    // Company information (when needed)
    @JsonProperty("company_name")
    private String companyName;
    
    // Download/access URLs (when needed)
    @JsonProperty("download_url")
    private String downloadUrl;
    
    @JsonProperty("thumbnail_url")
    private String thumbnailUrl;
    
    @JsonProperty("preview_url")
    private String previewUrl;
    
    // Constructors
    public MediaDto() {
    }
    
    public MediaDto(Long id, String mediaCode, Long companyId, Long uploadedBy, 
                    String originalFilename, String storedFilename, String filePath,
                    Long fileSize, String mimeType, MediaFormat format) {
        this.id = id;
        this.mediaCode = mediaCode;
        this.companyId = companyId;
        this.uploadedBy = uploadedBy;
        this.originalFilename = originalFilename;
        this.storedFilename = storedFilename;
        this.filePath = filePath;
        this.fileSize = fileSize;
        this.mimeType = mimeType;
        this.format = format;
    }
    
    // Business methods
    public String getFileExtension() {
        if (originalFilename != null && originalFilename.contains(".")) {
            return originalFilename.substring(originalFilename.lastIndexOf(".") + 1).toLowerCase();
        }
        return "";
    }
    
    public String getFileSizeFormatted() {
        if (fileSize == null) return "0 B";
        
        long bytes = fileSize;
        if (bytes < 1024) return bytes + " B";
        if (bytes < 1024 * 1024) return String.format("%.1f KB", bytes / 1024.0);
        if (bytes < 1024 * 1024 * 1024) return String.format("%.1f MB", bytes / (1024.0 * 1024.0));
        return String.format("%.1f GB", bytes / (1024.0 * 1024.0 * 1024.0));
    }
    
    public String getDurationFormatted() {
        if (durationSeconds == null) return null;
        
        int hours = durationSeconds / 3600;
        int minutes = (durationSeconds % 3600) / 60;
        int seconds = durationSeconds % 60;
        
        if (hours > 0) {
            return String.format("%d:%02d:%02d", hours, minutes, seconds);
        } else {
            return String.format("%d:%02d", minutes, seconds);
        }
    }
    
    // Getters and Setters
    public Long getId() {
        return id;
    }
    
    public void setId(Long id) {
        this.id = id;
    }
    
    public String getMediaCode() {
        return mediaCode;
    }
    
    public void setMediaCode(String mediaCode) {
        this.mediaCode = mediaCode;
    }
    
    public Long getCompanyId() {
        return companyId;
    }
    
    public void setCompanyId(Long companyId) {
        this.companyId = companyId;
    }
    
    public Long getUploadedBy() {
        return uploadedBy;
    }
    
    public void setUploadedBy(Long uploadedBy) {
        this.uploadedBy = uploadedBy;
    }
    
    public String getOriginalFilename() {
        return originalFilename;
    }
    
    public void setOriginalFilename(String originalFilename) {
        this.originalFilename = originalFilename;
    }
    
    public String getStoredFilename() {
        return storedFilename;
    }
    
    public void setStoredFilename(String storedFilename) {
        this.storedFilename = storedFilename;
    }
    
    public String getFilePath() {
        return filePath;
    }
    
    public void setFilePath(String filePath) {
        this.filePath = filePath;
    }
    
    public Long getFileSize() {
        return fileSize;
    }
    
    public void setFileSize(Long fileSize) {
        this.fileSize = fileSize;
        this.fileSizeFormatted = getFileSizeFormatted();
    }
    
    public String getMimeType() {
        return mimeType;
    }
    
    public void setMimeType(String mimeType) {
        this.mimeType = mimeType;
    }
    
    public MediaFormat getFormat() {
        return format;
    }
    
    public void setFormat(MediaFormat format) {
        this.format = format;
        // Set computed fields based on format
        if (format != null) {
            this.isImage = format.name().startsWith("IMAGE_");
            this.isVideo = format.name().startsWith("VIDEO_");
            this.isAudio = format.name().startsWith("AUDIO_");
            this.isDocument = format.name().startsWith("DOCUMENT_");
            this.isArchive = format.name().startsWith("ARCHIVE_");
        }
    }
    
    public Integer getWidth() {
        return width;
    }
    
    public void setWidth(Integer width) {
        this.width = width;
    }
    
    public Integer getHeight() {
        return height;
    }
    
    public void setHeight(Integer height) {
        this.height = height;
    }
    
    public Integer getDurationSeconds() {
        return durationSeconds;
    }
    
    public void setDurationSeconds(Integer durationSeconds) {
        this.durationSeconds = durationSeconds;
        this.durationFormatted = getDurationFormatted();
    }
    
    public Boolean getIsPublic() {
        return isPublic;
    }
    
    public void setIsPublic(Boolean isPublic) {
        this.isPublic = isPublic;
    }
    
    public String getDescription() {
        return description;
    }
    
    public void setDescription(String description) {
        this.description = description;
    }
    
    public String getAltText() {
        return altText;
    }
    
    public void setAltText(String altText) {
        this.altText = altText;
    }
    
    public Map<String, Object> getMetadata() {
        return metadata;
    }
    
    public void setMetadata(Map<String, Object> metadata) {
        this.metadata = metadata;
    }
    
    public String getFileChecksum() {
        return fileChecksum;
    }
    
    public void setFileChecksum(String fileChecksum) {
        this.fileChecksum = fileChecksum;
    }
    
    public String getStorageProvider() {
        return storageProvider;
    }
    
    public void setStorageProvider(String storageProvider) {
        this.storageProvider = storageProvider;
    }
    
    public MediaValidationStatus getValidationStatus() {
        return validationStatus;
    }
    
    public void setValidationStatus(MediaValidationStatus validationStatus) {
        this.validationStatus = validationStatus;
        // Set computed fields based on validation status
        if (validationStatus != null) {
            this.isApproved = validationStatus == MediaValidationStatus.APPROVED;
            this.isPending = validationStatus == MediaValidationStatus.PENDING;
            this.isRejected = validationStatus == MediaValidationStatus.REJECTED;
        }
    }
    
    public String getValidationNotes() {
        return validationNotes;
    }
    
    public void setValidationNotes(String validationNotes) {
        this.validationNotes = validationNotes;
    }
    
    public LocalDateTime getDeletedAt() {
        return deletedAt;
    }
    
    public void setDeletedAt(LocalDateTime deletedAt) {
        this.deletedAt = deletedAt;
        this.isDeleted = deletedAt != null;
    }
    
    public LocalDateTime getUploadedAt() {
        return uploadedAt;
    }
    
    public void setUploadedAt(LocalDateTime uploadedAt) {
        this.uploadedAt = uploadedAt;
    }
    
    public LocalDateTime getUpdatedAt() {
        return updatedAt;
    }
    
    public void setUpdatedAt(LocalDateTime updatedAt) {
        this.updatedAt = updatedAt;
    }
    
    public Boolean getIsImage() {
        return isImage;
    }
    
    public void setIsImage(Boolean isImage) {
        this.isImage = isImage;
    }
    
    public Boolean getIsVideo() {
        return isVideo;
    }
    
    public void setIsVideo(Boolean isVideo) {
        this.isVideo = isVideo;
    }
    
    public Boolean getIsAudio() {
        return isAudio;
    }
    
    public void setIsAudio(Boolean isAudio) {
        this.isAudio = isAudio;
    }
    
    public Boolean getIsDocument() {
        return isDocument;
    }
    
    public void setIsDocument(Boolean isDocument) {
        this.isDocument = isDocument;
    }
    
    public Boolean getIsArchive() {
        return isArchive;
    }
    
    public void setIsArchive(Boolean isArchive) {
        this.isArchive = isArchive;
    }
    
    public Boolean getIsDeleted() {
        return isDeleted;
    }
    
    public void setIsDeleted(Boolean isDeleted) {
        this.isDeleted = isDeleted;
    }
    
    public Boolean getIsApproved() {
        return isApproved;
    }
    
    public void setIsApproved(Boolean isApproved) {
        this.isApproved = isApproved;
    }
    
    public Boolean getIsPending() {
        return isPending;
    }
    
    public void setIsPending(Boolean isPending) {
        this.isPending = isPending;
    }
    
    public Boolean getIsRejected() {
        return isRejected;
    }
    
    public void setIsRejected(Boolean isRejected) {
        this.isRejected = isRejected;
    }
    
    public String getUploaderName() {
        return uploaderName;
    }
    
    public void setUploaderName(String uploaderName) {
        this.uploaderName = uploaderName;
    }
    
    public String getUploaderEmail() {
        return uploaderEmail;
    }
    
    public void setUploaderEmail(String uploaderEmail) {
        this.uploaderEmail = uploaderEmail;
    }
    
    public String getCompanyName() {
        return companyName;
    }
    
    public void setCompanyName(String companyName) {
        this.companyName = companyName;
    }
    
    public String getDownloadUrl() {
        return downloadUrl;
    }
    
    public void setDownloadUrl(String downloadUrl) {
        this.downloadUrl = downloadUrl;
    }
    
    public String getThumbnailUrl() {
        return thumbnailUrl;
    }
    
    public void setThumbnailUrl(String thumbnailUrl) {
        this.thumbnailUrl = thumbnailUrl;
    }
    
    public String getPreviewUrl() {
        return previewUrl;
    }
    
    public void setPreviewUrl(String previewUrl) {
        this.previewUrl = previewUrl;
    }
    
    // equals and hashCode
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        MediaDto mediaDto = (MediaDto) o;
        return Objects.equals(id, mediaDto.id) && Objects.equals(storedFilename, mediaDto.storedFilename);
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(id, storedFilename);
    }
    
    @Override
    public String toString() {
        return "MediaDto{" +
                "id=" + id +
                ", mediaCode='" + mediaCode + '\'' +
                ", companyId=" + companyId +
                ", uploadedBy=" + uploadedBy +
                ", originalFilename='" + originalFilename + '\'' +
                ", storedFilename='" + storedFilename + '\'' +
                ", fileSize=" + fileSize +
                ", format=" + format +
                ", validationStatus=" + validationStatus +
                ", isPublic=" + isPublic +
                ", uploadedAt=" + uploadedAt +
                '}';
    }
}
