//
//  WebViewElement.swift
//  Pascal
//
//  Created by Helena McGahagan on 5/3/19.
//  Copyright © 2019 Evidation Health, Inc. All rights reserved.
//

import Foundation

struct NavigationResponseHandler {
    let interceptUrl: String
    let statusCodeMap: [String:Int]?
    // Maping of response status codes to actions
    let responsePolicyActions: [Int:Action]
}

/// WebViewElement defines a web view
/// The element can define its response policy to intercepted urls
public class WebViewElement: Element {
    public let family = "presentation"
    public let type = "web_view"
    public let id: String?
    public let layout: Layout
    public let style: ServerStyle?
    public let dynamicViewFactory: DynamicViewFactory
    public let requirements: ElementRequirements = ElementRequirements(isRequired: false, errorText: nil)
    
    /// A web view element may specify the initial url to load
    let url: String?
    /// Alternatively, it may specify a LoadUrlAction that will return a url
    let urlAction: JSONObject?
    let responseHandlers: [NavigationResponseHandler]
    let bannerContent: JSONObject?
    let spinnerDefinition: SpinnerDefinition?
    let showNavigationBar: Bool // Default: true
    let navigationTitle: String // Default: ""
    let rightNavigationButtonDefinitions: [NavigationButtonDefinition]
    
    /// Note that one of url/urlAction is required
    private init(url: String?, urlAction: JSONObject?, responseHandlers: [NavigationResponseHandler],
                 id: String?, layout: Layout, style: ServerStyle?, bannerContent: JSONObject?,
                 spinnerDefinition: SpinnerDefinition?, dynamicViewFactory: DynamicViewFactory,
                 showNavigationBar: Bool, navigationTitle: String, rightNavigationButtonDefinitions: [NavigationButtonDefinition]) {
        self.id = id
        self.layout = layout
        self.style = style
        self.dynamicViewFactory = dynamicViewFactory
        self.url = url
        self.urlAction = urlAction
        self.responseHandlers = responseHandlers
        self.bannerContent = bannerContent
        self.spinnerDefinition = spinnerDefinition
        self.showNavigationBar = showNavigationBar
        self.navigationTitle = navigationTitle
        self.rightNavigationButtonDefinitions = rightNavigationButtonDefinitions
    }
    
    public static func createElement(json: JSONObject, dynamicViewFactory: DynamicViewFactory) -> Element? {
        // Require either a url be specified or an action that will retrive that url
        let url = json["uri"]?.string
        let urlAction = (url == nil) ? json["uri_action"]?.dictionary : nil
        guard url != nil || urlAction != nil else { return nil }
        
        let handlers = json["response_handlers"]?.array?.compactMap { $0.dictionary } ?? []
        let responseHandlers: [NavigationResponseHandler] =
            handlers.compactMap {handler in
                guard let interceptUrl = handler["intercept_url"]?.string else { return nil }
                
                let parsedInterceptUrl = parseUrl(interceptUrl)
                
                var statusCodeMap = [String: Int]()
                let statusCodeJSONMap = handler["status_code_map"]?.dictionary
                statusCodeJSONMap?.forEach { key, value in
                    guard let code = value.int else { return }
                    statusCodeMap[key] = code
                }
                let statusCodes = handler["status_codes"]?.dictionary ?? [:]
                var responsePolicyActions = [Int:Action]()
                for (status, json) in statusCodes {
                    guard
                        let actionJson = json.dictionary,
                        let action = dynamicViewFactory.actionFactory.create(from: actionJson),
                        let statusCode = Int(status) else { continue }
                    
                    responsePolicyActions[statusCode] = action
                }
                return NavigationResponseHandler(interceptUrl: parsedInterceptUrl,
                                                 statusCodeMap: statusCodeMap,
                                                 responsePolicyActions: responsePolicyActions)
            }
        
        let id = json["id"]?.string ?? json["identifier"]?.string
        let layout = Layout(json: json["layout"]?.dictionary)
        let style = json["style"]?.dictionary
        let bannerContent = json["banner_content"]?.dictionary
        
        let spinnerContent = json["spinner"]?.dictionary
        let spinnerDefinition = SpinnerDefinition(json: spinnerContent)
        
        let navigation = json["navigation"]?.dictionary
        let showNavigationBar = navigation != nil
        let navigationTitle = navigation?["title"]?.string ?? ""
        let navigationButtonJson = navigation?["right"]?.array?.compactMap { $0.dictionary }
        let buttonDefinitions = navigationButtonJson?.compactMap {
            NavigationButtonDefinition(json: $0)
        }
        
        let element = WebViewElement(url: url, urlAction: urlAction,
                                     responseHandlers: responseHandlers,
                                     id: id, layout: layout, style: style,
                                     bannerContent: bannerContent,
                                     spinnerDefinition: spinnerDefinition,
                                     dynamicViewFactory: dynamicViewFactory,
                                     showNavigationBar: showNavigationBar,
                                     navigationTitle: navigationTitle,
                                     rightNavigationButtonDefinitions: buttonDefinitions ?? [])
        return element
    }
    
    // TODO: remove
    private static func parseUrl(_ url: String) -> String { return url }
}
