// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
// Licensed under the MIT License (MIT). See License.txt in the repo root for license information.
// ------------------------------------------------------------

use crate::HRESULT;
use mssf_com::FabricTypes::FABRIC_ERROR_CODE;

// Common HRESULT codes that SF reuses from windows.
const S_OK: FABRIC_ERROR_CODE = FABRIC_ERROR_CODE(windows_core::Win32::Foundation::S_OK.0);
const E_ABORT: FABRIC_ERROR_CODE = FABRIC_ERROR_CODE(windows_core::Win32::Foundation::E_ABORT.0);
const E_ACCESSDENIED: FABRIC_ERROR_CODE =
    FABRIC_ERROR_CODE(windows_core::Win32::Foundation::E_ACCESSDENIED.0);
const E_FAIL: FABRIC_ERROR_CODE = FABRIC_ERROR_CODE(windows_core::Win32::Foundation::E_FAIL.0);
const E_HANDLE: FABRIC_ERROR_CODE = FABRIC_ERROR_CODE(windows_core::Win32::Foundation::E_HANDLE.0);
const E_INVALIDARG: FABRIC_ERROR_CODE =
    FABRIC_ERROR_CODE(windows_core::Win32::Foundation::E_INVALIDARG.0);
const E_NOINTERFACE: FABRIC_ERROR_CODE =
    FABRIC_ERROR_CODE(windows_core::Win32::Foundation::E_NOINTERFACE.0);
const E_NOTIMPL: FABRIC_ERROR_CODE =
    FABRIC_ERROR_CODE(windows_core::Win32::Foundation::E_NOTIMPL.0);
const E_OUTOFMEMORY: FABRIC_ERROR_CODE =
    FABRIC_ERROR_CODE(windows_core::Win32::Foundation::E_OUTOFMEMORY.0);
const E_POINTER: FABRIC_ERROR_CODE =
    FABRIC_ERROR_CODE(windows_core::Win32::Foundation::E_POINTER.0);
const E_UNEXPECTED: FABRIC_ERROR_CODE =
    FABRIC_ERROR_CODE(windows_core::Win32::Foundation::E_UNEXPECTED.0);

// HRESULT codes from win32 errors that SF resuses.
const E_FILE_EXISTS: FABRIC_ERROR_CODE =
    FABRIC_ERROR_CODE(HRESULT::from_win32(windows_core::Win32::Foundation::ERROR_FILE_EXISTS.0).0);
const E_DIR_NOT_EMPTY: FABRIC_ERROR_CODE = FABRIC_ERROR_CODE(
    HRESULT::from_win32(windows_core::Win32::Foundation::ERROR_DIR_NOT_EMPTY.0).0,
);
const E_NOT_FOUND: FABRIC_ERROR_CODE =
    FABRIC_ERROR_CODE(HRESULT::from_win32(windows_core::Win32::Foundation::ERROR_NOT_FOUND.0).0);

/// Hepler macro to define fabric error code.
/// SF uses win32 hresult code together with the custom fabric error code.
/// This enum helps passing errors between Rust and SF API, and is easy to debug.
/// code1 list are windows errors, lit is a dummy string literal, code list are fabric errors.
/// The macro defines windows errors first, then followed by fabric errors.
// Need to match cs impl:
// https://github.com/microsoft/service-fabric/blob/19791eb97c8d876517daa030e5a403f4bcad25b1/src/prod/src/managed/Api/src/System/Fabric/Interop/NativeTypes.cs#L57
macro_rules! define_fabric_error_code{
    ($( $code1:ident ),* ,($lit:literal), $( $code:ident ),*) =>{
        #[allow(non_camel_case_types)]
        #[derive(Debug, Clone, PartialEq)]
        #[repr(i32)]
        pub enum ErrorCode {
            // Define windows error codes for SF
            $(
                $code1 = $code1 .0,
            )*

            // defines SF error codes.
            $(
                $code = mssf_com::FabricTypes::$code .0,
            )*
        }

        impl TryFrom<FABRIC_ERROR_CODE> for ErrorCode {
            type Error = &'static str;

            fn try_from(value: FABRIC_ERROR_CODE) -> Result<Self, Self::Error> {
                match value {
                    $(
                        $code1 => Ok(Self::$code1),
                    )*
                    // SF code converts.
                    $(
                        mssf_com::FabricTypes::$code => Ok(Self::$code),
                    )*
                    _ => Err("Unknown FABRIC_ERROR_CODE")
                }
            }
        }
    }
}

impl From<ErrorCode> for crate::Error {
    fn from(value: ErrorCode) -> Self {
        crate::Error(HRESULT(value as i32))
    }
}

// other conversions goes through crate::Error
impl From<ErrorCode> for HRESULT {
    fn from(value: ErrorCode) -> Self {
        crate::Error::from(value).into()
    }
}

impl From<ErrorCode> for crate::WinError {
    fn from(value: ErrorCode) -> Self {
        crate::Error::from(value).into()
    }
}

impl core::fmt::Display for ErrorCode {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        core::write!(f, "{self:?}") // use the debug string
    }
}

// This defines all the fabric error codes.
// list copied from https://github.com/microsoft/service-fabric/blob/19791eb97c8d876517daa030e5a403f4bcad25b1/src/prod/src/idl/public/FabricTypes.idl#L60C18-L60C35
define_fabric_error_code!(
    S_OK,
    E_ABORT,
    E_ACCESSDENIED,
    E_FAIL,
    E_HANDLE,
    E_INVALIDARG,
    E_NOINTERFACE,
    E_NOTIMPL,
    E_OUTOFMEMORY,
    E_POINTER,
    E_UNEXPECTED,
    E_FILE_EXISTS,
    E_DIR_NOT_EMPTY,
    E_NOT_FOUND,
    ("Literal for breaking up first error chunk and the fabric errors"),
    FABRIC_E_COMMUNICATION_ERROR,
    FABRIC_E_INVALID_ADDRESS,
    FABRIC_E_INVALID_NAME_URI,
    FABRIC_E_INVALID_PARTITION_KEY,
    FABRIC_E_NAME_ALREADY_EXISTS,
    FABRIC_E_NAME_DOES_NOT_EXIST,
    FABRIC_E_NAME_NOT_EMPTY,
    FABRIC_E_NODE_NOT_FOUND,
    FABRIC_E_NODE_IS_UP,
    FABRIC_E_NO_WRITE_QUORUM,
    FABRIC_E_NOT_PRIMARY,
    FABRIC_E_NOT_READY,
    FABRIC_E_OPERATION_NOT_COMPLETE,
    FABRIC_E_PROPERTY_DOES_NOT_EXIST,
    FABRIC_E_RECONFIGURATION_PENDING,
    FABRIC_E_REPLICATION_QUEUE_FULL,
    FABRIC_E_SERVICE_ALREADY_EXISTS,
    FABRIC_E_SERVICE_DOES_NOT_EXIST,
    FABRIC_E_SERVICE_OFFLINE,
    FABRIC_E_SERVICE_METADATA_MISMATCH,
    FABRIC_E_SERVICE_AFFINITY_CHAIN_NOT_SUPPORTED,
    FABRIC_E_SERVICE_TYPE_ALREADY_REGISTERED,
    FABRIC_E_SERVICE_TYPE_NOT_REGISTERED,
    FABRIC_E_VALUE_TOO_LARGE,
    FABRIC_E_VALUE_EMPTY,
    FABRIC_E_PROPERTY_CHECK_FAILED,
    FABRIC_E_WRITE_CONFLICT,
    FABRIC_E_ENUMERATION_COMPLETED,
    FABRIC_E_APPLICATION_TYPE_PROVISION_IN_PROGRESS,
    FABRIC_E_APPLICATION_TYPE_ALREADY_EXISTS,
    FABRIC_E_APPLICATION_TYPE_NOT_FOUND,
    FABRIC_E_APPLICATION_TYPE_IN_USE,
    FABRIC_E_APPLICATION_ALREADY_EXISTS,
    FABRIC_E_APPLICATION_NOT_FOUND,
    FABRIC_E_APPLICATION_UPGRADE_IN_PROGRESS,
    FABRIC_E_APPLICATION_UPGRADE_VALIDATION_ERROR,
    FABRIC_E_SERVICE_TYPE_NOT_FOUND,
    FABRIC_E_SERVICE_TYPE_MISMATCH,
    FABRIC_E_SERVICE_TYPE_TEMPLATE_NOT_FOUND,
    FABRIC_E_CONFIGURATION_SECTION_NOT_FOUND,
    FABRIC_E_CONFIGURATION_PARAMETER_NOT_FOUND,
    FABRIC_E_INVALID_CONFIGURATION,
    FABRIC_E_IMAGEBUILDER_VALIDATION_ERROR,
    FABRIC_E_PARTITION_NOT_FOUND,
    FABRIC_E_REPLICA_DOES_NOT_EXIST,
    FABRIC_E_SERVICE_GROUP_ALREADY_EXISTS,
    FABRIC_E_SERVICE_GROUP_DOES_NOT_EXIST,
    FABRIC_E_PROCESS_DEACTIVATED,
    FABRIC_E_PROCESS_ABORTED,
    FABRIC_E_UPGRADE_FAILED,
    FABRIC_E_INVALID_CREDENTIAL_TYPE,
    FABRIC_E_INVALID_X509_FIND_TYPE,
    FABRIC_E_INVALID_X509_STORE_LOCATION,
    FABRIC_E_INVALID_X509_STORE_NAME,
    FABRIC_E_INVALID_X509_THUMBPRINT,
    FABRIC_E_INVALID_PROTECTION_LEVEL,
    FABRIC_E_INVALID_X509_STORE,
    FABRIC_E_INVALID_SUBJECT_NAME,
    FABRIC_E_INVALID_ALLOWED_COMMON_NAME_LIST,
    FABRIC_E_INVALID_CREDENTIALS,
    FABRIC_E_DECRYPTION_FAILED,
    FABRIC_E_CONFIGURATION_PACKAGE_NOT_FOUND,
    FABRIC_E_DATA_PACKAGE_NOT_FOUND,
    FABRIC_E_CODE_PACKAGE_NOT_FOUND,
    FABRIC_E_SERVICE_ENDPOINT_RESOURCE_NOT_FOUND,
    FABRIC_E_INVALID_OPERATION,
    FABRIC_E_OBJECT_CLOSED,
    FABRIC_E_TIMEOUT,
    FABRIC_E_FILE_NOT_FOUND,
    FABRIC_E_DIRECTORY_NOT_FOUND,
    FABRIC_E_INVALID_DIRECTORY,
    FABRIC_E_PATH_TOO_LONG,
    FABRIC_E_IMAGESTORE_IOERROR,
    FABRIC_E_CORRUPTED_IMAGE_STORE_OBJECT_FOUND,
    FABRIC_E_APPLICATION_NOT_UPGRADING,
    FABRIC_E_APPLICATION_ALREADY_IN_TARGET_VERSION,
    FABRIC_E_IMAGEBUILDER_UNEXPECTED_ERROR,
    FABRIC_E_FABRIC_VERSION_NOT_FOUND,
    FABRIC_E_FABRIC_VERSION_IN_USE,
    FABRIC_E_FABRIC_VERSION_ALREADY_EXISTS,
    FABRIC_E_FABRIC_ALREADY_IN_TARGET_VERSION,
    FABRIC_E_FABRIC_NOT_UPGRADING,
    FABRIC_E_FABRIC_UPGRADE_IN_PROGRESS,
    FABRIC_E_FABRIC_UPGRADE_VALIDATION_ERROR,
    FABRIC_E_HEALTH_MAX_REPORTS_REACHED,
    FABRIC_E_HEALTH_STALE_REPORT,
    FABRIC_E_KEY_TOO_LARGE,
    FABRIC_E_KEY_NOT_FOUND,
    FABRIC_E_SEQUENCE_NUMBER_CHECK_FAILED,
    FABRIC_E_ENCRYPTION_FAILED,
    FABRIC_E_INVALID_ATOMIC_GROUP,
    FABRIC_E_HEALTH_ENTITY_NOT_FOUND,
    FABRIC_E_SERVICE_MANIFEST_NOT_FOUND,
    FABRIC_E_RELIABLE_SESSION_TRANSPORT_STARTUP_FAILURE,
    FABRIC_E_RELIABLE_SESSION_ALREADY_EXISTS,
    FABRIC_E_RELIABLE_SESSION_CANNOT_CONNECT,
    FABRIC_E_RELIABLE_SESSION_MANAGER_EXISTS,
    FABRIC_E_RELIABLE_SESSION_REJECTED,
    FABRIC_E_RELIABLE_SESSION_MANAGER_ALREADY_LISTENING,
    FABRIC_E_RELIABLE_SESSION_MANAGER_NOT_FOUND,
    FABRIC_E_RELIABLE_SESSION_MANAGER_NOT_LISTENING,
    FABRIC_E_INVALID_SERVICE_TYPE,
    FABRIC_E_IMAGEBUILDER_TIMEOUT,
    FABRIC_E_IMAGEBUILDER_ACCESS_DENIED,
    FABRIC_E_IMAGEBUILDER_INVALID_MSI_FILE,
    FABRIC_E_SERVICE_TOO_BUSY,
    FABRIC_E_TRANSACTION_NOT_ACTIVE,
    FABRIC_E_REPAIR_TASK_ALREADY_EXISTS,
    FABRIC_E_REPAIR_TASK_NOT_FOUND,
    FABRIC_E_RELIABLE_SESSION_NOT_FOUND,
    FABRIC_E_RELIABLE_SESSION_QUEUE_EMPTY,
    FABRIC_E_RELIABLE_SESSION_QUOTA_EXCEEDED,
    FABRIC_E_RELIABLE_SESSION_SERVICE_FAULTED,
    FABRIC_E_RELIABLE_SESSION_INVALID_TARGET_PARTITION,
    FABRIC_E_TRANSACTION_TOO_LARGE,
    FABRIC_E_REPLICATION_OPERATION_TOO_LARGE,
    FABRIC_E_INSTANCE_ID_MISMATCH,
    FABRIC_E_UPGRADE_DOMAIN_ALREADY_COMPLETED,
    FABRIC_E_NODE_HAS_NOT_STOPPED_YET,
    FABRIC_E_INSUFFICIENT_CLUSTER_CAPACITY,
    FABRIC_E_INVALID_PACKAGE_SHARING_POLICY,
    FABRIC_E_PREDEPLOYMENT_NOT_ALLOWED,
    FABRIC_E_INVALID_BACKUP_SETTING,
    FABRIC_E_MISSING_FULL_BACKUP,
    FABRIC_E_BACKUP_IN_PROGRESS,
    FABRIC_E_DUPLICATE_SERVICE_NOTIFICATION_FILTER_NAME,
    FABRIC_E_INVALID_REPLICA_OPERATION,
    FABRIC_E_INVALID_REPLICA_STATE,
    FABRIC_E_LOADBALANCER_NOT_READY,
    FABRIC_E_INVALID_PARTITION_OPERATION,
    FABRIC_E_PRIMARY_ALREADY_EXISTS,
    FABRIC_E_SECONDARY_ALREADY_EXISTS,
    FABRIC_E_BACKUP_DIRECTORY_NOT_EMPTY,
    FABRIC_E_FORCE_NOT_SUPPORTED_FOR_REPLICA_OPERATION,
    FABRIC_E_ACQUIRE_FILE_LOCK_FAILED,
    FABRIC_E_CONNECTION_DENIED,
    FABRIC_E_SERVER_AUTHENTICATION_FAILED,
    FABRIC_E_CONSTRAINT_KEY_UNDEFINED,
    FABRIC_E_MULTITHREADED_TRANSACTIONS_NOT_ALLOWED,
    FABRIC_E_INVALID_X509_NAME_LIST,
    FABRIC_E_VERBOSE_FM_PLACEMENT_HEALTH_REPORTING_REQUIRED,
    FABRIC_E_GATEWAY_NOT_REACHABLE,
    FABRIC_E_USER_ROLE_CLIENT_CERTIFICATE_NOT_CONFIGURED,
    FABRIC_E_TRANSACTION_ABORTED,
    FABRIC_E_CANNOT_CONNECT,
    FABRIC_E_MESSAGE_TOO_LARGE,
    FABRIC_E_CONSTRAINT_NOT_SATISFIED,
    FABRIC_E_ENDPOINT_NOT_FOUND,
    FABRIC_E_APPLICATION_UPDATE_IN_PROGRESS,
    FABRIC_E_DELETE_BACKUP_FILE_FAILED,
    FABRIC_E_CONNECTION_CLOSED_BY_REMOTE_END,
    FABRIC_E_INVALID_TEST_COMMAND_STATE,
    FABRIC_E_TEST_COMMAND_OPERATION_ID_ALREADY_EXISTS,
    FABRIC_E_CM_OPERATION_FAILED,
    FABRIC_E_IMAGEBUILDER_RESERVED_DIRECTORY_ERROR,
    FABRIC_E_CERTIFICATE_NOT_FOUND,
    FABRIC_E_CHAOS_ALREADY_RUNNING,
    FABRIC_E_FABRIC_DATA_ROOT_NOT_FOUND,
    FABRIC_E_INVALID_RESTORE_DATA,
    FABRIC_E_DUPLICATE_BACKUPS,
    FABRIC_E_INVALID_BACKUP_CHAIN,
    FABRIC_E_STOP_IN_PROGRESS,
    FABRIC_E_ALREADY_STOPPED,
    FABRIC_E_NODE_IS_DOWN,
    FABRIC_E_NODE_TRANSITION_IN_PROGRESS,
    FABRIC_E_INVALID_BACKUP,
    FABRIC_E_INVALID_INSTANCE_ID,
    FABRIC_E_INVALID_DURATION,
    FABRIC_E_RESTORE_SAFE_CHECK_FAILED,
    FABRIC_E_CONFIG_UPGRADE_FAILED,
    FABRIC_E_UPLOAD_SESSION_RANGE_NOT_SATISFIABLE,
    FABRIC_E_UPLOAD_SESSION_ID_CONFLICT,
    FABRIC_E_INVALID_PARTITION_SELECTOR,
    FABRIC_E_INVALID_REPLICA_SELECTOR,
    FABRIC_E_DNS_SERVICE_NOT_FOUND,
    FABRIC_E_INVALID_DNS_NAME,
    FABRIC_E_DNS_NAME_IN_USE,
    FABRIC_E_COMPOSE_DEPLOYMENT_ALREADY_EXISTS,
    FABRIC_E_COMPOSE_DEPLOYMENT_NOT_FOUND,
    FABRIC_E_INVALID_FOR_STATEFUL_SERVICES,
    FABRIC_E_INVALID_FOR_STATELESS_SERVICES,
    FABRIC_E_ONLY_VALID_FOR_STATEFUL_PERSISTENT_SERVICES,
    FABRIC_E_INVALID_UPLOAD_SESSION_ID,
    FABRIC_E_BACKUP_NOT_ENABLED,
    FABRIC_E_BACKUP_IS_ENABLED,
    FABRIC_E_BACKUP_POLICY_DOES_NOT_EXIST,
    FABRIC_E_BACKUP_POLICY_ALREADY_EXISTS,
    FABRIC_E_RESTORE_IN_PROGRESS,
    FABRIC_E_RESTORE_SOURCE_TARGET_PARTITION_MISMATCH,
    FABRIC_E_FAULT_ANALYSIS_SERVICE_NOT_ENABLED,
    FABRIC_E_CONTAINER_NOT_FOUND,
    FABRIC_E_OBJECT_DISPOSED,
    FABRIC_E_NOT_READABLE,
    FABRIC_E_BACKUPCOPIER_UNEXPECTED_ERROR,
    FABRIC_E_BACKUPCOPIER_TIMEOUT,
    FABRIC_E_BACKUPCOPIER_ACCESS_DENIED,
    FABRIC_E_INVALID_SERVICE_SCALING_POLICY,
    FABRIC_E_SINGLE_INSTANCE_APPLICATION_ALREADY_EXISTS,
    FABRIC_E_SINGLE_INSTANCE_APPLICATION_NOT_FOUND,
    FABRIC_E_VOLUME_ALREADY_EXISTS,
    FABRIC_E_VOLUME_NOT_FOUND,
    FABRIC_E_DATABASE_MIGRATION_IN_PROGRESS,
    FABRIC_E_CENTRAL_SECRET_SERVICE_GENERIC,
    FABRIC_E_SECRET_INVALID,
    FABRIC_E_SECRET_VERSION_ALREADY_EXISTS,
    FABRIC_E_SINGLE_INSTANCE_APPLICATION_UPGRADE_IN_PROGRESS,
    FABRIC_E_OPERATION_NOT_SUPPORTED,
    FABRIC_E_COMPOSE_DEPLOYMENT_NOT_UPGRADING,
    FABRIC_E_SECRET_TYPE_CANNOT_BE_CHANGED,
    FABRIC_E_NETWORK_NOT_FOUND,
    FABRIC_E_NETWORK_IN_USE,
    FABRIC_E_ENDPOINT_NOT_REFERENCED
);
