package com.iqser.red.service.persistence.management.v1.processor.utils;

import static org.assertj.core.api.Assertions.assertThat;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.InputStream;
import java.io.ObjectOutputStream;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.SplittableRandom;

import org.junit.jupiter.api.Test;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class FileSystemBackedArchiverTest {

    private final static byte[] dummyFileContent = new byte[]{1, 2};


    @Test
    @SneakyThrows
    public void testFileSystemBackedArchiver() {

        try (var fileSystemBackedArchiver = new FileSystemBackedArchiver(true)) {

            SplittableRandom sr = new SplittableRandom();

            var data = sr.doubles().limit(1024 * 1024).toArray();
            for (int i = 0; i < 10; i++) {
                log.info("At entry: {}, using {}MB of memory", i, (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) / (1024 * 1024));

                try (ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos)) {
                    oos.writeObject(data);
                    byte[] bytes = bos.toByteArray();
                    var entry = new FileSystemBackedArchiver.ArchiveModel("folder-" + i, "file-" + i, bytes);
                    fileSystemBackedArchiver.addEntry(entry);
                }
            }

            File tempFile = File.createTempFile("test", ".zip");

            var contentSize = fileSystemBackedArchiver.getContentLength();

            try (InputStream inputStream = fileSystemBackedArchiver.toInputStream()) {
                Files.copy(inputStream, tempFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
                log.info("File: {}", tempFile.getAbsolutePath());
            }

            assertThat(tempFile.length()).isEqualTo(contentSize);

            log.info("Total File Size: {}MB", tempFile.length() / (1024 * 1024));

            Files.delete(tempFile.toPath());
        }
    }


    @Test
    public void testContentLengthForTwoEntries() {

        try (var fileSystemBackedArchiver = new FileSystemBackedArchiver(true)) {

            fileSystemBackedArchiver.addEntry(new FileSystemBackedArchiver.ArchiveModel("Original", "original", dummyFileContent));
            fileSystemBackedArchiver.addEntry(new FileSystemBackedArchiver.ArchiveModel("Preview", "preview", dummyFileContent));

            assertThat(fileSystemBackedArchiver.getContentLength()).isGreaterThan(0);
        }
    }


    @Test
    @SneakyThrows
    public void testContentLengthForTwoEntriesAndStream() {

        try (var fileSystemBackedArchiver = new FileSystemBackedArchiver(true)) {

            fileSystemBackedArchiver.addEntry(new FileSystemBackedArchiver.ArchiveModel("Original", "original", dummyFileContent));
            fileSystemBackedArchiver.addEntry(new FileSystemBackedArchiver.ArchiveModel("Preview", "preview", dummyFileContent));

            try (InputStream stream = fileSystemBackedArchiver.toInputStream()) {
                // Dummy statement to just have the code do something with the stream
                //noinspection ResultOfMethodCallIgnored
                stream.getClass();
            }

            assertThat(fileSystemBackedArchiver.getContentLength()).isGreaterThan(0);
        }
    }


    @Test
    public void testContentLengthForTwoEntriesWithClosing() {
        // deliberately do not use try-with-resources to see if the content-length is available after temp file deletion
        var fileSystemBackedArchiver = new FileSystemBackedArchiver(true);

        fileSystemBackedArchiver.addEntry(new FileSystemBackedArchiver.ArchiveModel("Original", "original", dummyFileContent));
        fileSystemBackedArchiver.addEntry(new FileSystemBackedArchiver.ArchiveModel("Preview", "preview", dummyFileContent));

        fileSystemBackedArchiver.close();

        assertThat(fileSystemBackedArchiver.getContentLength()).isGreaterThan(0);
    }

}