//
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//

import Foundation
public import LibSignalClient
import ObjectiveC

extension Error {
    public var isRetryable: Bool {
        // Error and NSError have a special relationship.
        // They can be "cast" back and forth, but are separate objects.
        //
        // If Error is cast to NSError, a new NSError will wrap the Error.
        // This is called "NSError bridging".
        //
        // NSError implements Error protocol, but casting NSError to Error
        // might unwrap a bridged wrapper.
        //
        // If you roundtrip-cast Error to NSError and back (or vice versa),
        // you should not count on ending up with the same as instance as
        // you began with, even though you sometimes will.
        //
        // When trying to cast an error to IsRetryableProvider,
        // we need to try casting both the Error and NSError form.
        if let error = self as? IsRetryableProvider, error.isRetryableProvider {
            return true
        }
        if let error = (self as NSError) as? IsRetryableProvider, error.isRetryableProvider {
            return true
        }

        if self.isNetworkFailureOrTimeout {
            // We can safely default to retrying network failures.
            return true
        }

        return false
    }
}

// MARK: -

public protocol IsRetryableProvider {
    var isRetryableProvider: Bool { get }
}

// MARK: -

// NOTE: We typically prefer to use a more specific error.
public class OWSRetryableError: CustomNSError, IsRetryableProvider {
    public static var asNSError: NSError {
        OWSRetryableError() as Error as NSError
    }

    public init() {
    }

    // MARK: - IsRetryableProvider

    public var isRetryableProvider: Bool { true }
}

// MARK: - SignalError

extension SignalError: IsRetryableProvider {
    public var isRetryableProvider: Bool {
        switch self {
        case .mismatchedDevices: return true
        default: return false
        }
    }
}
