use crate::pagination::ResultPagination;
use serde::{Deserialize, Serialize};
use serde_json::Value;

// ============================================================
// Error Codes
// ============================================================

/// Standard error codes for API responses
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(i32)]
#[non_exhaustive]
pub enum ErrorCode {
    Success = 0,
    BadRequest = 400,
    Unauthorized = 401,
    Forbidden = 403,
    NotFound = 404,
    Conflict = 409,
    ValidationError = 422,
    InternalError = 500,
}

impl ErrorCode {
    /// Get the integer representation of the error code
    pub fn as_i32(self) -> i32 {
        self as i32
    }

    /// Convert error code to HTTP status message
    pub fn as_str(self) -> &'static str {
        match self {
            ErrorCode::Success => "Success",
            ErrorCode::BadRequest => "Bad Request",
            ErrorCode::Unauthorized => "Unauthorized",
            ErrorCode::Forbidden => "Forbidden",
            ErrorCode::NotFound => "Not Found",
            ErrorCode::Conflict => "Conflict",
            ErrorCode::ValidationError => "Unprocessable Entity",
            ErrorCode::InternalError => "Internal Server Error",
        }
    }

    /// Try to convert an integer to an ErrorCode
    pub fn from_i32(value: i32) -> Option<Self> {
        match value {
            0 => Some(ErrorCode::Success),
            400 => Some(ErrorCode::BadRequest),
            401 => Some(ErrorCode::Unauthorized),
            403 => Some(ErrorCode::Forbidden),
            404 => Some(ErrorCode::NotFound),
            409 => Some(ErrorCode::Conflict),
            422 => Some(ErrorCode::ValidationError),
            500 => Some(ErrorCode::InternalError),
            _ => None,
        }
    }
}

// ============================================================
// Field-level Validation Errors
// ============================================================

/// A single field-level validation error
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(not(feature = "snake-case"), serde(rename_all = "camelCase"))]
#[cfg_attr(feature = "snake-case", serde(rename_all = "snake_case"))]
pub struct FieldError {
    pub field: String,
    pub message: String,
}

impl FieldError {
    pub fn new(field: impl Into<String>, message: impl Into<String>) -> Self {
        Self {
            field: field.into(),
            message: message.into(),
        }
    }
}

// ============================================================
// Response Data Types
// ============================================================

/// Response data wrapper that can hold either a single value or a list
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
#[serde(untagged)]
#[non_exhaustive]
pub enum ResponseData<T> {
    /// A single value
    Single(T),
    /// A list of values
    Multiple(Vec<T>),
    /// No data
    #[default]
    Empty,
}

impl<T> ResponseData<T> {
    /// Create a single value response data
    pub fn single(v: T) -> Self {
        ResponseData::Single(v)
    }

    /// Create a multiple values response data
    pub fn multiple(v: Vec<T>) -> Self {
        ResponseData::Multiple(v)
    }

    /// Check if this is a single value
    pub fn is_single(&self) -> bool {
        matches!(self, ResponseData::Single(_))
    }

    /// Check if this is multiple values
    pub fn is_multiple(&self) -> bool {
        matches!(self, ResponseData::Multiple(_))
    }

    /// Check if this is empty
    pub fn is_empty(&self) -> bool {
        matches!(self, ResponseData::Empty)
    }

    /// Get reference to the single value, if present
    pub fn as_single(&self) -> Option<&T> {
        match self {
            ResponseData::Single(v) => Some(v),
            _ => None,
        }
    }

    /// Get reference to the multiple values, if present
    pub fn as_multiple(&self) -> Option<&Vec<T>> {
        match self {
            ResponseData::Multiple(v) => Some(v),
            _ => None,
        }
    }

    /// Number of items in the data: 1 for `Single`, vec len for `Multiple`, 0 for `Empty`
    #[inline]
    pub fn len(&self) -> usize {
        match self {
            ResponseData::Single(_) => 1,
            ResponseData::Multiple(v) => v.len(),
            ResponseData::Empty => 0,
        }
    }

    /// Whether the data carries no items.
    ///
    /// Different from `is_empty()` which checks the `Empty` variant.
    /// `Multiple(vec![])` has `is_empty_data() == true` but `is_empty() == false`.
    #[inline]
    #[allow(clippy::len_zero)]
    pub fn is_empty_data(&self) -> bool {
        self.len() == 0
    }
}

impl<T> From<T> for ResponseData<T> {
    fn from(v: T) -> Self {
        ResponseData::Single(v)
    }
}

impl<T> From<Vec<T>> for ResponseData<T> {
    fn from(v: Vec<T>) -> Self {
        ResponseData::Multiple(v)
    }
}

// ============================================================
// API Response Types
// ============================================================

/// API response wrapper with unified structure
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(not(feature = "snake-case"), serde(rename_all = "camelCase"))]
#[cfg_attr(feature = "snake-case", serde(rename_all = "snake_case"))]
pub struct ApiResult<T> {
    pub success: bool,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub data: Option<ResponseData<T>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub message: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub code: Option<i32>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub pagination: Option<ResultPagination>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub errors: Option<Vec<FieldError>>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub trace_id: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub biz_code: Option<i32>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub timestamp: Option<i64>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub extra: Option<Value>,
}

impl<T> ApiResult<T> {
    // ── Internal constructor ──

    /// Internal constructor that creates the base struct with all optional fields as None.
    #[inline]
    fn new(
        success: bool,
        data: Option<ResponseData<T>>,
        message: Option<String>,
        code: Option<i32>,
    ) -> Self {
        ApiResult {
            success,
            data,
            message,
            code,
            pagination: None,
            errors: None,
            trace_id: None,
            biz_code: None,
            timestamp: None,
            extra: None,
        }
    }

    // ── Factory methods ──

    /// Create a successful response with a single value
    #[inline]
    pub fn value(v: T) -> Self {
        Self::new(true, Some(ResponseData::single(v)), None, None)
    }

    /// Create a successful response with a list of values
    #[inline]
    pub fn list(v: Vec<T>) -> Self {
        Self::new(true, Some(ResponseData::multiple(v)), None, None)
    }

    /// Create a failed response with a message (alias for `failure`)
    #[inline]
    pub fn fail(message: &str) -> Self {
        Self::failure(message)
    }

    /// Create a failed response with a message
    #[inline]
    pub fn failure(message: &str) -> Self {
        Self::new(false, None, Some(message.to_string()), None)
    }

    /// Create a successful response without data
    ///
    /// Alias for `ok()` - use `ok()` for clarity
    #[inline]
    pub fn success() -> Self {
        Self::ok()
    }

    /// Create a successful response without data (recommended method name)
    #[inline]
    pub fn ok() -> Self {
        Self::new(true, None, None, None)
    }

    /// Create a validation error response with field-level details
    pub fn validation_errors(errors: Vec<FieldError>) -> Self {
        let mut r = Self::new(
            false,
            None,
            Some("Validation failed".to_string()),
            Some(ErrorCode::ValidationError as i32),
        );
        r.errors = Some(errors);
        r
    }

    /// Convert a `Result<T, E>` into `ApiResult<T>`, mapping all errors to `InternalError`
    pub fn from_result<E: std::fmt::Display>(result: Result<T, E>) -> Self {
        match result {
            Ok(data) => Self::value(data),
            Err(err) => Self::new(
                false,
                None,
                Some(err.to_string()),
                Some(ErrorCode::InternalError as i32),
            ),
        }
    }

    // ── Query methods ──

    /// Whether this is a successful response
    #[inline]
    pub fn is_success(&self) -> bool {
        self.success
    }

    /// Whether this is an error response
    #[inline]
    pub fn is_error(&self) -> bool {
        !self.success
    }

    /// Get the error code if this is an error response
    pub fn error_code(&self) -> Option<ErrorCode> {
        if !self.success {
            self.code.and_then(ErrorCode::from_i32)
        } else {
            None
        }
    }

    // ── Builder methods ──

    /// Add extra metadata to the response
    #[inline]
    pub fn with_extra(mut self, key: &str, value: Value) -> Self {
        match self.extra {
            Some(ref mut v) => {
                v[key] = value;
            }
            None => {
                let mut v = serde_json::Map::new();
                v.insert(key.to_string(), value);
                self.extra = Some(v.into());
            }
        }
        self
    }

    /// Set error code for the response
    #[inline]
    pub fn with_code(mut self, code: i32) -> Self {
        self.code = Some(code);
        self
    }

    /// Set pagination metadata for list responses
    #[inline]
    pub fn with_pagination(mut self, pagination: ResultPagination) -> Self {
        self.pagination = Some(pagination);
        self
    }

    /// Set message for the response
    #[inline]
    pub fn with_message(mut self, message: &str) -> Self {
        self.message = Some(message.to_string());
        self
    }

    /// Set field-level validation errors
    #[inline]
    pub fn with_errors(mut self, errors: Vec<FieldError>) -> Self {
        self.errors = Some(errors);
        self
    }

    /// Add a single field-level validation error
    #[inline]
    pub fn with_error(mut self, field: impl Into<String>, message: impl Into<String>) -> Self {
        match self.errors {
            Some(ref mut v) => v.push(FieldError::new(field, message)),
            None => self.errors = Some(vec![FieldError::new(field, message)]),
        }
        self
    }

    /// Set request trace ID
    #[inline]
    pub fn with_trace_id(mut self, id: impl Into<String>) -> Self {
        self.trace_id = Some(id.into());
        self
    }

    /// Set business error code (independent of HTTP status code)
    #[inline]
    pub fn with_biz_code(mut self, code: i32) -> Self {
        self.biz_code = Some(code);
        self
    }

    /// Set timestamp (Unix milliseconds)
    #[inline]
    pub fn with_timestamp(mut self, ts: i64) -> Self {
        self.timestamp = Some(ts);
        self
    }

    /// Set timestamp to current time automatically
    pub fn with_current_timestamp(self) -> Self {
        use std::time::{SystemTime, UNIX_EPOCH};
        let ts = SystemTime::now()
            .duration_since(UNIX_EPOCH)
            .map(|d| d.as_millis() as i64)
            .unwrap_or(0);
        self.with_timestamp(ts)
    }
}

// ============================================================
// From Implementations for Error Conversion
// ============================================================

impl<T> From<anyhow::Error> for ApiResult<T> {
    fn from(err: anyhow::Error) -> Self {
        Self::new(
            false,
            None,
            Some(err.to_string()),
            Some(ErrorCode::InternalError as i32),
        )
    }
}

impl<T> From<std::io::Error> for ApiResult<T> {
    fn from(err: std::io::Error) -> Self {
        Self::new(
            false,
            None,
            Some(err.to_string()),
            Some(ErrorCode::InternalError as i32),
        )
    }
}

impl<T> From<std::string::FromUtf8Error> for ApiResult<T> {
    fn from(err: std::string::FromUtf8Error) -> Self {
        Self::new(
            false,
            None,
            Some(err.to_string()),
            Some(ErrorCode::InternalError as i32),
        )
    }
}

/// Convert any `Result<T, E>` where E implements Display to `ApiResult<T>`
impl<T, E: std::fmt::Display + std::fmt::Debug> From<Result<T, E>> for ApiResult<T> {
    fn from(result: Result<T, E>) -> Self {
        match result {
            Ok(data) => Self::value(data),
            Err(err) => Self::new(
                false,
                None,
                Some(format!("{}", err)),
                Some(ErrorCode::InternalError as i32),
            ),
        }
    }
}

/// Type alias for standard Result with `Box<dyn Error>`.
///
/// Commonly used as the return type for API handlers:
/// `-> DefaultResult<impl Responder>` where `Ok(ApiResult::value(data))` is returned.
pub type DefaultResult<T> = Result<T, Box<dyn std::error::Error>>;
