import Foundation
import BlazeSDK

extension [String: AnyHashable] {
    
    var toDataSourceType: BlazeDataSourceType? {
        var datasourceType: BlazeDataSourceType? = nil
        if let widgetLabel = self["labels"]?.asBlazeWidgetLabel {
            
            let orderType = self["orderType"]?.asOrderType
            let maxItems = self["maxItems"] as? Int
            
            let labelsPriority: [BlazeWidgetLabel]?
            if let labelsPriorityArray = self["labelsPriority"] as? [AnyHashable] {
                labelsPriority = labelsPriorityArray.compactMap({ item in
                    return item.asBlazeWidgetLabel
                })
            } else {
                labelsPriority = nil
            }
            
            datasourceType = .labels(widgetLabel,
                                     labelsPriority: labelsPriority,
                                     orderType: orderType,
                                     maxItems: maxItems)
        } else if let idsDataSource = self["ids"] as? [String] {
            let orderType = self["orderType"]?.asOrderType
            datasourceType = .ids(idsDataSource,
                                  orderType: orderType)
            
        } else if let recommendationsDataSource = self["recommendationsType"]?.asBlazeRecommendations {
            datasourceType = .recommendations(recommendationsDataSource)
        }
        
        return datasourceType
    }
    
    var toReactWidgetLayout: BlazeReactWidgetLayout? {
        var result: BlazeReactWidgetLayout?
        
        do {
            let jsonData = try JSONSerialization.data(withJSONObject: self, options: [])
            result = try JSONDecoder().decode(BlazeReactWidgetLayout.self, from: jsonData)
        } catch {
            print("Error decoding JSON: \(error)")
        }
        
        return result
    }
    
    var toReactStoryPlayerStyle: BlazeReactStoryPlayerStyle? {
        var result: BlazeReactStoryPlayerStyle?
        
        do {
            let jsonData = try JSONSerialization.data(withJSONObject: self, options: [])
            result = try JSONDecoder().decode(BlazeReactStoryPlayerStyle.self, from: jsonData)
        } catch {
            print("Error decoding JSON: \(error)")
        }
        
        return result

    }

    var toReactMomentsPlayerStyle: BlazeReactMomentsPlayerStyle? {
        var result: BlazeReactMomentsPlayerStyle?
        
        do {
            let jsonData = try JSONSerialization.data(withJSONObject: self, options: [])
            result = try JSONDecoder().decode(BlazeReactMomentsPlayerStyle.self, from: jsonData)
        } catch {
            print("Error decoding JSON: \(error)")
        }
        
        return result

    }

}

extension AnyHashable {
    
    var asOrderType: BlazeOrderType? {
        guard let orderTypeString = self as? String else { return nil }
        
        switch orderTypeString {
        case "manual":
            return .manual
        case "recentlyUpdatedFirst":
            return .recentlyUpdatedFirst
        case "recentlyUpdatedLast":
            return .recentlyUpdatedLast
        case "aToZ":
            return .aToZ
        case "zToA":
            return .zToA
        case "recentlyCreatedFirst":
            return .recentlyCreatedFirst
        case "recentlyCreatedLast":
            return .recentlyCreatedLast
        case "random":
            return .random
        default:
            return nil
        }
    }
    
}

extension AnyHashable {
    
    var asBlazeWidgetLabel: BlazeWidgetLabel? {
        guard let labelDataSource = self as? [String: Any],
              let labelValue = labelDataSource["value"] as? String else {
                  return nil
        }
        
        return .singleLabel(labelValue)
    }
    
    var asBlazeRecommendations: BlazeRecommendationsType? {
        guard let recommendationsDataSource = self as? [String: Any],
              let type = recommendationsDataSource["type"] as? String else {
            return nil
        }
        
        let anyLabelFilter = recommendationsDataSource["anyLabelFilter"] as? [String] ?? []
        
        guard let recommendationType = BlazeRecommendationsType.from(type: type, anyLabelFilter: anyLabelFilter) else {
            return nil
        }
        
        return recommendationType
    }
}

extension BlazeRecommendationsType {
    static func from(type: String, anyLabelFilter: [String]) -> BlazeRecommendationsType? {
        switch type {
        case "ForYou":
            return .forYou(anyLabelFilter: anyLabelFilter)
        case "Trending":
            return .trending(anyLabelFilter: anyLabelFilter)
        default:
            return nil
        }
    }
}

extension Dictionary where Key == String, Value == AnyHashable {
    /// Transforms the dictionary into a map of BlazeReactWidgetItemCustomMapping to BlazeReactWidgetStylesOverrides
    var toReactWidgetStylesOverridesMap: [BlazeReactWidgetItemCustomMapping: BlazeReactWidgetStylesOverrides]? {
        var resultMap = [BlazeReactWidgetItemCustomMapping: BlazeReactWidgetStylesOverrides]()

        // Iterate through each key-value pair in the dictionary
        for (key, value) in self {
            // Attempt to decode the key into BlazeReactWidgetItemCustomMapping
            guard let keyData = key.data(using: .utf8),
                  let keyValue = try? JSONDecoder().decode(BlazeReactWidgetItemCustomMapping.self, from: keyData) else {
                continue
            }

            // Attempt to serialize the value dictionary and decode it into BlazeReactWidgetStylesOverrides
            guard let valueDict = value as? [String: AnyHashable],
                  let valueData = try? JSONSerialization.data(withJSONObject: valueDict, options: []),
                  let valueValue = try? JSONDecoder().decode(BlazeReactWidgetStylesOverrides.self, from: valueData) else {
                continue
            }

            // Add to the result map
            resultMap[keyValue] = valueValue
        }

        return resultMap.isEmpty ? nil : resultMap
    }
}

extension String {
    var asCachingLevel: BlazeCachePolicyLevel? {
        switch self {
        case "LOW":
            return .Low
        case "DEFAULT":
            return .Default
        case "HIGH":
            return .High
        case "EXTREME":
            return .Extreme
        default:
            return nil
        }
    }
}

