package ru.soune.nocopy.service.file;

import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import ru.soune.nocopy.dto.file.FileInfoUserResponse;
import ru.soune.nocopy.entity.file.FileEntity;
import ru.soune.nocopy.entity.file.FileStatus;
import ru.soune.nocopy.entity.file.FileType;
import ru.soune.nocopy.entity.file.ProtectionStatus;
import ru.soune.nocopy.entity.user.User;
import ru.soune.nocopy.repository.FileEntityRepository;
import ru.soune.nocopy.repository.UserRepository;
import ru.soune.nocopy.service.CompanyService;

import java.util.ArrayList;
import java.util.List;

@Service
@RequiredArgsConstructor
public class FileStatsService {

    private final FileEntityRepository fileEntityRepository;

    private final CompanyService companyService;

    private final UserRepository userRepository;

    private final FileEntityService fileEntityService;

    public FileInfoUserResponse getUserFileStats(Long userId) {
        List<FileEntity> userFiles = fileEntityService.getAllUserFiles(userId, List.of(FileStatus.ACTIVE,
                FileStatus.BLOCKED, FileStatus.MODERATION));

        return calculateStats(userFiles);
    }

    public FileInfoUserResponse calculateStats(List<FileEntity> files) {
        return FileInfoUserResponse.builder()
                .allFileSize(calculateTotalSize(files))
                .fileCount(calculateTotalCount(files))
//                .filesCheck(calculateByStatus(files, FileStatus.CHECKED))
//                .filesViolation(calculateByStatus(files, FileStatus.VIOLATION))
                .protectedFilesCount(protectedUserFiles(files))

                .imagesSize(calculateMediaSize(files, FileType.IMAGE))
                .imagesCount(calculateMediaCount(files, FileType.IMAGE))
                .protectedImageFilesCount(protectedUserFiles(files, FileType.IMAGE))

                .videosSize(calculateMediaSize(files, FileType.VIDEO))
                .videosCount(calculateMediaCount(files, FileType.VIDEO))
                .protectedVideoFilesCount(protectedUserFiles(files, FileType.VIDEO))

                .audiosSize(calculateMediaSize(files, FileType.AUDIO))
                .audiosCount(calculateMediaCount(files, FileType.AUDIO))
                .protectedAudioFilesCount(protectedUserFiles(files, FileType.AUDIO))

                .documentSize(calculateMediaSize(files, FileType.DOCUMENT))
                .documentCount(calculateMediaCount(files, FileType.DOCUMENT))
                .protectedDocumentFilesCount(protectedUserFiles(files, FileType.DOCUMENT))
                .build();
    }

    public Long calculateUserFileSize(Long userId) {
        List<FileEntity> userFiles = fileEntityRepository.findByUserId(userId);

        return calculateTotalSize(userFiles);
    }

    public Long calculateCompanyFileSize(Long userId) {
        User user = userRepository.findById(userId).orElseThrow();

        List<User> companyUsers = companyService.getCompanyUsers(user.getCompany().getId());

        List<FileEntity> userFiles = new ArrayList<>();

        for (User companyUser : companyUsers) {
            userFiles.addAll(fileEntityRepository.findByUserId(companyUser.getId()));
        }

        return calculateTotalSize(userFiles);
    }

    public Integer filesUserCount(Long userId) {
        List<FileEntity> userFiles = fileEntityRepository.findByUserId(userId);

        return calculateTotalCount(userFiles);
    }


    public Integer filesCompanyCount(Long userId) {
        User user = userRepository.findById(userId).orElseThrow();

        List<User> companyUsers = companyService.getCompanyUsers(user.getCompany().getId());

        List<FileEntity> userFiles = new ArrayList<>();

        for (User companyUser : companyUsers) {
            userFiles.addAll(fileEntityRepository.findByUserId(companyUser.getId()));
        }

        return calculateTotalCount(userFiles);
    }

    private Long protectedUserFiles(List<FileEntity> files) {
        return files.stream().filter(file -> file.getProtectionStatus() == ProtectionStatus.PROTECTED).count();
    }

    private Long protectedUserFiles(List<FileEntity> files, FileType type) {
        return files.stream().filter(file -> file.getStatus() != FileStatus.DELETED &&
                file.getStatus() != FileStatus.TEMP &&
                file.getProtectionStatus() == ProtectionStatus.PROTECTED &&
                file.getMimeType().equals(type.getDisplayName())).count();
    }

    private Long calculateTotalSize(List<FileEntity> files) {
        return files.stream()
                .filter(file -> file.getStatus() != FileStatus.DELETED && file.getStatus() != FileStatus.TEMP)
                .mapToLong(FileEntity::getFileSize)
                .sum();
    }

    private Integer calculateTotalCount(List<FileEntity> files) {
        return (int) files.stream()
                .filter(file -> file.getStatus() != FileStatus.DELETED && file.getStatus() != FileStatus.TEMP)
                .count();
    }

    private Integer calculateByStatus(List<FileEntity> files, FileStatus status) {
        return (int) files.stream()
                .filter(file -> file.getStatus() == status)
                .count();
    }

    private Long calculateMediaSize(List<FileEntity> files, FileType fileType) {
        return files.stream()
                .filter(file -> file.getStatus() != FileStatus.DELETED && file.getStatus() != FileStatus.TEMP)
                .filter(file -> isFileType(file, fileType))
                .mapToLong(FileEntity::getFileSize)
                .sum();
    }

    private Integer calculateMediaCount(List<FileEntity> files, FileType fileType) {
        return (int) files.stream()
                .filter(file -> file.getStatus() != FileStatus.DELETED && file.getStatus() != FileStatus.TEMP)
                .filter(file -> isFileType(file, fileType))
                .count();
    }

    private Integer calculateMediaByStatus(List<FileEntity> files, FileType fileType, FileStatus status) {
        return (int) files.stream()
                .filter(file -> isFileType(file, fileType))
                .filter(file -> file.getStatus() == status)
                .count();
    }

    private boolean isFileType(FileEntity file, FileType fileType) {
        if (file.getFileExtension() == null) return false;

        String extension = file.getFileExtension().toLowerCase().replace(".", "");
        return fileType.supportsExtension(extension);
    }
}
