//! Error types for the record daemon.

use thiserror::Error;

/// Main error type for the daemon.
#[derive(Debug, Error)]
pub enum DaemonError {
    #[error("Configuration error: {0}")]
    Config(#[from] ConfigError),

    #[error("LQP connection error: {0}")]
    Lqp(#[from] LqpError),

    #[error("Recording error: {0}")]
    Recording(#[from] RecordingError),

    #[error("IPC error: {0}")]
    Ipc(#[from] IpcError),

    #[error("Timeline error: {0}")]
    Timeline(#[from] TimelineError),

    #[error("IO error: {0}")]
    Io(#[from] std::io::Error),

    #[error("Serialization error: {0}")]
    Serialization(#[from] serde_json::Error),

    #[error("WebSocket error: {0}")]
    WebSocket(#[from] Box<tokio_tungstenite::tungstenite::Error>),

    #[error("HTTP request error: {0}")]
    Http(#[from] reqwest::Error),
}

/// Configuration-related errors.
#[derive(Debug, Error)]
pub enum ConfigError {
    #[error("Failed to read configuration file: {0}")]
    ReadError(#[source] std::io::Error),

    #[error("Failed to write configuration file: {0}")]
    WriteError(#[source] std::io::Error),

    #[error("Invalid configuration: {0}")]
    InvalidConfig(String),

    #[error("Failed to parse configuration: {0}")]
    ParseError(String),

    #[error("Configuration directory not found")]
    ConfigDirNotFound,

    #[error("Invalid encoder preset: {0}")]
    InvalidPreset(String),
}

impl From<toml::de::Error> for ConfigError {
    fn from(e: toml::de::Error) -> Self {
        ConfigError::ParseError(e.to_string())
    }
}

/// LQP (League Client API) related errors.
#[derive(Debug, Error)]
pub enum LqpError {
    #[error("League Client lockfile not found")]
    LockfileNotFound,

    #[error("Failed to parse lockfile: {0}")]
    LockfileParseError(String),

    #[error("Failed to connect to League Client: {0}")]
    ConnectionFailed(String),

    #[error("WebSocket connection error: {0}")]
    WebSocketError(String),

    #[error("Authentication failed: {0}")]
    AuthFailed(String),

    #[error("Event parsing error: {0}")]
    EventParseError(String),

    #[error("League Client not running")]
    ClientNotRunning,

    #[error("Request timeout")]
    Timeout,
}

/// Recording-related errors.
#[derive(Debug, Error)]
pub enum RecordingError {
    #[error("Failed to initialize OBS context: {0}")]
    ObsInitError(String),

    #[error("Failed to create capture source: {0}")]
    CaptureError(String),

    #[error("Failed to configure encoder: {0}")]
    EncoderError(String),

    #[error("Failed to start recording: {0}")]
    StartError(String),

    #[error("Failed to stop recording: {0}")]
    StopError(String),

    #[error("Recording already in progress")]
    AlreadyRecording,

    #[error("No recording in progress")]
    NotRecording,

    #[error("Output directory not accessible: {0}")]
    OutputDirError(String),

    #[error("Encoder not available: {0}")]
    EncoderNotAvailable(String),

    #[error("Game window not found")]
    GameWindowNotFound,
}

/// IPC-related errors.
#[derive(Debug, Error)]
pub enum IpcError {
    #[error("Failed to bind to socket: {0}")]
    BindError(#[source] std::io::Error),

    #[error("Failed to accept connection: {0}")]
    AcceptError(#[source] std::io::Error),

    #[error("Failed to read from socket: {0}")]
    ReadError(#[source] std::io::Error),

    #[error("Failed to write to socket: {0}")]
    WriteError(#[source] std::io::Error),

    #[error("Codec error: {0}")]
    CodecError(String),

    #[error("Invalid command: {0}")]
    InvalidCommand(String),

    #[error("Protocol error: {0}")]
    ProtocolError(String),

    #[error("Client disconnected")]
    ClientDisconnected,
}

/// Timeline-related errors.
#[derive(Debug, Error)]
pub enum TimelineError {
    #[error("Failed to store event: {0}")]
    StoreError(String),

    #[error("Failed to load timeline: {0}")]
    LoadError(String),

    #[error("Recording not found: {0}")]
    RecordingNotFound(uuid::Uuid),

    #[error("Invalid timestamp: {0}")]
    InvalidTimestamp(String),
}

/// Result type alias for daemon operations.
pub type Result<T> = std::result::Result<T, DaemonError>;
