//
//  CookiesStore.swift
//  Astro
//
//  Created by Steven Shin on 3/14/17.
//  Copyright © 2017 Mobify Research & Development Inc. All rights reserved.
//

import Foundation
import WebKit

class CookiesStore: BaseMessageReceiver, Addressable, WKNavigationDelegate {
    @objc let address: MessageAddress = "AstroCookiesStore:0"
    private var wkWebView: WKWebView?
    private var cookieScript: String?

    init(messageBus: MessageBus) {
        super.init()

        self.addRpcMethodShim("setCookie") { params, respond in
            ////////// This will be autogenerated at some point //////////
            if let url: String = MethodShimUtils.getArg(params, key: "url", respond: respond),
                let key: String = MethodShimUtils.getArg(params, key: "key", respond: respond),
                let value: String = MethodShimUtils.getArg(params, key: "value", respond: respond) {
                self.setCookie(url, key: key, value: value, respond: respond)
            }
            /////////////////////////////////////////////////////////////
        }
        messageBus.register(self)
    }

    // @RpcMethod
    func setCookie(_ url: String, key: String, value: String, respond: RPCMethodCallback) {
        if key.isEmpty {
            respond(.error("Cannot set an empty key"))
            return
        }

        if url.isEmpty {
            respond(.error("Cannot set a cookie on an empty url"))
            return
        }
        setUIWebViewCookie(url, key: key, value: value)
        setWkWebViewCookie(url, key: key, value: value)
    }

    @objc func setUIWebViewCookie(_ url: String, key: String, value: String) -> Void {
        guard let cookies = HTTPCookieStorage.shared.cookies else {
            return
        }
        for cookie in cookies {
            guard cookie.name == key else {
                continue
            }

            // This cookie already exists
            if cookie.value == value {
                return
            }

            guard var properties = cookie.properties else {
                continue
            }

            // The cookie name exists but the value is different. Override this cookie
            properties[HTTPCookiePropertyKey.value] = value
            guard let newCookie = HTTPCookie(properties: properties) else {
                continue
            }
            HTTPCookieStorage.shared.setCookie(newCookie)
            return
        }
        // No cookie with the name was found, so create a new cookie
        // This should most likely not be called for sandy-client-id
        if let cookie = HTTPCookie.init(properties: [
            HTTPCookiePropertyKey.name: key,
            HTTPCookiePropertyKey.value: value,
            HTTPCookiePropertyKey.path: "/",
            HTTPCookiePropertyKey.domain: url
            ]) {
            HTTPCookieStorage.shared.setCookie(cookie)
        }
    }

    @objc func setWkWebViewCookie(_ url: String, key: String, value: String) {
        self.cookieScript = "document.cookie=\'\(key)=\(value)\'"
        guard let cookieURL = URL(string: url) else {
            return
        }
        let request = URLRequest(url: cookieURL)
        wkWebView = WKWebView(frame: .zero, configuration: WebViewPlugin.webViewConfiguration)
        wkWebView?.navigationDelegate = self
        _ = wkWebView?.load(request)
    }

    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        guard let cookieScript = self.cookieScript else {
            self.wkWebView = nil
            return
        }

        webView.evaluateJavaScript(cookieScript) { (_, error) -> Void in
            if error != nil {
                webView.reload()        // flush this cookie
                self.wkWebView = nil    // this webview is not needed anymore
            }
        }
    }
}
