import Foundation

/// A JSON sanitizing utility.
///
/// While most of the bridging between React Native and DevRev SDK is handled by the `RCTConvert` class,
/// some types are not converted as expected by standard JSON serialization, so we need to handle them manually.
///
/// This object provides a method for sanitizing these types.
///
/// - Important: The React Native boolean type can be converted to a `NSNumber` of a subtype `__NSCFBoolean`,
///   which is not a valid type for JSON serialization (produces `1` or `0` instead of `true` or `false`).
struct JSONSanitizer {
	/// Recursively sanitizes a dictionary.
	///
	/// - Parameters:
	///   - dictionary: The dictionary to sanitize.
	///
	/// - Returns: A new dictionary with sanitized values.
	func sanitize(
		dictionary: [String: Any]
	) -> [String: Any] {
		dictionary.mapValues { sanitize(value: $0) }
	}

	/// Recursively sanitizes an array.
	///
	/// - Parameters:
	///   - array: The array to sanitize.
	///
	/// - Returns: A new array with sanitized values.
	func sanitize(
		array: [Any]
	) -> [Any] {
		array.map { sanitize(value: $0) }
	}

	/// Sanitizes a single value, handling different types appropriately.
	///
	/// - Parameters:
	///   - value: The value to sanitize.
	///
	/// - Returns: The sanitized value.
	func sanitize(value: Any) -> Any {
		if let value = value as? String {
			return value
		}
		else if let rawNumber = value as? NSNumber {
			// Convert NSNumber (which includes __NSCFBoolean) to Swift Bool if it's a boolean.
			if CFGetTypeID(value as CFTypeRef) == CFBooleanGetTypeID() {
				// Preserve the original boolean value (true or false)
				return rawNumber.boolValue
			}

			return rawNumber
		}
		else if let value = value as? [String: Any] {
			return sanitize(dictionary: value)
		}
		else if let value = value as? [Any] {
			return sanitize(array: value)
		}

		return value
	}
}
