//! Common error types for trading operations
//!
//! Error types that implement Send + Sync for use in async contexts.

use serde::{Deserialize, Serialize};

// =============================================================================
// TRADING TYPES (Migrated from foxhunt-common-types)
// =============================================================================

/// Common error types for trading operations
///
/// This error type implements Send + Sync for use in async contexts
#[derive(thiserror::Error, Debug)]
pub enum CommonTypeError {
    /// Invalid price value
    #[error("Invalid price: {value} - {reason}")]
    InvalidPrice {
        /// The invalid price value as string
        value: String,
        /// Reason why the price is invalid
        reason: String,
    },

    /// Invalid quantity value
    #[error("Invalid quantity: {value} - {reason}")]
    InvalidQuantity {
        /// The invalid quantity value as string
        value: String,
        /// Reason why the quantity is invalid
        reason: String,
    },

    /// Invalid identifier
    #[error("Invalid {field}: {reason}")]
    InvalidIdentifier {
        /// The field name that contains the invalid identifier
        field: String,
        /// Reason why the identifier is invalid
        reason: String,
    },

    /// Validation error
    #[error("Validation error for {field}: {reason}")]
    ValidationError {
        /// The field name that failed validation
        field: String,
        /// Reason why the validation failed
        reason: String,
    },

    /// Conversion error
    #[error("Conversion error: {message}")]
    ConversionError {
        /// Detailed error message describing the conversion failure
        message: String,
    },

    /// I/O error
    #[error("I/O error: {0}")]
    IoError(#[from] std::io::Error),

    /// JSON serialization/deserialization error
    #[error("JSON error: {0}")]
    JsonError(#[from] serde_json::Error),

    /// Float parsing error
    #[error("Float parsing error: {0}")]
    ParseFloatError(#[from] std::num::ParseFloatError),

    /// Integer parsing error
    #[error("Integer parsing error: {0}")]
    ParseIntError(#[from] std::num::ParseIntError),
}

// Manual trait implementations for CommonTypeError
// (Cannot derive Clone, PartialEq, Eq, Serialize due to std::io::Error and serde_json::Error)

impl Clone for CommonTypeError {
    /// Clone the error, converting IO and JSON errors to conversion errors
    fn clone(&self) -> Self {
        match self {
            Self::InvalidPrice { value, reason } => Self::InvalidPrice {
                value: value.clone(),
                reason: reason.clone(),
            },
            Self::InvalidQuantity { value, reason } => Self::InvalidQuantity {
                value: value.clone(),
                reason: reason.clone(),
            },
            Self::InvalidIdentifier { field, reason } => Self::InvalidIdentifier {
                field: field.clone(),
                reason: reason.clone(),
            },
            Self::ValidationError { field, reason } => Self::ValidationError {
                field: field.clone(),
                reason: reason.clone(),
            },
            Self::ConversionError { message } => Self::ConversionError {
                message: message.clone(),
            },
            // Cannot clone std::io::Error or serde_json::Error, so create new instances
            Self::IoError(e) => Self::ConversionError {
                message: format!("I/O error: {}", e),
            },
            Self::JsonError(e) => Self::ConversionError {
                message: format!("JSON error: {}", e),
            },
            Self::ParseFloatError(e) => Self::ParseFloatError(e.clone()),
            Self::ParseIntError(e) => Self::ParseIntError(e.clone()),
        }
    }
}
impl PartialEq for CommonTypeError {
    /// Compare two errors for equality
    fn eq(&self, other: &Self) -> bool {
        match (self, other) {
            (
                Self::InvalidPrice {
                    value: v1,
                    reason: r1,
                },
                Self::InvalidPrice {
                    value: v2,
                    reason: r2,
                },
            ) => v1 == v2 && r1 == r2,
            (
                Self::InvalidQuantity {
                    value: v1,
                    reason: r1,
                },
                Self::InvalidQuantity {
                    value: v2,
                    reason: r2,
                },
            ) => v1 == v2 && r1 == r2,
            (
                Self::InvalidIdentifier {
                    field: f1,
                    reason: r1,
                },
                Self::InvalidIdentifier {
                    field: f2,
                    reason: r2,
                },
            ) => f1 == f2 && r1 == r2,
            (
                Self::ValidationError {
                    field: f1,
                    reason: r1,
                },
                Self::ValidationError {
                    field: f2,
                    reason: r2,
                },
            ) => f1 == f2 && r1 == r2,
            (Self::ConversionError { message: m1 }, Self::ConversionError { message: m2 }) => {
                m1 == m2
            },
            (Self::ParseFloatError(e1), Self::ParseFloatError(e2)) => e1 == e2,
            (Self::ParseIntError(e1), Self::ParseIntError(e2)) => e1 == e2,
            // std::io::Error and serde_json::Error don't implement PartialEq, so they're never equal
            (Self::IoError(_), Self::IoError(_)) => false,
            (Self::JsonError(_), Self::JsonError(_)) => false,
            _ => false,
        }
    }
}

impl Eq for CommonTypeError {}

// Note: Display is automatically implemented by thiserror::Error derive
// based on the #[error("...")] attributes on each variant
impl Serialize for CommonTypeError {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        use serde::ser::SerializeStruct;
        match self {
            Self::InvalidPrice { value, reason } => {
                let mut state = serializer.serialize_struct("InvalidPrice", 2)?;
                state.serialize_field("value", value)?;
                state.serialize_field("reason", reason)?;
                state.end()
            },
            Self::InvalidQuantity { value, reason } => {
                let mut state = serializer.serialize_struct("InvalidQuantity", 2)?;
                state.serialize_field("value", value)?;
                state.serialize_field("reason", reason)?;
                state.end()
            },
            Self::InvalidIdentifier { field, reason } => {
                let mut state = serializer.serialize_struct("InvalidIdentifier", 2)?;
                state.serialize_field("field", field)?;
                state.serialize_field("reason", reason)?;
                state.end()
            },
            Self::ValidationError { field, reason } => {
                let mut state = serializer.serialize_struct("ValidationError", 2)?;
                state.serialize_field("field", field)?;
                state.serialize_field("reason", reason)?;
                state.end()
            },
            Self::ConversionError { message } => {
                let mut state = serializer.serialize_struct("ConversionError", 1)?;
                state.serialize_field("message", message)?;
                state.end()
            },
            Self::IoError(e) => {
                let mut state = serializer.serialize_struct("IoError", 1)?;
                state.serialize_field("message", &format!("I/O error: {}", e))?;
                state.end()
            },
            Self::JsonError(e) => {
                let mut state = serializer.serialize_struct("JsonError", 1)?;
                state.serialize_field("message", &format!("JSON error: {}", e))?;
                state.end()
            },
            Self::ParseFloatError(e) => {
                let mut state = serializer.serialize_struct("ParseFloatError", 1)?;
                state.serialize_field("message", &format!("Float parsing error: {}", e))?;
                state.end()
            },
            Self::ParseIntError(e) => {
                let mut state = serializer.serialize_struct("ParseIntError", 1)?;
                state.serialize_field("message", &format!("Integer parsing error: {}", e))?;
                state.end()
            },
        }
    }
}

impl<'de> Deserialize<'de> for CommonTypeError {
    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
    where
        D: serde::Deserializer<'de>,
    {
        // For deserialization, we'll convert everything to ConversionError since
        // we can't reconstruct std::io::Error or serde_json::Error from serialized form
        use serde::de::{MapAccess, Visitor};
        use std::fmt;

        struct CommonTypeErrorVisitor;

        impl<'de> Visitor<'de> for CommonTypeErrorVisitor {
            type Value = CommonTypeError;

            fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
                formatter.write_str("a CommonTypeError")
            }

            fn visit_map<V>(self, mut map: V) -> Result<CommonTypeError, V::Error>
            where
                V: MapAccess<'de>,
            {
                // For simplicity, deserialize everything as ConversionError
                let mut message = String::new();
                while let Some(key) = map.next_key::<String>()? {
                    let value: serde_json::Value = map.next_value()?;
                    if key == "message" {
                        if let Some(msg) = value.as_str() {
                            message = msg.to_owned();
                        }
                    } else {
                        message = format!("Deserialized error: {}: {}", key, value);
                    }
                }
                if message.is_empty() {
                    message = "Unknown deserialized error".to_owned();
                }
                Ok(CommonTypeError::ConversionError { message })
            }
        }

        deserializer.deserialize_struct(
            "CommonTypeError",
            &["value", "reason", "field", "message"],
            CommonTypeErrorVisitor,
        )
    }
}
