# Copyright 2026 The Gitea Authors. All rights reserved.
# SPDX-License-Identifier: MIT

"""Exception classes for the Gitea SDK."""

from typing import Optional, Dict, Any


class GiteaError(Exception):
    """Base exception for all Gitea SDK errors."""

    def __init__(self, message: str):
        self.message = message
        super().__init__(message)


class APIError(GiteaError):
    """Raised when the API returns an error response."""

    def __init__(
        self,
        message: str,
        code: Optional[str] = None,
        status: int = 0,
        details: Optional[Dict[str, Any]] = None,
    ):
        super().__init__(message)
        self.code = code
        self.status = status
        self.details = details or {}

    def __str__(self) -> str:
        if self.code:
            return f"[{self.code}] {self.message}"
        return self.message


class AuthenticationError(APIError):
    """Raised when authentication fails."""

    def __init__(self, message: str = "Authentication failed", code: str = "AUTH_FAILED"):
        super().__init__(message, code=code, status=401)


class NotFoundError(APIError):
    """Raised when a resource is not found."""

    def __init__(self, resource: str, identifier: str = ""):
        message = f"{resource} not found"
        if identifier:
            message = f"{resource} '{identifier}' not found"
        super().__init__(message, code="NOT_FOUND", status=404)
        self.resource = resource
        self.identifier = identifier


class ValidationError(APIError):
    """Raised when request validation fails."""

    def __init__(self, message: str, field: Optional[str] = None):
        super().__init__(message, code="VALIDATION_FAILED", status=400)
        self.field = field


class UploadError(GiteaError):
    """Raised when an upload fails."""

    def __init__(self, message: str, session_id: Optional[str] = None, chunk: Optional[int] = None):
        super().__init__(message)
        self.session_id = session_id
        self.chunk = chunk

    def __str__(self) -> str:
        parts = [self.message]
        if self.session_id:
            parts.append(f"session={self.session_id}")
        if self.chunk is not None:
            parts.append(f"chunk={self.chunk}")
        return " ".join(parts)


class RateLimitError(APIError):
    """Raised when rate limit is exceeded."""

    def __init__(self, retry_after: Optional[int] = None):
        message = "Rate limit exceeded"
        if retry_after:
            message += f". Retry after {retry_after} seconds"
        super().__init__(message, code="RATE_LIMIT_EXCEEDED", status=429)
        self.retry_after = retry_after
