package ru.soune.nocopy.entity.file;

import com.fasterxml.jackson.annotation.JsonIgnore;
import jakarta.persistence.*;
import lombok.*;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
import ru.soune.nocopy.entity.file.permission.PermissionType;
import ru.soune.nocopy.entity.monitoring.FileMonitoringEntity;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "file_entities")
@EntityListeners(AuditingEntityListener.class)
public class FileEntity {

    private static AtomicInteger supportIdCounter = new AtomicInteger(0);

    @Id
    @GeneratedValue(strategy = GenerationType.UUID)
    private String id;

    @Column(name = "support_id", unique = true, updatable = false)
    private Integer supportId;

    @Column(name = "user_id", nullable = false)
    private Long userId;

    @Column(name = "original_file_name", nullable = false)
    private String originalFileName;

    @Column(name = "stored_file_name", nullable = false)
    private String storedFileName;

    @Column(name = "file_path", nullable = false, unique = true)
    private String filePath;

    @Column(name = "file_size", nullable = false)
    private Long fileSize;

    @Column(name = "mime_type")
    private String mimeType;

    @Column(name = "file_extension")
    private String fileExtension;

    @Column(name = "checksum")
    private String checksum;

    @Column(name = "upload_session_id")
    private String uploadSessionId;

    @Enumerated(EnumType.STRING)
    @Column(name = "status")
    private FileStatus status;

    @CreatedDate
    @Column(name = "created_at", updatable = false)
    private LocalDateTime createdAt;

    @LastModifiedDate
    @Column(name = "updated_at")
    private LocalDateTime updatedAt;

    @Column(name = "protected_file_path")
    private String protectedFilePath;

    @Column(name = "protection_status")
    @Enumerated(EnumType.STRING)
    private ProtectionStatus protectionStatus;

    @Column(name = "protected_at")
    private LocalDateTime protectedAt;

    @Column(name = "signature")
    @JsonIgnore
    private String signature;

    @Column(name = "thumbnail_path")
    private String thumbnailPath;

    @Column(name = "medium_path")
    private String mediumPath;

    @Column
    private String newExtension;

    @ElementCollection
    @CollectionTable(name = "file_permissions",
            joinColumns = @JoinColumn(name = "file_id"))
    @Column(name = "allowed")
    @MapKeyEnumerated(EnumType.STRING)
    @MapKeyColumn(name = "permission_type")
    private Map<PermissionType, Boolean> permissions = new HashMap<>();

    @OneToOne(mappedBy = "file", cascade = CascadeType.ALL, orphanRemoval = true)
    @JsonIgnore
    private ImageHashEntity imageHash;

    @PrePersist
    public void prePersist() {
        if (this.supportId == null) {
            this.supportId = supportIdCounter.incrementAndGet();
        }

        if (this.status == null) {
            this.status = FileStatus.MODERATION;
        }

        if (this.protectionStatus == null) {
            this.protectionStatus = ProtectionStatus.NOT_PROTECTED;
        }

        if (this.createdAt == null) {
            this.createdAt = LocalDateTime.now();
        }

        if (this.permissions == null) {
            this.permissions = new HashMap<>();
            this.permissions.put(PermissionType.DOWNLOAD, true);
//            this.permissions.put(PermissionType.VIEW, true);
//            this.permissions.put(PermissionType.EDIT, true);
        }


        this.updatedAt = LocalDateTime.now();
    }

    @PreUpdate
    public void preUpdate() {
        this.updatedAt = LocalDateTime.now();
    }

    public static void initializeCounter(int maxId) {
        supportIdCounter = new AtomicInteger(maxId);
    }

    @Transient
    public boolean hasPermission(PermissionType type) {
        return permissions.getOrDefault(type, false);
    }

    @Transient
    public void setPermission(PermissionType type, boolean allowed) {
        permissions.put(type, allowed);
    }

    @Transient
    public boolean canDownload() {
        return hasPermission(PermissionType.DOWNLOAD);
    }

//    @Transient
//    public boolean canView() {
//        return hasPermission(PermissionType.VIEW);
//    }
//
//    @Transient
//    public boolean canEdit() {
//        return hasPermission(PermissionType.EDIT);
//    }
}
