"""Exceptions raised by the Mariner module."""

from __future__ import annotations

import pathlib
from collections.abc import Sequence


class Error(Exception):
    """Base class for all exceptions raised by this module."""


class InputError(Error):
    """Wrong input by user."""


class EmptyKeywordsError(InputError):
    """Search keywords are empty."""

    def __init__(self) -> None:
        super().__init__("No string to search for.")


class NoTrackersError(InputError):
    """No trackers were specified for search."""

    def __init__(self) -> None:
        super().__init__("No torrent trackers to search on.")


class InvalidLimitError(InputError):
    """Search result limit is not a positive integer."""

    def __init__(self, limit: int) -> None:
        self.limit = limit
        super().__init__(
            f"Limit has to be higher than zero, got {limit}.",
        )


class UnknownConfigKeyError(InputError):
    """Configuration key does not exist."""

    def __init__(self, key: str) -> None:
        self.key = key
        super().__init__(f"Unknown configuration option: {key!r}.")


class HTTPError(Error):
    """Error during HTTP request."""

    def __init__(self, url: str, cause: Exception) -> None:
        self.url = url
        super().__init__(f"HTTP error for {url}: {cause}")


class NoResultError(Error):
    """No result found for given search."""


class ResultNotFoundError(NoResultError):
    """No torrent found for the given ID."""

    def __init__(self, tid: int) -> None:
        self.tid = tid
        super().__init__(f"No torrent with ID {tid}.")


class NoSearchResultsError(NoResultError):
    """Search returned zero results."""

    def __init__(self, keywords: str) -> None:
        self.keywords = keywords
        super().__init__(f"No results for {keywords!r}.")


class NoServerAvailableError(Error):
    """No server available for given tracker."""

    def __init__(self, tracker_name: str) -> None:
        self.tracker_name = tracker_name
        super().__init__(
            f"No servers available for tracker {tracker_name}.",
        )


class DefinitionsDirectoryError(Error):
    """Definitions directory does not exist or is not accessible."""

    def __init__(self, path: pathlib.Path) -> None:
        self.path = path
        super().__init__(
            f"Definitions directory does not exist: {path}",
        )


class NoDefinitionsFoundError(Error):
    """No valid tracker definitions found in the definitions directory."""

    def __init__(self, path: pathlib.Path) -> None:
        self.path = path
        super().__init__(
            f"No valid tracker definitions found in {path}.",
        )


class TrackerNotFoundError(Error):
    """Requested tracker ID is not in the registry."""

    def __init__(
        self,
        tracker_id: str,
        available: Sequence[str] | None = None,
    ) -> None:
        self.tracker_id = tracker_id
        self.available = list(available) if available else []
        msg = f"Unknown tracker: {tracker_id!r}."
        if self.available:
            msg += f" Available: {self.available}"
        super().__init__(msg)


class TrackerNotUserManagedError(Error):
    """Operation attempted on a shipped tracker that requires user ownership."""

    def __init__(self, tracker_id: str) -> None:
        self.tracker_id = tracker_id
        super().__init__(
            f"Tracker {tracker_id!r} is shipped with Mariner and cannot be modified.",
        )


class DefinitionFieldMissingError(Error):
    """A required field is absent from a tracker definition."""

    def __init__(self, tracker_id: str, field: str) -> None:
        self.tracker_id = tracker_id
        self.field = field
        super().__init__(
            f"Tracker {tracker_id!r} has no {field!r} field.",
        )
