"""
Error handling and formatting utilities for consistent error messages across the application.
"""

import subprocess
from pathlib import Path
from typing import Any, Dict, Optional


class DownloadError(Exception):
    """Base exception for download-related errors."""

    def __init__(
        self,
        message: str,
        error_type: str = "download_error",
        details: Optional[str] = None,
    ):
        self.message = message
        self.error_type = error_type
        self.details = details
        super().__init__(self.message)


class YtDlpError(DownloadError):
    """Exception for yt-dlp specific errors."""

    def __init__(
        self,
        message: str,
        exit_code: Optional[int] = None,
        stderr: Optional[str] = None,
    ):
        self.exit_code = exit_code
        self.stderr = stderr
        super().__init__(
            message, "yt_dlp_error", f"Exit code: {exit_code}, Stderr: {stderr}"
        )


class FileValidationError(DownloadError):
    """Exception for file validation errors."""

    def __init__(self, message: str, file_path: Optional[Path] = None):
        self.file_path = file_path
        super().__init__(message, "file_validation_error", f"File: {file_path}")


def format_error_message(
    error_type: str,
    artist: str,
    title: str,
    video_id: Optional[str] = None,
    channel_name: Optional[str] = None,
    details: Optional[str] = None,
) -> str:
    """
    Format a consistent error message for tracking and logging.

    Args:
        error_type: Type of error (e.g., "yt-dlp failed", "file verification failed")
        artist: Artist name
        title: Song title
        video_id: YouTube video ID (optional)
        channel_name: Channel name (optional)
        details: Additional error details (optional)

    Returns:
        Formatted error message
    """
    base_msg = f"{error_type}: {artist} - {title}"

    if video_id:
        base_msg += f" (Video ID: {video_id})"

    if channel_name:
        base_msg += f" (Channel: {channel_name})"

    if details:
        base_msg += f" - {details}"

    return base_msg


def handle_yt_dlp_error(
    exception: subprocess.CalledProcessError,
    artist: str,
    title: str,
    video_id: Optional[str] = None,
    channel_name: Optional[str] = None,
) -> YtDlpError:
    """
    Handle yt-dlp subprocess errors and create a standardized exception.

    Args:
        exception: The CalledProcessError from subprocess.run
        artist: Artist name
        title: Song title
        video_id: YouTube video ID (optional)
        channel_name: Channel name (optional)

    Returns:
        YtDlpError with formatted message
    """
    error_msg = format_error_message(
        "yt-dlp failed",
        artist,
        title,
        video_id,
        channel_name,
        f"exit code {exception.returncode}: {exception.stderr}",
    )

    return YtDlpError(
        error_msg, exit_code=exception.returncode, stderr=exception.stderr
    )


def handle_file_validation_error(
    message: str,
    file_path: Path,
    artist: str,
    title: str,
    video_id: Optional[str] = None,
    channel_name: Optional[str] = None,
) -> FileValidationError:
    """
    Handle file validation errors and create a standardized exception.

    Args:
        message: Error message
        file_path: Path to the file that failed validation
        artist: Artist name
        title: Song title
        video_id: YouTube video ID (optional)
        channel_name: Channel name (optional)

    Returns:
        FileValidationError with formatted message
    """
    error_msg = format_error_message(
        "file validation failed",
        artist,
        title,
        video_id,
        channel_name,
        f"{message} - File: {file_path}",
    )

    return FileValidationError(error_msg, file_path)


def log_error(error: DownloadError, logger=None) -> None:
    """
    Log an error with consistent formatting.

    Args:
        error: DownloadError instance
        logger: Optional logger instance
    """
    if logger:
        logger.error(f"❌ {error.message}")
        if error.details:
            logger.error(f"   Details: {error.details}")
    else:
        print(f"❌ {error.message}")
        if error.details:
            print(f"   Details: {error.details}")


def create_error_context(
    artist: str,
    title: str,
    video_id: Optional[str] = None,
    channel_name: Optional[str] = None,
    file_path: Optional[Path] = None,
) -> Dict[str, Any]:
    """
    Create a context dictionary for error reporting.

    Args:
        artist: Artist name
        title: Song title
        video_id: YouTube video ID (optional)
        channel_name: Channel name (optional)
        file_path: File path (optional)

    Returns:
        Dictionary with error context
    """
    context = {
        "artist": artist,
        "title": title,
        "timestamp": None,  # Could be added if needed
    }

    if video_id:
        context["video_id"] = video_id

    if channel_name:
        context["channel_name"] = channel_name

    if file_path:
        context["file_path"] = str(file_path)

    return context
