use axum::http::StatusCode;
use axum::response::{IntoResponse, Response};
use axum::Json;
use serde::{Deserialize, Serialize};
use serde_json::json;
/// Gestion centralisée des erreurs du stream server
///
/// Hiérarchie d'erreurs pour un debugging efficace et une gestion robuste
use std::fmt;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum AppError {
    // Configuration et initialisation
    ConfigError {
        message: String,
    },
    InitializationError {
        message: String,
    },

    // Erreurs réseau et connexion
    NetworkError {
        message: String,
    },
    ConnectionClosed,
    ConnectionTimeout,

    // Erreurs audio et streaming
    AudioError {
        message: String,
    },
    StreamingError {
        message: String,
    },
    EncodingError {
        message: String,
    },
    DecodingError {
        message: String,
    },

    // Erreurs de codec
    UnsupportedCodec {
        codec: String,
    },
    InvalidSampleRate {
        rate: u32,
        supported: Vec<u32>,
    },
    InvalidChannelCount {
        channels: u8,
    },
    InvalidBitrate {
        codec: String,
        bitrate: u32,
        min: u32,
        max: u32,
    },
    ParameterMismatch {
        expected: String,
        received: String,
    },

    // Erreurs de fichier et stockage
    FileError {
        message: String,
    },
    NotFound {
        resource: String,
    },
    NotFoundWithStreamId {
        resource: String,
        stream_id: String,
    },
    StorageError {
        message: String,
    },

    // Erreurs de sérialisation
    SerializationError,
    InvalidData {
        message: String,
    },

    // Erreurs de ressources
    ResourceExhausted {
        resource: String,
    },
    LimitExceeded {
        limit: String,
        current: u32,
    },
    ListenerLimitExceeded {
        limit: u32,
        stream_id: String,
    },
    NotEnoughData,
    InsufficientData {
        message: String,
    },
    BufferOverflow,
    BufferNotFound {
        buffer_id: String,
        stream_id: Option<String>,
    },
    BufferFull {
        buffer_id: String,
        stream_id: Option<String>,
    },

    // Erreurs d'autorisation
    Unauthorized,
    Forbidden,
    SignatureError {
        message: String,
    },

    // Erreurs de thread et concurrence
    AlreadyRunning,
    AlreadyProcessing {
        resource: String,
    },
    ThreadError {
        message: String,
    },

    // Erreurs de synchronisation
    NoSyncPoint {
        message: String,
    },
    TimeSync {
        message: String,
    },

    // Erreurs génériques
    InternalError {
        message: String,
    },
    Internal {
        message: String,
    }, // Alias pour compatibilité
    ExternalServiceError {
        service: String,
        message: String,
    },
}

impl fmt::Display for AppError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            AppError::ConfigError { message } => write!(f, "Configuration error: {}", message),
            AppError::InitializationError { message } => {
                write!(f, "Initialization error: {}", message)
            }
            AppError::NetworkError { message } => write!(f, "Network error: {}", message),
            AppError::ConnectionClosed => write!(f, "Connection closed"),
            AppError::ConnectionTimeout => write!(f, "Connection timeout"),
            AppError::AudioError { message } => write!(f, "Audio error: {}", message),
            AppError::StreamingError { message } => write!(f, "Streaming error: {}", message),
            AppError::EncodingError { message } => write!(f, "Encoding error: {}", message),
            AppError::DecodingError { message } => write!(f, "Decoding error: {}", message),
            AppError::UnsupportedCodec { codec } => write!(f, "Unsupported codec: {}", codec),
            AppError::InvalidSampleRate { rate, supported } => write!(
                f,
                "Invalid sample rate: {} (supported: {:?})",
                rate, supported
            ),
            AppError::InvalidChannelCount { channels } => {
                write!(f, "Invalid channel count: {}", channels)
            }
            AppError::InvalidBitrate {
                codec,
                bitrate,
                min,
                max,
            } => write!(
                f,
                "Invalid bitrate for {}: {} (supported: {}-{})",
                codec, bitrate, min, max
            ),
            AppError::ParameterMismatch { expected, received } => write!(
                f,
                "Parameter mismatch: expected {}, received {}",
                expected, received
            ),
            AppError::FileError { message } => write!(f, "File error: {}", message),
            AppError::NotFound { resource } => write!(f, "Not found: {}", resource),
            AppError::NotFoundWithStreamId {
                resource,
                stream_id,
            } => write!(f, "Not found: {} (stream_id: {})", resource, stream_id),
            AppError::StorageError { message } => write!(f, "Storage error: {}", message),
            AppError::SerializationError => write!(f, "Serialization error"),
            AppError::InvalidData { message } => write!(f, "Invalid data: {}", message),
            AppError::ResourceExhausted { resource } => {
                write!(f, "Resource exhausted: {}", resource)
            }
            AppError::LimitExceeded { limit, current } => {
                write!(f, "Limit exceeded: {} (current: {})", limit, current)
            }
            AppError::ListenerLimitExceeded { limit, stream_id } => write!(
                f,
                "Listener limit exceeded: {} (stream_id: {})",
                limit, stream_id
            ),
            AppError::NotEnoughData => write!(f, "Not enough data"),
            AppError::InsufficientData { message } => write!(f, "Insufficient data: {}", message),
            AppError::BufferOverflow => write!(f, "Buffer overflow"),
            AppError::BufferNotFound {
                buffer_id,
                stream_id,
            } => {
                if let Some(sid) = stream_id {
                    write!(f, "Buffer not found: {} (stream_id: {})", buffer_id, sid)
                } else {
                    write!(f, "Buffer not found: {}", buffer_id)
                }
            }
            AppError::BufferFull {
                buffer_id,
                stream_id,
            } => {
                if let Some(sid) = stream_id {
                    write!(f, "Buffer full: {} (stream_id: {})", buffer_id, sid)
                } else {
                    write!(f, "Buffer full: {}", buffer_id)
                }
            }
            AppError::Unauthorized => write!(f, "Unauthorized access"),
            AppError::Forbidden => write!(f, "Forbidden access"),
            AppError::SignatureError { message } => write!(f, "Signature error: {}", message),
            AppError::AlreadyRunning => write!(f, "Process already running"),
            AppError::AlreadyProcessing { resource } => {
                write!(f, "Already processing: {}", resource)
            }
            AppError::ThreadError { message } => write!(f, "Thread error: {}", message),
            AppError::NoSyncPoint { message } => write!(f, "No sync point: {}", message),
            AppError::TimeSync { message } => write!(f, "Time sync error: {}", message),
            AppError::InternalError { message } => write!(f, "Internal error: {}", message),
            AppError::Internal { message } => write!(f, "Internal error: {}", message),
            AppError::ExternalServiceError { service, message } => {
                write!(f, "External service error: {} - {}", service, message)
            }
        }
    }
}

impl std::error::Error for AppError {}

impl IntoResponse for AppError {
    fn into_response(self) -> Response {
        let (status, error_message) = match &self {
            AppError::ConfigError { message } => {
                (StatusCode::INTERNAL_SERVER_ERROR, message.clone())
            }
            AppError::InitializationError { message } => {
                (StatusCode::INTERNAL_SERVER_ERROR, message.clone())
            }
            AppError::NetworkError { message } => {
                (StatusCode::INTERNAL_SERVER_ERROR, message.clone())
            }
            AppError::ConnectionClosed => (
                StatusCode::INTERNAL_SERVER_ERROR,
                "Connection closed".to_string(),
            ),
            AppError::ConnectionTimeout => (
                StatusCode::INTERNAL_SERVER_ERROR,
                "Connection timeout".to_string(),
            ),
            AppError::AudioError { message } => {
                (StatusCode::INTERNAL_SERVER_ERROR, message.clone())
            }
            AppError::StreamingError { message } => {
                (StatusCode::INTERNAL_SERVER_ERROR, message.clone())
            }
            AppError::EncodingError { message } => {
                (StatusCode::INTERNAL_SERVER_ERROR, message.clone())
            }
            AppError::DecodingError { message } => {
                (StatusCode::INTERNAL_SERVER_ERROR, message.clone())
            }
            AppError::UnsupportedCodec { codec } => (
                StatusCode::BAD_REQUEST,
                format!("Unsupported codec: {}", codec),
            ),
            AppError::InvalidSampleRate { rate, supported } => (
                StatusCode::BAD_REQUEST,
                format!("Invalid sample rate: {} (supported: {:?})", rate, supported),
            ),
            AppError::InvalidChannelCount { channels } => (
                StatusCode::BAD_REQUEST,
                format!("Invalid channel count: {}", channels),
            ),
            AppError::InvalidBitrate {
                codec,
                bitrate,
                min,
                max,
            } => (
                StatusCode::BAD_REQUEST,
                format!(
                    "Invalid bitrate for {}: {} (supported: {}-{})",
                    codec, bitrate, min, max
                ),
            ),
            AppError::ParameterMismatch { expected, received } => (
                StatusCode::BAD_REQUEST,
                format!(
                    "Parameter mismatch: expected {}, received {}",
                    expected, received
                ),
            ),
            AppError::FileError { message } => (StatusCode::INTERNAL_SERVER_ERROR, message.clone()),
            AppError::NotFound { resource } => {
                (StatusCode::NOT_FOUND, format!("Not found: {}", resource))
            }
            AppError::StorageError { message } => {
                (StatusCode::INTERNAL_SERVER_ERROR, message.clone())
            }
            AppError::SerializationError => (
                StatusCode::INTERNAL_SERVER_ERROR,
                "Serialization error".to_string(),
            ),
            AppError::InvalidData { message } => (StatusCode::BAD_REQUEST, message.clone()),
            AppError::ResourceExhausted { resource } => (
                StatusCode::INTERNAL_SERVER_ERROR,
                format!("Resource exhausted: {}", resource),
            ),
            AppError::LimitExceeded { limit, current } => (
                StatusCode::TOO_MANY_REQUESTS,
                format!("Limit exceeded: {} (current: {})", limit, current),
            ),
            AppError::ListenerLimitExceeded { limit, stream_id } => (
                StatusCode::TOO_MANY_REQUESTS,
                format!(
                    "Listener limit exceeded: {} (stream_id: {})",
                    limit, stream_id
                ),
            ),
            AppError::NotEnoughData => (StatusCode::BAD_REQUEST, "Not enough data".to_string()),
            AppError::InsufficientData { message } => (StatusCode::BAD_REQUEST, message.clone()),
            AppError::BufferOverflow => (StatusCode::BAD_REQUEST, "Buffer overflow".to_string()),
            AppError::BufferNotFound {
                buffer_id,
                stream_id,
            } => {
                let msg = if let Some(sid) = stream_id {
                    format!("Buffer not found: {} (stream_id: {})", buffer_id, sid)
                } else {
                    format!("Buffer not found: {}", buffer_id)
                };
                (StatusCode::NOT_FOUND, msg)
            }
            AppError::BufferFull {
                buffer_id,
                stream_id,
            } => {
                let msg = if let Some(sid) = stream_id {
                    format!("Buffer full: {} (stream_id: {})", buffer_id, sid)
                } else {
                    format!("Buffer full: {}", buffer_id)
                };
                (StatusCode::BAD_REQUEST, msg)
            }
            AppError::Unauthorized => (StatusCode::UNAUTHORIZED, "Unauthorized access".to_string()),
            AppError::Forbidden => (StatusCode::FORBIDDEN, "Forbidden access".to_string()),
            AppError::SignatureError { message } => (StatusCode::UNAUTHORIZED, message.clone()),
            AppError::AlreadyRunning => {
                (StatusCode::CONFLICT, "Process already running".to_string())
            }
            AppError::AlreadyProcessing { resource } => (
                StatusCode::CONFLICT,
                format!("Already processing: {}", resource),
            ),
            AppError::ThreadError { message } => {
                (StatusCode::INTERNAL_SERVER_ERROR, message.clone())
            }
            AppError::NoSyncPoint { message } => {
                (StatusCode::INTERNAL_SERVER_ERROR, message.clone())
            }
            AppError::TimeSync { message } => (StatusCode::INTERNAL_SERVER_ERROR, message.clone()),
            AppError::InternalError { message } => {
                (StatusCode::INTERNAL_SERVER_ERROR, message.clone())
            }
            AppError::Internal { message } => (StatusCode::INTERNAL_SERVER_ERROR, message.clone()),
            AppError::ExternalServiceError { service, message } => (
                StatusCode::INTERNAL_SERVER_ERROR,
                format!("External service error: {} - {}", service, message),
            ),
            AppError::NotFoundWithStreamId {
                resource,
                stream_id,
            } => (
                StatusCode::NOT_FOUND,
                format!("Not found: {} (stream_id: {})", resource, stream_id),
            ),
        };

        let body = Json(json!({
            "error": error_message.clone(),
            "status": status.as_u16(),
        }));

        (status, body).into_response()
    }
}

pub type Result<T> = std::result::Result<T, AppError>;

/// Types d'erreurs spécifiques au streaming
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum StreamError {
    FileNotFound,
    InvalidRange,
    StreamError(String),
}

impl fmt::Display for StreamError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            StreamError::FileNotFound => write!(f, "File not found"),
            StreamError::InvalidRange => write!(f, "Invalid range"),
            StreamError::StreamError(msg) => write!(f, "Stream error: {}", msg),
        }
    }
}

impl std::error::Error for StreamError {}

/// Conversion de StreamError vers AppError
impl From<StreamError> for AppError {
    fn from(err: StreamError) -> Self {
        match err {
            StreamError::FileNotFound => AppError::NotFound {
                resource: "stream_file".to_string(),
            },
            StreamError::InvalidRange => AppError::InvalidData {
                message: "Invalid range request".to_string(),
            },
            StreamError::StreamError(msg) => AppError::StreamingError { message: msg },
        }
    }
}

/// Conversion de AppError vers StreamError (quand applicable)
impl From<AppError> for StreamError {
    fn from(err: AppError) -> Self {
        match err {
            AppError::NotFound { resource } => StreamError::FileNotFound,
            AppError::InvalidData { message }
                if message.contains("range") || message.contains("Range") =>
            {
                StreamError::InvalidRange
            }
            AppError::StreamingError { message } => StreamError::StreamError(message),
            _ => StreamError::StreamError(format!("{}", err)),
        }
    }
}

/// Conversion depuis std::io::Error
impl From<std::io::Error> for StreamError {
    fn from(err: std::io::Error) -> Self {
        match err.kind() {
            std::io::ErrorKind::NotFound => StreamError::FileNotFound,
            std::io::ErrorKind::InvalidInput => StreamError::InvalidRange,
            _ => StreamError::StreamError(format!("IO error: {}", err)),
        }
    }
}

/// Conversion depuis std::io::Error vers AppError
impl From<std::io::Error> for AppError {
    fn from(err: std::io::Error) -> Self {
        match err.kind() {
            std::io::ErrorKind::NotFound => AppError::NotFound {
                resource: "file".to_string(),
            },
            std::io::ErrorKind::InvalidInput => AppError::InvalidData {
                message: format!("Invalid input: {}", err),
            },
            std::io::ErrorKind::PermissionDenied => AppError::Forbidden,
            _ => AppError::FileError {
                message: format!("IO error: {}", err),
            },
        }
    }
}

/// Conversion depuis sqlx::Error
impl From<sqlx::Error> for AppError {
    fn from(err: sqlx::Error) -> Self {
        match err {
            sqlx::Error::Database(db_err) => AppError::ExternalServiceError {
                service: "database".to_string(),
                message: db_err.message().to_string(),
            },
            sqlx::Error::RowNotFound => AppError::NotFound {
                resource: "database_row".to_string(),
            },
            sqlx::Error::PoolClosed => AppError::ConnectionClosed,
            sqlx::Error::PoolTimedOut => AppError::ConnectionTimeout,
            _ => AppError::ExternalServiceError {
                service: "database".to_string(),
                message: format!("Database error: {}", err),
            },
        }
    }
}

/// Conversion depuis serde_json::Error
impl From<serde_json::Error> for AppError {
    fn from(err: serde_json::Error) -> Self {
        AppError::SerializationError
    }
}

/// Conversion depuis tokio::time::error::Elapsed
impl From<tokio::time::error::Elapsed> for AppError {
    fn from(_: tokio::time::error::Elapsed) -> Self {
        AppError::ConnectionTimeout
    }
}

/// Implémentation de IntoResponse pour StreamError
impl IntoResponse for StreamError {
    fn into_response(self) -> Response {
        let app_error: AppError = self.into();
        app_error.into_response()
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_stream_error_display() {
        let err1 = StreamError::FileNotFound;
        assert_eq!(format!("{}", err1), "File not found");

        let err2 = StreamError::InvalidRange;
        assert_eq!(format!("{}", err2), "Invalid range");

        let err3 = StreamError::StreamError("Test error".to_string());
        assert_eq!(format!("{}", err3), "Stream error: Test error");
    }

    #[test]
    fn test_stream_error_to_app_error() {
        let stream_err = StreamError::FileNotFound;
        let app_err: AppError = stream_err.into();

        match app_err {
            AppError::NotFound { resource } => {
                assert_eq!(resource, "stream_file");
            }
            _ => panic!("Expected NotFound variant"),
        }

        let stream_err2 = StreamError::InvalidRange;
        let app_err2: AppError = stream_err2.into();

        match app_err2 {
            AppError::InvalidData { message } => {
                assert!(message.contains("range"));
            }
            _ => panic!("Expected InvalidData variant"),
        }

        let stream_err3 = StreamError::StreamError("Test message".to_string());
        let app_err3: AppError = stream_err3.into();

        match app_err3 {
            AppError::StreamingError { message } => {
                assert_eq!(message, "Test message");
            }
            _ => panic!("Expected StreamingError variant"),
        }
    }

    #[test]
    fn test_app_error_to_stream_error() {
        let app_err = AppError::NotFound {
            resource: "test".to_string(),
        };
        let stream_err: StreamError = app_err.into();

        match stream_err {
            StreamError::FileNotFound => {}
            _ => panic!("Expected FileNotFound variant"),
        }

        let app_err2 = AppError::InvalidData {
            message: "Invalid range request".to_string(),
        };
        let stream_err2: StreamError = app_err2.into();

        match stream_err2 {
            StreamError::InvalidRange => {}
            _ => panic!("Expected InvalidRange variant"),
        }

        let app_err3 = AppError::StreamingError {
            message: "Stream failed".to_string(),
        };
        let stream_err3: StreamError = app_err3.into();

        match stream_err3 {
            StreamError::StreamError(msg) => {
                assert_eq!(msg, "Stream failed");
            }
            _ => panic!("Expected StreamError variant"),
        }
    }

    #[test]
    fn test_io_error_conversions() {
        let io_err = std::io::Error::from(std::io::ErrorKind::NotFound);
        let stream_err: StreamError = io_err.into();

        match stream_err {
            StreamError::FileNotFound => {}
            _ => panic!("Expected FileNotFound variant"),
        }

        let io_err2 = std::io::Error::from(std::io::ErrorKind::InvalidInput);
        let stream_err2: StreamError = io_err2.into();

        match stream_err2 {
            StreamError::InvalidRange => {}
            _ => panic!("Expected InvalidRange variant"),
        }

        let io_err3 = std::io::Error::from(std::io::ErrorKind::NotFound);
        let app_err: AppError = io_err3.into();

        match app_err {
            AppError::NotFound { resource } => {
                assert_eq!(resource, "file");
            }
            _ => panic!("Expected NotFound variant"),
        }
    }

    #[tokio::test]
    async fn test_stream_error_into_response() {
        let stream_err = StreamError::FileNotFound;
        let response = stream_err.into_response();

        assert_eq!(response.status(), StatusCode::NOT_FOUND);
    }

    #[test]
    fn test_serde_json_error_conversion() {
        let json_err = serde_json::from_str::<serde_json::Value>("invalid json").unwrap_err();
        let app_err: AppError = json_err.into();

        match app_err {
            AppError::SerializationError => {}
            _ => panic!("Expected SerializationError variant"),
        }
    }
}
