"""Standardized error codes for the Trax platform.

This module defines error codes that provide consistent identification
and categorization of errors across the application.
"""

from enum import Enum
from typing import Dict, Optional


class ErrorSeverity(Enum):
    """Error severity levels."""
    LOW = "low"
    MEDIUM = "medium"
    HIGH = "high"
    CRITICAL = "critical"


class ErrorCategory(Enum):
    """Error categories for classification."""
    NETWORK = "network"
    API = "api"
    FILESYSTEM = "filesystem"
    VALIDATION = "validation"
    PROCESSING = "processing"
    CONFIGURATION = "configuration"
    AUTHENTICATION = "authentication"
    RESOURCE = "resource"


class ErrorCode:
    """Standardized error code with metadata."""
    
    def __init__(
        self,
        code: str,
        category: ErrorCategory,
        severity: ErrorSeverity,
        description: str,
        retryable: bool = False,
        actionable_message: Optional[str] = None
    ):
        self.code = code
        self.category = category
        self.severity = severity
        self.description = description
        self.retryable = retryable
        self.actionable_message = actionable_message or description
    
    def __str__(self) -> str:
        return self.code
    
    def __repr__(self) -> str:
        return f"ErrorCode({self.code}, {self.category.value}, {self.severity.value})"


# Network Errors (TRAX-NET-001 to TRAX-NET-099)
NETWORK_CONNECTION_FAILED = ErrorCode(
    "TRAX-NET-001",
    ErrorCategory.NETWORK,
    ErrorSeverity.HIGH,
    "Network connection failed",
    retryable=True,
    actionable_message="Check your internet connection and try again"
)

NETWORK_TIMEOUT = ErrorCode(
    "TRAX-NET-002",
    ErrorCategory.NETWORK,
    ErrorSeverity.MEDIUM,
    "Network request timed out",
    retryable=True,
    actionable_message="The request took too long. Try again or check your connection"
)

DNS_RESOLUTION_FAILED = ErrorCode(
    "TRAX-NET-003",
    ErrorCategory.NETWORK,
    ErrorSeverity.HIGH,
    "DNS resolution failed",
    retryable=True,
    actionable_message="Unable to resolve domain name. Check your DNS settings"
)

# API Errors (TRAX-API-001 to TRAX-API-099)
API_AUTHENTICATION_FAILED = ErrorCode(
    "TRAX-API-001",
    ErrorCategory.API,
    ErrorSeverity.CRITICAL,
    "API authentication failed",
    retryable=False,
    actionable_message="Invalid API key. Please check your configuration"
)

API_RATE_LIMIT_EXCEEDED = ErrorCode(
    "TRAX-API-002",
    ErrorCategory.API,
    ErrorSeverity.MEDIUM,
    "API rate limit exceeded",
    retryable=True,
    actionable_message="Too many requests. Please wait before trying again"
)

API_QUOTA_EXCEEDED = ErrorCode(
    "TRAX-API-003",
    ErrorCategory.API,
    ErrorSeverity.HIGH,
    "API quota exceeded",
    retryable=False,
    actionable_message="API quota limit reached. Please upgrade your plan"
)

API_SERVICE_UNAVAILABLE = ErrorCode(
    "TRAX-API-004",
    ErrorCategory.API,
    ErrorSeverity.HIGH,
    "API service unavailable",
    retryable=True,
    actionable_message="Service temporarily unavailable. Please try again later"
)

API_INVALID_RESPONSE = ErrorCode(
    "TRAX-API-005",
    ErrorCategory.API,
    ErrorSeverity.MEDIUM,
    "Invalid API response",
    retryable=True,
    actionable_message="Received invalid response from API. Retrying..."
)

# File System Errors (TRAX-FS-001 to TRAX-FS-099)
FILE_NOT_FOUND = ErrorCode(
    "TRAX-FS-001",
    ErrorCategory.FILESYSTEM,
    ErrorSeverity.HIGH,
    "File not found",
    retryable=False,
    actionable_message="The specified file does not exist"
)

FILE_PERMISSION_DENIED = ErrorCode(
    "TRAX-FS-002",
    ErrorCategory.FILESYSTEM,
    ErrorSeverity.HIGH,
    "Permission denied",
    retryable=False,
    actionable_message="Insufficient permissions to access the file"
)

DISK_SPACE_INSUFFICIENT = ErrorCode(
    "TRAX-FS-003",
    ErrorCategory.FILESYSTEM,
    ErrorSeverity.CRITICAL,
    "Insufficient disk space",
    retryable=False,
    actionable_message="Not enough disk space available"
)

FILE_CORRUPTED = ErrorCode(
    "TRAX-FS-004",
    ErrorCategory.FILESYSTEM,
    ErrorSeverity.HIGH,
    "File is corrupted",
    retryable=False,
    actionable_message="The file appears to be corrupted or incomplete"
)

# Validation Errors (TRAX-VAL-001 to TRAX-VAL-099)
INVALID_INPUT = ErrorCode(
    "TRAX-VAL-001",
    ErrorCategory.VALIDATION,
    ErrorSeverity.MEDIUM,
    "Invalid input provided",
    retryable=False,
    actionable_message="Please check your input and try again"
)

MISSING_REQUIRED_FIELD = ErrorCode(
    "TRAX-VAL-002",
    ErrorCategory.VALIDATION,
    ErrorSeverity.MEDIUM,
    "Missing required field",
    retryable=False,
    actionable_message="A required field is missing"
)

INVALID_FORMAT = ErrorCode(
    "TRAX-VAL-003",
    ErrorCategory.VALIDATION,
    ErrorSeverity.MEDIUM,
    "Invalid format",
    retryable=False,
    actionable_message="The provided data is in an invalid format"
)

# Processing Errors (TRAX-PROC-001 to TRAX-PROC-099)
TRANSCRIPTION_FAILED = ErrorCode(
    "TRAX-PROC-001",
    ErrorCategory.PROCESSING,
    ErrorSeverity.HIGH,
    "Transcription processing failed",
    retryable=True,
    actionable_message="Failed to transcribe audio. Please try again"
)

ENHANCEMENT_FAILED = ErrorCode(
    "TRAX-PROC-002",
    ErrorCategory.PROCESSING,
    ErrorSeverity.MEDIUM,
    "Text enhancement failed",
    retryable=True,
    actionable_message="Failed to enhance text. Retrying with original..."
)

MEDIA_PROCESSING_FAILED = ErrorCode(
    "TRAX-PROC-003",
    ErrorCategory.PROCESSING,
    ErrorSeverity.HIGH,
    "Media processing failed",
    retryable=True,
    actionable_message="Failed to process media file. Please try again"
)

AUDIO_CONVERSION_FAILED = ErrorCode(
    "TRAX-PROC-004",
    ErrorCategory.PROCESSING,
    ErrorSeverity.HIGH,
    "Audio conversion failed",
    retryable=True,
    actionable_message="Failed to convert audio format. Please check the file"
)

# Configuration Errors (TRAX-CFG-001 to TRAX-CFG-099)
MISSING_CONFIGURATION = ErrorCode(
    "TRAX-CFG-001",
    ErrorCategory.CONFIGURATION,
    ErrorSeverity.CRITICAL,
    "Missing configuration",
    retryable=False,
    actionable_message="Required configuration is missing"
)

INVALID_CONFIGURATION = ErrorCode(
    "TRAX-CFG-002",
    ErrorCategory.CONFIGURATION,
    ErrorSeverity.HIGH,
    "Invalid configuration",
    retryable=False,
    actionable_message="Configuration contains invalid values"
)

ENVIRONMENT_ERROR = ErrorCode(
    "TRAX-CFG-003",
    ErrorCategory.CONFIGURATION,
    ErrorSeverity.HIGH,
    "Environment configuration error",
    retryable=False,
    actionable_message="Environment variables are not properly configured"
)

# Resource Errors (TRAX-RES-001 to TRAX-RES-099)
MEMORY_INSUFFICIENT = ErrorCode(
    "TRAX-RES-001",
    ErrorCategory.RESOURCE,
    ErrorSeverity.CRITICAL,
    "Insufficient memory",
    retryable=False,
    actionable_message="Not enough memory available for processing"
)

CPU_OVERLOADED = ErrorCode(
    "TRAX-RES-002",
    ErrorCategory.RESOURCE,
    ErrorSeverity.MEDIUM,
    "CPU overloaded",
    retryable=True,
    actionable_message="System is overloaded. Please try again later"
)

# Error code registry
ERROR_CODES: Dict[str, ErrorCode] = {
    # Network errors
    "TRAX-NET-001": NETWORK_CONNECTION_FAILED,
    "TRAX-NET-002": NETWORK_TIMEOUT,
    "TRAX-NET-003": DNS_RESOLUTION_FAILED,
    
    # API errors
    "TRAX-API-001": API_AUTHENTICATION_FAILED,
    "TRAX-API-002": API_RATE_LIMIT_EXCEEDED,
    "TRAX-API-003": API_QUOTA_EXCEEDED,
    "TRAX-API-004": API_SERVICE_UNAVAILABLE,
    "TRAX-API-005": API_INVALID_RESPONSE,
    
    # File system errors
    "TRAX-FS-001": FILE_NOT_FOUND,
    "TRAX-FS-002": FILE_PERMISSION_DENIED,
    "TRAX-FS-003": DISK_SPACE_INSUFFICIENT,
    "TRAX-FS-004": FILE_CORRUPTED,
    
    # Validation errors
    "TRAX-VAL-001": INVALID_INPUT,
    "TRAX-VAL-002": MISSING_REQUIRED_FIELD,
    "TRAX-VAL-003": INVALID_FORMAT,
    
    # Processing errors
    "TRAX-PROC-001": TRANSCRIPTION_FAILED,
    "TRAX-PROC-002": ENHANCEMENT_FAILED,
    "TRAX-PROC-003": MEDIA_PROCESSING_FAILED,
    "TRAX-PROC-004": AUDIO_CONVERSION_FAILED,
    
    # Configuration errors
    "TRAX-CFG-001": MISSING_CONFIGURATION,
    "TRAX-CFG-002": INVALID_CONFIGURATION,
    "TRAX-CFG-003": ENVIRONMENT_ERROR,
    
    # Resource errors
    "TRAX-RES-001": MEMORY_INSUFFICIENT,
    "TRAX-RES-002": CPU_OVERLOADED,
}


def get_error_code(code: str) -> Optional[ErrorCode]:
    """Get an error code by its string representation."""
    return ERROR_CODES.get(code)


def get_error_codes_by_category(category: ErrorCategory) -> list[ErrorCode]:
    """Get all error codes for a specific category."""
    return [code for code in ERROR_CODES.values() if code.category == category]


def get_error_codes_by_severity(severity: ErrorSeverity) -> list[ErrorCode]:
    """Get all error codes for a specific severity level."""
    return [code for code in ERROR_CODES.values() if code.severity == severity]


def get_retryable_error_codes() -> list[ErrorCode]:
    """Get all retryable error codes."""
    return [code for code in ERROR_CODES.values() if code.retryable]


def is_retryable_error_code(code: str) -> bool:
    """Check if an error code is retryable."""
    error_code = get_error_code(code)
    return error_code.retryable if error_code else False
