package dev.lions.models;

import dev.lions.utils.ImageType;
import jakarta.persistence.*;
import jakarta.validation.constraints.*;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.io.Serializable;
import java.time.LocalDateTime;

/**
 * Entité représentant une image associée à un projet.
 * Cette classe gère les métadonnées et le stockage des images
 * avec support pour différents types et versions.
 */
@Slf4j
@Data
@Entity
@Table(name = "project_images")
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ProjectImage implements Serializable {

  private static final long serialVersionUID = 1L;
  private static final int MAX_FILE_SIZE = 10485760; // 10MB

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;

  @ManyToOne(fetch = FetchType.LAZY)
  @JoinColumn(name = "project_id", nullable = false)
  @NotNull(message = "Le projet associé est requis")
  private Project project;

  @Column(nullable = false)
  @NotBlank(message = "Le nom du fichier est requis")
  @Size(max = 255, message = "Le nom du fichier ne peut pas dépasser 255 caractères")
  private String fileName;

  @ManyToOne
  @JoinColumn(name = "type_id", nullable = false)
  @NotNull(message = "Le type d'image est requis")
  private ImageType type;

  @Column(nullable = false)
  @Min(value = 1, message = "La largeur doit être positive")
  @Max(value = 10000, message = "La largeur ne peut pas dépasser 10000 pixels")
  private Integer width;

  @Column(nullable = false)
  @Min(value = 1, message = "La hauteur doit être positive")
  @Max(value = 10000, message = "La hauteur ne peut pas dépasser 10000 pixels")
  private Integer height;

  @Column(nullable = false)
  @Min(value = 1, message = "La taille du fichier doit être positive")
  @Max(value = MAX_FILE_SIZE, message = "La taille du fichier ne peut pas dépasser 10MB")
  private Long fileSize;

  @Column(length = 500)
  @Size(max = 500, message = "Le texte alternatif ne peut pas dépasser 500 caractères")
  private String altText;

  @Column(name = "mime_type")
  @NotBlank(message = "Le type MIME est requis")
  @Pattern(regexp = "^image/[a-zA-Z0-9.+-]+$",
           message = "Type MIME invalide")
  private String mimeType;

  @Column(nullable = false)
  private LocalDateTime uploadDate;

  @Column(name = "last_modified")
  private LocalDateTime lastModified;

  @Column(name = "checksum")
  @NotBlank(message = "Le checksum est requis")
  private String checksum;

  @Version
  private Long version;

  /**
   * Initialise les champs par défaut avant la persistance.
   */
  @PrePersist
  protected void onCreate() {
    if (uploadDate == null) {
      uploadDate = LocalDateTime.now();
    }
    lastModified = uploadDate;
  }

  /**
   * Met à jour la date de modification avant la mise à jour.
   */
  @PreUpdate
  protected void onUpdate() {
    lastModified = LocalDateTime.now();
  }

  /**
   * Calcule le ratio d'aspect de l'image.
   *
   * @return Ratio largeur/hauteur
   */
  public double getAspectRatio() {
    return width.doubleValue() / height.doubleValue();
  }

  /**
   * Vérifie si l'image est en mode portrait.
   *
   * @return true si la hauteur est supérieure à la largeur
   */
  public boolean isPortrait() {
    return height > width;
  }

  /**
   * Vérifie si l'image est en mode paysage.
   *
   * @return true si la largeur est supérieure à la hauteur
   */
  public boolean isLandscape() {
    return width > height;
  }

  /**
   * Vérifie si l'image est carrée.
   *
   * @return true si la largeur est égale à la hauteur
   */
  public boolean isSquare() {
    return width.equals(height);
  }

  /**
   * Génère une URL relative pour l'image.
   *
   * @return URL relative de l'image
   */
  public String getRelativeUrl() {
    return String.format("/images/projects/%d/%s", project.getId(), fileName);
  }

  /**
   * Vérifie si la taille de l'image est valide.
   *
   * @return true si les dimensions sont valides
   */
  public boolean hasValidDimensions() {
    return width > 0 && width <= 10000 &&
           height > 0 && height <= 10000;
  }

  /**
   * Vérifie si la taille du fichier est valide.
   *
   * @return true si la taille est valide
   */
  public boolean hasValidFileSize() {
    return fileSize > 0 && fileSize <= MAX_FILE_SIZE;
  }

  /**
   * Calcule la taille en mégaoctets.
   *
   * @return Taille en Mo
   */
  public double getSizeInMB() {
    return fileSize / (1024.0 * 1024.0);
  }
}