// Copyright (C) 2024 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Error handling for HTTP client operations.
//!
//! This module defines error types and codes used throughout the HTTP client
//! implementation, providing a consistent error handling mechanism across the
//! library.

use crate::wrapper::ffi;

/// Represents an error that occurred during an HTTP request.
///
/// Contains both an error code for programmatic handling and
/// a human-readable error message.
#[derive(Clone)]
pub struct HttpClientError {
    /// The specific error code categorizing this error
    code: HttpErrorCode,
    /// Human-readable description of the error
    msg: String,
}

impl HttpClientError {
    /// Creates an `HttpClientError` from a raw FFI error object.
    ///
    /// # Arguments
    /// * `inner` - The FFI error object to convert
    pub(crate) fn from_ffi(inner: &ffi::HttpClientError) -> Self {
        let code = HttpErrorCode::try_from(inner.GetErrorCode()).unwrap_or_default();
        let msg = inner.GetErrorMessage().to_string();
        Self { code, msg }
    }

    /// Creates a new `HttpClientError` with the given code and message.
    ///
    /// # Arguments
    /// * `code` - The error code
    /// * `msg` - Human-readable error message
    pub fn new(code: HttpErrorCode, msg: String) -> Self {
        Self { code, msg }
    }

    /// Gets the error code for this error.
    pub fn code(&self) -> &HttpErrorCode {
        &self.code
    }

    /// Gets the human-readable error message.
    pub fn msg(&self) -> &str {
        &self.msg
    }
}

/// Enumeration of possible HTTP client error codes.
///
/// These codes correspond to common HTTP client errors and are compatible
/// with the underlying C++ implementation through `#[repr(i32)]`.
#[derive(Default, Clone, PartialEq, Eq)]
#[repr(i32)]
pub enum HttpErrorCode {
    /// No specific error occurred.
    HttpNoneErr,

    /// Permission denied when attempting to perform an operation (201).
    ///
    /// Typically indicates lack of necessary permissions for network access.
    HttpPermissionDeniedCode = 201,

    /// Error parsing data (401).
    ///
    /// Indicates failure to parse HTTP headers, JSON, or other structured data.
    HttpParseErrorCode = 401,

    /// Base value for all HTTP error codes (2300000).
    ///
    /// Used as an offset for generating specific error codes within the system.
    HttpErrorCodeBase = 2300000,

    /// The requested protocol is not supported.
    ///
    /// Occurs when attempting to use a protocol that the client doesn't
    /// support.
    HttpUnsupportedProtocol,

    /// Failed to initialize the HTTP client.
    ///
    /// Indicates a problem during client creation or initialization.
    HttpFailedInit,

    /// URL format is invalid or malformed.
    ///
    /// The provided URL string doesn't conform to URL syntax rules.
    HttpUrlMalformat,

    /// Failed to resolve the proxy server hostname (2300005).
    HttpCouldntResolveProxy = 2300005,

    /// Failed to resolve the target host hostname.
    ///
    /// May indicate DNS resolution failure or network connectivity issues.
    HttpCouldntResolveHost,

    /// Failed to establish a connection to the target host.
    ///
    /// Occurs when connection attempts time out or are rejected.
    HttpCouldntConnect,

    /// Received an unexpected or malformed response from the server.
    HttpWeirdServerReply,

    /// The server denied access to the requested resource.
    HttpRemoteAccessDenied,

    /// HTTP/2 protocol-specific error occurred (2300016).
    HttpHttp2Error = 2300016,

    /// File transfer completed only partially (2300018).
    ///
    /// The connection was closed before the full file could be transferred.
    HttpPartialFile = 2300018,

    /// Error occurred while writing data to a file or buffer (2300023).
    HttpWriteError = 2300023,

    /// File upload operation failed (2300025).
    HttpUploadFailed = 2300025,

    /// Error occurred while reading data from a file or stream (2300026).
    HttpReadError = 2300026,

    /// Insufficient memory to complete the operation.
    HttpOutOfMemory,

    /// Operation timed out before completion.
    ///
    /// The operation took longer than the specified timeout period.
    HttpOperationTimedout,

    /// Error during HTTP POST operation (2300034).
    HttpPostError = 2300034,

    /// The HTTP task was canceled before completion (2300042).
    HttpTaskCanceled = 2300042,

    /// Exceeded the maximum number of allowed redirects (2300047).
    HttpTooManyRedirects = 2300047,

    /// Received an empty response from the server (2300052).
    HttpGotNothing = 2300052,

    /// Error occurred while sending data to the server (2300055).
    HttpSendError = 2300055,

    /// Error occurred while receiving data from the server.
    HttpRecvError,

    /// Problem with the SSL certificate validation (2300058).
    HttpSslCertproblem = 2300058,

    /// SSL cipher selection or handshake failed.
    HttpSslCipher,

    /// Peer verification failed during SSL/TLS handshake.
    HttpPeerFailedVerification,

    /// The content encoding of the response is invalid or unsupported.
    HttpBadContentEncoding,

    /// File size exceeds the configured limit (2300063).
    HttpFilesizeExceeded = 2300063,

    /// Remote server reported that its disk is full (2300070).
    HttpRemoteDiskFull = 2300070,

    /// Operation failed because the remote file already exists (2300073).
    HttpRemoteFileExists = 2300073,

    /// CA certificate file is invalid or corrupted (2300077).
    HttpSslCacertBadfile = 2300077,

    /// The requested remote file was not found on the server.
    HttpRemoteFileNotFound,

    /// SSL public key pinning validation failed (2300090).
    ///
    /// The server's public key does not match the expected pinned key.
    HttpSslPinnedpubkeynotmatch = 2300090,

    /// Authentication with the server failed (2300094).
    HttpAuthError = 2300094,

    /// Catch-all for unknown or uncategorized errors (2300999).
    ///
    /// Used when an error occurs that doesn't match any specific error code.
    #[default]
    HttpUnknownOtherError = 2300999,
}