package ru.soune.nocopy.service.file;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import ru.soune.nocopy.entity.file.FileEntity;
import ru.soune.nocopy.entity.file.moderation.ModerationPassportFile;
import ru.soune.nocopy.service.file.cloud.CloudStorageService;
import ru.soune.nocopy.service.file.moderation.ModerationFileService;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Base64;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

@Service
@Slf4j
@RequiredArgsConstructor
public class ZipService {

    private final ModerationFileService moderationFileService;
    private final CloudStorageService cloudStorageService;

    private static final int MAX_SIZE_MB = 20;
    private static final int FIRST_PART = 1;
    private static final int SECOND_PART = 2;

    @Value("${yandex.cloud.bucket-cold}")
    private String bucketCold;

    public void createAndSplitZip(Long userId, List<FileEntity> files) throws IOException {
        byte[] zipBytes = createZip(files);
        String base64String = Base64.getEncoder().encodeToString(zipBytes);
        String[] parts = splitBase64(base64String);
        saveSplitFiles(userId, parts[0], parts[1]);
    }

    public byte[] assembleZipFromSplitFiles(Long userId) throws IOException {
        List<ModerationPassportFile> activeFiles = moderationFileService.getActiveFilesByUserId(userId);

        String part1Key = null;
        String part2Key = null;

        for (ModerationPassportFile file : activeFiles) {
            if (file.getPart() == FIRST_PART) {
                part1Key = file.getPath();
            } else if (file.getPart() == SECOND_PART) {
                part2Key = file.getPath();
            }
        }

        if (part1Key == null || part2Key == null) {
            throw new IOException("Missing part 1 or part 2 for user: " + userId);
        }

        String part1Base64 = cloudStorageService.downloadPartFromBucket(bucketCold, part1Key);
        String part2Base64 = cloudStorageService.downloadPartFromBucket(bucketCold, part2Key);

        String fullBase64 = part1Base64 + part2Base64;

        log.debug("Part1 length: {}, Part2 length: {}, Combined length: {}",
                part1Base64.length(), part2Base64.length(), fullBase64.length());

        return Base64.getDecoder().decode(fullBase64);
    }

    private byte[] createZip(List<FileEntity> files) throws IOException {
        long totalSize = files.stream()
                .map(FileEntity::getFileSize)
                .reduce(0L, Long::sum);

        if (totalSize > MAX_SIZE_MB * 1024 * 1024) {
            throw new IllegalArgumentException(
                    String.format("Total size %.2f MB exceeds %d MB limit",
                            totalSize / (1024.0 * 1024.0), MAX_SIZE_MB)
            );
        }

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try (ZipOutputStream zos = new ZipOutputStream(baos)) {
            for (FileEntity file : files) {
                String filePath = file.getFilePath();
                String fileName = file.getStoredFileName();

                Path path = Paths.get(filePath);
                ZipEntry zipEntry = new ZipEntry(fileName);
                zos.putNextEntry(zipEntry);
                Files.copy(path, zos);
                zos.closeEntry();

                log.info("Added file {} to ZIP", fileName);
            }
        }

        return baos.toByteArray();
    }

    private String[] splitBase64(String base64) {
        int half = base64.length() / 2;
        return new String[]{
                base64.substring(0, half),
                base64.substring(half)
        };
    }

    private void saveSplitFiles(Long userId, String part1, String part2) throws IOException {
        Path userDir = Paths.get("/uploads/passport", String.valueOf(userId));
        Files.createDirectories(userDir);

        Path file1 = userDir.resolve(userId + "___1.txt");
        Files.writeString(file1, part1);
        Path file2 = userDir.resolve(userId + "___2.txt");
        Files.writeString(file2, part2);

        Map<String, String> cloudKeys = cloudStorageService.saveSplitPartsToColdStorage(userId, file1, file2);

        Map<Integer, String> files = Map.of(
                FIRST_PART, cloudKeys.get("part1"),
                SECOND_PART, cloudKeys.get("part2"));

        moderationFileService.addFiles(userId, files);

        log.info("Saved split files to cold storage for userId: {}, Base64 length: {}",
                userId, part1.length() + part2.length());
    }
}