"""Exception hierarchy for the :mod:`rclone` package."""

from __future__ import annotations

import shlex
from typing import Sequence

#: Human-readable meanings of rclone's documented exit codes.
#: See https://rclone.org/docs/#exit-code
EXIT_CODES = {
    0: "Success",
    1: "Syntax or usage error",
    2: "Error not otherwise categorised",
    3: "Directory not found",
    4: "File not found",
    5: "Temporary error (retries might fix it)",
    6: "Less serious errors (NoRetry errors)",
    7: "Fatal error (retries will not fix it)",
    8: "Transfer limit exceeded (--max-transfer)",
    9: "Operation successful, but no files were transferred",
    10: "Duration limit exceeded (--max-duration)",
}


class RcloneError(Exception):
    """Base class for every error raised by this package."""


class RcloneNotFoundError(RcloneError):
    """Raised when the rclone binary cannot be located."""


class RcloneCommandError(RcloneError):
    """Raised when an rclone command exits with a non-zero status.

    The original command, its exit code and any captured output are kept as
    attributes so callers can inspect or re-raise them.
    """

    def __init__(
        self,
        command: Sequence[str],
        returncode: int,
        stdout: str = "",
        stderr: str = "",
    ) -> None:
        self.command = list(command)
        self.returncode = returncode
        self.stdout = stdout
        self.stderr = stderr

        meaning = EXIT_CODES.get(returncode, "Unknown error")
        printable = " ".join(shlex.quote(part) for part in self.command)
        message = f"rclone exited with code {returncode} ({meaning}): {printable}"
        detail = (stderr or stdout or "").strip()
        if detail:
            message = f"{message}\n{detail}"
        super().__init__(message)
