from enum import Enum
from pathlib import Path

import zstandard as zstd


class CompressionLevel(int, Enum):
    fastest = -7
    normal = 3
    best = 22


class Compressor:
    """
    Class to handle compression of files using the zstd algorithm.

    Attributes:
        level (CompressionLevel): The compression level.
        parallel (bool): Whether to use parallel compression.
    """

    def __init__(self, level=CompressionLevel.normal, parallel=False):
        """
        Initializes the compressor with the specified compression level and parallel option.

        Args:
            level (CompressionLevel): The compression level for zstd compression (default is normal).
            parallel (bool): Whether to use multithreaded compression (default is False).
        """
        self.level = level
        self.parallel = parallel

    def compress_file(self, input_path, output_path):
        """
        Compresses a single file using zstd and writes the compressed data to the output path.

        Args:
            input_path (str or Path): The path to the file to compress.
            output_path (str or Path): The path where the compressed file will be saved.
        """
        if not Path(input_path).is_file():
            raise FileNotFoundError

        with open(input_path, 'rb') as f:
            data = f.read()
        cctx = zstd.ZstdCompressor(level=self.level.value)
        compressed = cctx.compress(data)
        with open(output_path, 'wb') as f:
            f.write(compressed)

        return output_path

    @staticmethod
    def decompress_file(input_path, output_path):
        """
        Decompresses a zstd compressed file and writes the decompressed data to the output path.
        """
        assert Path(input_path).is_file(), "Input path should be a file"

        with open(input_path, 'rb') as f:
            compressed_data = f.read()

        try:
            dctx = zstd.ZstdDecompressor()
            decompressed_data = dctx.decompress(compressed_data)
        except zstd.ZstdError as e:
            print(f"Decompression failed for {input_path}: {e}")
            raise

        with open(output_path, 'wb') as f:
            f.write(decompressed_data)

        return output_path
