package ru.soune.nocopy.service.file.impl;

import com.vrt.fileprotection.FileProtector;
import com.vrt.fileprotection.OperationResult;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.springframework.stereotype.Component;
import ru.soune.nocopy.entity.file.FileEntity;
import ru.soune.nocopy.repository.FileEntityRepository;
import ru.soune.nocopy.repository.FileUploadSessionRepository;
import ru.soune.nocopy.service.file.FileEntityService;
import ru.soune.nocopy.service.file.cloud.CloudStorageService;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

@Slf4j
@Component
@RequiredArgsConstructor
public class ProtectionFileProviderImpl implements FileProtector.FileProvider {

    private static final Path SIGNATURE_FILE_PATH = Paths.get("/data/uploads/signature");

    private final FileEntityService fileEntityService;

    private final FileUploadSessionRepository fileUploadSessionRepository;

    private final FileEntityRepository fileEntityRepository;

    private final CloudStorageService cloudStorageService;

    @Nullable
    @Override
    public File getImageFile(@NotNull String id) {
        FileEntity fileEntity = fileEntityRepository.findById(id).orElseThrow(() ->
                new RuntimeException("File not found: " + id));
        try {
            return cloudStorageService.readFileFromStorageByPath(fileEntity.getFilePath());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Nullable
    @Override
    public File getVideoFile(@NotNull String id) {
        FileEntity fileEntity = fileEntityRepository.findById(id).orElseThrow(() ->
                new RuntimeException("File not found: " + id));
        try {
            return cloudStorageService.readFileFromStorageByPath(fileEntity.getFilePath());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Nullable
    @Override
    public File getAudioFile(@NotNull String id) {
        FileEntity fileEntity = fileEntityRepository.findById(id).orElseThrow(() ->
                new RuntimeException("File not found: " + id));
        try {
            return cloudStorageService.readFileFromStorageByPath(fileEntity.getFilePath());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public @Nullable File getDocument(@NotNull String id) {
        FileEntity fileEntity = fileEntityRepository.findById(id).orElseThrow(() ->
                new RuntimeException("File not found: " + id));
        try {
            return cloudStorageService.readFileFromStorageByPath(fileEntity.getFilePath());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public @Nullable File getSignature() {
        File signatureFile = SIGNATURE_FILE_PATH.toFile();

        if (signatureFile.exists() && signatureFile.isFile() && signatureFile.length() > 0) {
            return signatureFile;
        }

        return null;
    }

    @Override
    public @NotNull OperationResult writeSignature(@NotNull byte[] bytes) {
        try {
            Path directory = SIGNATURE_FILE_PATH.getParent();

            if (directory != null && !Files.exists(directory)) {
                Files.createDirectories(directory);
            }

            Files.write(SIGNATURE_FILE_PATH, bytes);

            return OperationResult.Companion.success();
        } catch (IOException e) {
            return OperationResult.Companion.failure("Not saved signature file");
        }
    }

    @NotNull
    @Override
    public com.vrt.fileprotection.OperationResult writeAudioFile(@NotNull String id, @NotNull byte[] data, @Nullable String fileExt) {
        try {
            FileEntity fileEntity = fileEntityService.writeProtectedFile(id, data, fileExt);

            Path filePath = Paths.get(fileEntity.getProtectedFilePath());

            if (!Files.exists(filePath)) {
                log.error("File not found after write: {}", filePath);
                return OperationResult.Companion.failure("File not found");
            }

            log.info("File ready for upload: {} (size: {} bytes)", filePath, Files.size(filePath));

            cloudStorageService.saveFilesToStorage(fileEntity.getMimeType(), fileEntity.getFileExtension(),
                    fileEntity.getProtectedFilePath());

            return OperationResult.Companion.success();
        } catch (Exception e) {
            log.error("Failed to create protected file: {}", id, e);
            return OperationResult.Companion.failure("Failed to create protected file");
        }
    }

    @NotNull
    @Override
    public com.vrt.fileprotection.OperationResult writeVideoFile(@NotNull String id, @NotNull byte[] data, @Nullable String fileExt) {
        try {
            FileEntity fileEntity = fileEntityService.writeProtectedFile(id, data, fileExt);

            cloudStorageService.saveFilesToStorage(fileEntity.getMimeType(), fileEntity.getFileExtension(),
                    fileEntity.getProtectedFilePath());

            return OperationResult.Companion.success();
        } catch (Exception e) {
            log.error("Failed to create protected file: {}", id, e);
            return OperationResult.Companion.failure("Failed to create protected file");
        }
    }

    @NotNull
    @Override
    public com.vrt.fileprotection.OperationResult writeImageFile(@NotNull String id, @NotNull byte[] data, @Nullable String fileExt) {
        try {
            FileEntity fileEntity = fileEntityService.writeProtectedFile(id, data, fileExt);

            cloudStorageService.saveFilesToStorage(fileEntity.getMimeType(), fileEntity.getFileExtension(),
                    fileEntity.getProtectedFilePath());

            return OperationResult.Companion.success();
        } catch (Exception e) {
            log.error("Failed to create protected file: {}", id, e);
            return OperationResult.Companion.failure("Failed to create protected file");
        }
    }

    @Override
    public @NotNull OperationResult writeDocumentFile(@NotNull String id, @NotNull byte[] data) {
        try {
            FileEntity fileEntity = fileEntityService.writeProtectedFile(id, data, null);

            cloudStorageService.saveFilesToStorage(fileEntity.getMimeType(), fileEntity.getFileExtension(),
                    fileEntity.getProtectedFilePath());
            return OperationResult.Companion.success();
        } catch (Exception e) {
            log.error("Failed to create protected file: {}", id, e);
            return OperationResult.Companion.failure("Failed to create protected file");
        }
    }
}
