//
//  Dictionaries.swift
//  Pods
//
//  Created by Tomasz Oponowicz on 22/11/2024.
//

import Foundation

func deepCompare(_ dict1: [String: Any], _ dict2: [String: Any]) -> Bool {
    guard dict1.count == dict2.count else { return false }

    for (key, value1) in dict1 {
        guard let value2 = dict2[key] else { return false }

        if let subDict1 = value1 as? [String: Any], let subDict2 = value2 as? [String: Any] {
            // Recursively compare nested dictionaries
            if !deepCompare(subDict1, subDict2) {
                return false
            }
        } else if let array1 = value1 as? [Any], let array2 = value2 as? [Any] {
            // Recursively compare arrays
            if !deepCompareArrays(array1, array2) {
                return false
            }
        } else if !areEqual(value1, value2) {
            // Compare primitive values or unsupported types
            return false
        }
    }

    return true
}

func deepCompareArrays(_ array1: [Any], _ array2: [Any]) -> Bool {
    guard array1.count == array2.count else { return false }

    for (item1, item2) in zip(array1, array2) {
        if let subDict1 = item1 as? [String: Any], let subDict2 = item2 as? [String: Any] {
            // Recursively compare dictionaries in arrays
            if !deepCompare(subDict1, subDict2) {
                return false
            }
        } else if let subArray1 = item1 as? [Any], let subArray2 = item2 as? [Any] {
            // Recursively compare arrays in arrays
            if !deepCompareArrays(subArray1, subArray2) {
                return false
            }
        } else if !areEqual(item1, item2) {
            // Compare primitive values or unsupported types
            return false
        }
    }

    return true
}

func areEqual(_ value1: Any, _ value2: Any) -> Bool {
    // Compare values using `Equatable` conformance where possible
    if let v1 = value1 as? String, let v2 = value2 as? String {
        return v1 == v2
    } else if let v1 = value1 as? Int, let v2 = value2 as? Int {
        return v1 == v2
    } else if let v1 = value1 as? Double, let v2 = value2 as? Double {
        return v1 == v2
    } else if let v1 = value1 as? Bool, let v2 = value2 as? Bool {
        return v1 == v2
    } else if value1 is NSNull && value2 is NSNull {
        return true
    }

    return false
}

// Any Codable struct can use this method
extension Encodable {
    func toDictionary() -> [String: Any]? {
        guard let data = try? JSONEncoder().encode(self) else { return nil }
        return try? JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
    }
}
