"""
Protected module contains job request file classes
"""

from abc import ABC, abstractmethod
from contextlib import contextmanager
from io import BufferedReader, BytesIO
from pathlib import Path
from typing import Generator


class JobRequestFile(ABC):
    """
    Abstract Job Request File Interface for the blue API.
    This interface is implemented by #JobRequestFileFromPath, #JobRequestFileFromReader and JobRequestFileFromBytes.

    """

    @abstractmethod
    def __init__(self):
        raise NotImplementedError

    @property
    @abstractmethod
    def size(self) -> int:
        """
        File size in bytes. This information is required by the RPC API.

        Returns:
            int: File size in bytes.
        """
        raise NotImplementedError

    @property
    @abstractmethod
    def extension(self) -> str:
        """
        File extension as required by the PRC API.

        Returns:
           str: File extension without the dot (e.g., "txt" for file.txt).
        """
        raise NotImplementedError

    @abstractmethod
    @contextmanager
    def open(self) -> Generator[BufferedReader, None, None]:
        """
        Abstract method that returns a context manager for the file as BufferedReader.

        Returns:
           context manager with a BufferedReader.
        """
        raise NotImplementedError


class JobRequestFileFromPath(JobRequestFile):
    """
    Implements the JobRequestFile interface for a file located at a specific path on the filesystem.

    Args:
        path (str | Path): The path to the file on the filesystem.

    """

    def __init__(self, path: str | Path):
        if isinstance(path, Path):
            self.path = path
        else:
            self.path = Path(path)

    @property
    def size(self) -> int:
        return self.path.stat().st_size

    @property
    def extension(self) -> str:
        return self.path.suffix[1:]

    @contextmanager
    def open(self) -> Generator[BufferedReader, None, None]:
        file = None
        try:
            file = open(self.path, "rb")
            yield file
        finally:
            if file is not None:
                file.close()


class JobRequestFileFromReader(JobRequestFile):
    """
    Implements the JobRequestFile interface for a file that is provided as a BufferedReader.

    Args:
       reader (BufferedReader): The BufferedReader object that provides the file content.
       size (int): The size of the file.
       extension (str): The file extension.
    """

    def __init__(self, reader: BufferedReader, size: int, extension: str):
        self._size = size
        self._extension = extension
        self._reader = reader

    @contextmanager
    def open(self) -> Generator[BufferedReader, None, None]:
        yield self._reader

    @property
    def size(self) -> int:
        return self._size

    @property
    def extension(self) -> str:
        return self._extension


class JobRequestFileFromBytes(JobRequestFile):
    """
    Implements the JobRequestFile interface for a file that is provided as bytes.

    Args:
       file_bytes (bytes): The bytes of the file.
       extension (str): The file extension.
    """

    def __init__(self, file_bytes: bytes, extension: str):
        self._extension = extension
        self._bytes = file_bytes

    @contextmanager
    def open(self) -> Generator[BufferedReader, None, None]:
        yield BufferedReader(BytesIO(self._bytes))

    @property
    def size(self) -> int:
        return len(self._bytes)

    @property
    def extension(self) -> str:
        return self._extension
