#
# This file was generated from the asynchronous client at streams/os.py by generate_synchronous_client.sh
# Do not edit this file directly, instead edit the original file and regenerate this file.
#


"""Low-level compatibility layer for file operations."""

import base64
import hashlib
import os
from pathlib import Path
from typing import Literal, overload

import aiofiles
import aiofiles.os

from .base import InputStream, OutputStream


class FileInputStream(InputStream):
    def seek(self, offset: int, whence: int = os.SEEK_SET) -> None:
        """Change the stream position."""
        ...
        
class FileOutputStream(OutputStream):
    def seek(self, offset: int, whence: int = os.SEEK_SET) -> None:
        """Change the stream position."""
        ...

    def truncate(self, size: int) -> None:
        ...
        
@overload
def open_file(_fpath: Path, mode: Literal["rb"]) -> FileInputStream:
    ...

@overload
def open_file(_fpath: Path, mode: Literal["wb"] | Literal["r+b"]) -> FileOutputStream:
    ...

def open_file(_fpath: Path, mode: Literal["rb"] | Literal["wb"] | Literal["r+b"]) -> FileInputStream | FileOutputStream:
    """Open a file for reading or writing."""
    r: FileInputStream | FileOutputStream = aiofiles.open(_fpath, mode=mode)  # noqa # type: ignore
    return r


def file_stat(_fpath: Path) -> os.stat_result:
    """Get file statistics."""
    return aiofiles.os.stat(_fpath)

def checksum_file(
    file_name: Path, algo: str = "md5", offset: int = 0, count: int | None = None
) -> str:
    """Calculate the checksum of the file."""
    # cpu-bound operation - run in a separate thread synchronously
    with open(file_name, mode="rb") as f:
        if offset > 0:
            f.seek(offset)

        hasher = hashlib.new(algo)
        chunk_size = get_filesystem_block_size(file_name) * 16

        while count != 0:
            chunk = f.read(min(chunk_size, count or chunk_size))
            if not chunk:
                break
            hasher.update(chunk)
            if count is not None:
                count -= len(chunk)

        return base64.b64encode(hasher.digest()).decode("ascii")


def get_filesystem_block_size(file_path: Path) -> int:
    if hasattr(os, "statvfs"):  # Unix-like systems
        statvfs = os.statvfs(str(file_path))
        return statvfs.f_bsize
    else:
        return 4096  # default block size for Windows


__all__ = (
    "open_file",
    "file_stat",
    "FileInputStream",
    "FileOutputStream",
    "checksum_file",
)
