/*
 * Copyright (c) 2023 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#import <WebKit/WebKit.h>
#include "web_cookie_manager_ios.h"
#import <Foundation/Foundation.h>
using namespace OHOS::NWebError;

namespace OHOS::Plugin {
bool SetCookie(const std::string& url, std::map<std::string, std::string> cookieAttr,
    std::map<std::string, std::string> cookieValue)
{
    NSString* ocUrl = [NSString stringWithCString:url.c_str() encoding:NSUTF8StringEncoding];
    NSString* urlHost = [[NSURL URLWithString:ocUrl] host];
    if (ocUrl == nil || urlHost == nil) {
        return false;
    }
    for (auto iter = cookieValue.begin(); iter != cookieValue.end(); iter++) {
        NSString* key = (0 == iter->first.length()) ? (@"") : (@(iter->first.c_str()));
        NSString* value = (0 == iter->second.length()) ? (@"") : (@(iter->second.c_str()));
        NSString* path = [NSString stringWithCString:cookieAttr["path"].c_str() encoding:NSUTF8StringEncoding];
        NSString* domain = [NSString stringWithCString:cookieAttr["domain"].c_str() encoding:NSUTF8StringEncoding];
        NSString* expiresDate =
            [NSString stringWithCString:cookieAttr["expires"].c_str() encoding:NSUTF8StringEncoding];
        NSString* maxAge = [NSString stringWithCString:cookieAttr["max-age"].c_str() encoding:NSUTF8StringEncoding];
        NSString* sameSite = [NSString stringWithCString:cookieAttr["samesite"].c_str() encoding:NSUTF8StringEncoding];
        NSString* isSecure = [NSString stringWithCString:cookieAttr["secure"].c_str() encoding:NSUTF8StringEncoding];
        NSMutableDictionary* cookieProperties = [NSMutableDictionary dictionary];
        if (key == nil || value == nil || key.length == 0 || value.length == 0) {
            break;
        }
        [cookieProperties setObject:key forKey:NSHTTPCookieName];
        [cookieProperties setObject:value forKey:NSHTTPCookieValue];
        if (path != nil && path.length != 0) {
            [cookieProperties setObject:path forKey:NSHTTPCookiePath];
        } else {
            [cookieProperties setObject:@"/" forKey:NSHTTPCookiePath];
        }
        if (domain != nil && domain.length != 0) {
            [cookieProperties setObject:domain forKey:NSHTTPCookieDomain];
        } else {
            [cookieProperties setObject:urlHost forKey:NSHTTPCookieDomain];
        }
        if (expiresDate != nil && expiresDate.length != 0) {
            [cookieProperties setObject:expiresDate forKey:NSHTTPCookieExpires];
        }
        if (maxAge != nil && maxAge.length != 0) {
            [cookieProperties setObject:maxAge forKey:NSHTTPCookieMaximumAge];
        }
        if (isSecure != nil && [isSecure boolValue]) {
            [cookieProperties setObject:@"TRUE" forKey:NSHTTPCookieSecure];
        }
        if (sameSite != nil && sameSite.length != 0) {
            [cookieProperties setObject:sameSite forKey:NSHTTPCookieSameSitePolicy];
        }
        NSHTTPCookie* cookie = [NSHTTPCookie cookieWithProperties:cookieProperties];
        [NSHTTPCookieStorage.sharedHTTPCookieStorage setCookie:cookie];
    }
    return true;
}

ErrCode WebCookieManagerIOS::ConfigCookie(const std::string& url, const std::string& value, int32_t asyncCallbackInfoId)
{
    NSArray* cookieAttribute = @[
        @"domain", @"path", @"expires", @"max-age", @"size", @"httponly", @"secure", @"samesite", @"partitioned",
        @"priority"
    ];
    NSString* ocUrl = [NSString stringWithCString:url.c_str() encoding:NSUTF8StringEncoding];
    NSString* ocString = [NSString stringWithCString:value.c_str() encoding:NSUTF8StringEncoding];
    NSArray* array = [ocString componentsSeparatedByString:@";"];
    std::map<std::string, std::string> cookieValueDict;
    std::map<std::string, std::string> cookieAttrDict;
    for (NSString* key_value in array) {
        NSRange range = [key_value rangeOfString:@"="];
        if (range.location != NSNotFound) {
            NSArray* keyValueArray = [key_value componentsSeparatedByString:@"="];
            NSString* cookieName = [keyValueArray objectAtIndex:0];
            NSString* cookieValue = [keyValueArray objectAtIndex:1];
            BOOL contains = [cookieAttribute containsObject:[cookieName lowercaseString]];
            if (contains) {
                cookieAttrDict.insert(
                    std::map<std::string, std::string>::value_type([cookieName UTF8String], [cookieValue UTF8String]));
            } else {
                cookieValueDict.insert(
                    std::map<std::string, std::string>::value_type([cookieName UTF8String], [cookieValue UTF8String]));
            }
        }
    }
    WebCookieManager::OnConfigReceiveValue(SetCookie(url, cookieAttrDict, cookieValueDict), asyncCallbackInfoId);
    return NO_ERROR;
}

void WebCookieManagerIOS::FetchCookie(const std::string& url, int32_t asyncCallbackInfoId)
{
    NSString* ocUrl = [NSString stringWithCString:url.c_str() encoding:NSUTF8StringEncoding];
    NSString* urlHost = [[NSURL URLWithString:ocUrl] host];
    NSString* cookieValue = @"";
    NSArray* cookies = NSHTTPCookieStorage.sharedHTTPCookieStorage.cookies;
    for (int i = 0; i < cookies.count; i++) {
        NSHTTPCookie* cookie = cookies[i];
        if ([urlHost hasSuffix:cookie.domain] ||
            [[NSString stringWithFormat:@".\\%@", urlHost] hasSuffix:cookie.domain]) {
            NSString* nameValue = [NSString stringWithFormat:@"%@=%@", cookie.name, cookie.value];
            if (cookieValue.length > 0) {
                cookieValue = [NSString stringWithFormat:@"%@;%@", cookieValue, nameValue];
            } else {
                cookieValue = nameValue;
            }
        }
    }

    WebCookieManager::OnFetchReceiveValue([cookieValue UTF8String], asyncCallbackInfoId);
}

void WebCookieManagerIOS::ClearAllCookies(int32_t asyncCallbackInfoId)
{
    NSHTTPCookieStorage* sharedHTTPCookieStorage = NSHTTPCookieStorage.sharedHTTPCookieStorage;
    NSArray* cookies = sharedHTTPCookieStorage.cookies;
    for (int i = 0; i < (int)cookies.count; i++) {
        [sharedHTTPCookieStorage deleteCookie:cookies[i]];
    }
    WebCookieManager::OnClearReceiveValue(asyncCallbackInfoId);
}

bool WebCookieManagerIOS::ExistCookie(bool incognito)
{
    NSHTTPCookieStorage* sharedHTTPCookieStorage = NSHTTPCookieStorage.sharedHTTPCookieStorage;
    NSArray* cookies = sharedHTTPCookieStorage.cookies;
    return cookies && [cookies count] > 0;
}

void WebCookieManagerIOS::ClearSessionCookie(int32_t asyncCallbackInfoId)
{
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_11_0
    if (@available(iOS 11.0, *)) {
        WKWebsiteDataStore *defaultDataStore = [WKWebsiteDataStore defaultDataStore];
        WKHTTPCookieStore *wkHTTPCookieStorage = [defaultDataStore httpCookieStore];
        [wkHTTPCookieStorage getAllCookies:^(NSArray<NSHTTPCookie *> * _Nonnull cookies) {
            for (NSHTTPCookie *cookie in cookies) {
                if ([cookie isSessionOnly]) {
                    [wkHTTPCookieStorage deleteCookie:cookie completionHandler:nil];
                }
            }
        }];
    }
#endif
    NSHTTPCookieStorage *sharedHTTPCookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
    NSArray<NSHTTPCookie *> * cookies = [sharedHTTPCookieStorage.cookies copy];
    for (NSHTTPCookie *cookie in cookies) {
        if ([cookie isSessionOnly]) {
            [sharedHTTPCookieStorage deleteCookie:cookie];
        }
    }
    WebCookieManager::OnClearReceiveValue(asyncCallbackInfoId);
}
} // namespace OHOS::Plugin