//
//  Utils.swift
//  react-native-vivocha
//
//  Created by Marco Lanzotti on 03/12/24.
//

import Foundation
import VivochaSDK

class Utils {
    static func objToOptions(obj: NSDictionary?) -> VivochaSDK.VivochaOptions? {
        if (obj == nil) {
            return nil
        }
        let options = VivochaSDK.VivochaOptions.fromBuilder({ builder in
            if (obj?["blockSideTab"] != nil) {
                builder.setOption(BLOCK_SIDE_TAB_BUTTON, withBoolean: obj?["blockSideTab"] as! Bool)
            }
            if (obj?["audioVideo"] != nil) {
                builder.setOption(DISABLE_AUDIO_VIDEO_FEATURE, withBoolean: obj?["audioVideo"] as! Bool)
            }
            if (obj?["cannedQuestion"] != nil) {
                builder.setOption(DISABLE_CANNED_QUESTION_FEATURE, withBoolean: obj?["cannedQuestion"] as! Bool)
            }
            if (obj?["autoRestoreChatView"] != nil) {
                builder.setOption(DISABLE_CHAT_VIEW_AUTO_RESTORING_ON_APP_KILL, withBoolean: obj?["autoRestoreChatView"] as! Bool)
            }
            if (obj?["fileTransfer"] != nil) {
                builder.setOption(DISABLE_FILE_TRANSFER_FEATURE, withBoolean: obj?["fileTransfer"] as! Bool)
            }
            if (obj?["location"] != nil) {
                builder.setOption(DISABLE_LOCATION_FEATURE, withBoolean: obj?["location"] as! Bool)
            }
            if (obj?["screenshot"] != nil) {
                builder.setOption(DISABLE_SCREENSHOT_FEATURE, withBoolean: obj?["screenshot"] as! Bool)
            }
            if (obj?["developerMode"] != nil) {
                builder.setOption(ENABLE_DEVELOPER_MODE, withBoolean: obj?["developerMode"] as! Bool)
            }
            if (obj?["server"] != nil) {
                builder.setOption(SERVER_URL, with: obj?["server"] as! String)
            }
            if (obj?["waitToken"] != nil) {
                builder.setOption(WAIT_FOR_TOKEN, withBoolean: obj?["waitToken"] as! Bool)
            }
        })
        return options
    }
    
    static func arrayToDataCollection(data: NSArray?) -> VivochaDataCollection? {
        if (data == nil) {
            return nil
        }
        let dataCollection = VivochaDataCollection()
        for aForm in data! {
            let form = aForm as! NSDictionary
            let dataForm = VivochaDataCollectionForm()
            if (form["name"] != nil) {
                dataForm.name = form["name"] as? String
            }
            if (form["desc"] != nil) {
                dataForm.desc = form["desc"] as? String
            }
            if (form["data"] != nil) {
                for aField in form["data"] as! NSArray {
                    let field = aField as! NSDictionary
                    let dataField = VivochaDataCollectionField()
                    
                    switch field["type"] as! String {
                    case "text":
                        dataField.type = VivochaDataCollectionFieldType.text
                    case "date":
                        dataField.type = VivochaDataCollectionFieldType.date
                    case "email":
                        dataField.type = VivochaDataCollectionFieldType.email
                    case "link":
                        dataField.type = VivochaDataCollectionFieldType.link
                    case "nickname":
                        dataField.type = VivochaDataCollectionFieldType.nickname
                    case "number":
                        dataField.type = VivochaDataCollectionFieldType.number
                    case "phone":
                        dataField.type = VivochaDataCollectionFieldType.phone
                    case "checkbox":
                        dataField.type = VivochaDataCollectionFieldType.checkbox
                    case "firstname":
                        dataField.type = VivochaDataCollectionFieldType.firstName
                    case "lastname":
                        dataField.type = VivochaDataCollectionFieldType.lastName
                    default:
                        dataField.type = VivochaDataCollectionFieldType.text
                    }
                    if (field["name"] != nil) {
                        dataField.name = field["name"] as? String
                    }
                    if (field["desc"] != nil) {
                        dataField.desc = field["desc"] as? String
                    }
                    if (field["value"] != nil) {
                        dataField.value = field["value"] as? String
                    }
                    if (field["visible"] != nil) {
                        dataField.visible = field["visible"] as! Bool
                    }
                    if (field["secure"] != nil) {
                        dataField.secure = field["secure"] as! Bool
                    }
                    if (field["checked"] != nil) {
                        dataField.checked = field["checked"] as! Bool
                    }
                    dataForm.add(dataField)
                }
            }
            dataCollection.addForm(dataForm)
        }
        return dataCollection
    }
    
    static func dataCollectionToArray(dataCollection: VivochaDataCollection) -> NSArray {
        let data: NSMutableArray = []
        for _collectionForm in dataCollection.forms {
            let collectionForm = _collectionForm as! VivochaDataCollectionForm
            let form: NSMutableDictionary = [:]
            
            if (collectionForm.name != nil) {
                form.setValue(collectionForm.name, forKey: "name")
            }
            if (collectionForm.desc != nil) {
                form.setValue(collectionForm.desc, forKey: "desc")
            }
            let fields: NSMutableArray = []
            for _collectionField in collectionForm.data {
                let collectionField = _collectionField as! VivochaDataCollectionField
                let field: NSMutableDictionary = [:]
                
                switch collectionField.type {
                case VivochaDataCollectionFieldType.text:
                    field.setValue("text", forKey: "type")
                case VivochaDataCollectionFieldType.date:
                    field.setValue("date", forKey: "type")
                case VivochaDataCollectionFieldType.email:
                    field.setValue("email", forKey: "type")
                case VivochaDataCollectionFieldType.link:
                    field.setValue("link", forKey: "type")
                case VivochaDataCollectionFieldType.nickname:
                    field.setValue("nickname", forKey: "type")
                case VivochaDataCollectionFieldType.number:
                    field.setValue("number", forKey: "type")
                case VivochaDataCollectionFieldType.phone:
                    field.setValue("phone", forKey: "type")
                case VivochaDataCollectionFieldType.checkbox:
                    field.setValue("checkbox", forKey: "type")
                case VivochaDataCollectionFieldType.firstName:
                    field.setValue("firstname", forKey: "type")
                case VivochaDataCollectionFieldType.lastName:
                    field.setValue("lastname", forKey: "type")
                default:
                    field.setValue("text", forKey: "type")
                }
                if (collectionField.name != nil) {
                    field.setValue(collectionField.name, forKey: "name")
                }
                if (collectionField.value != nil) {
                    field.setValue(collectionField.value, forKey: "value")
                }
                if (collectionField.desc != nil) {
                    field.setValue(collectionField.desc, forKey: "desc")
                }
                field.setValue(collectionField.visible, forKey: "visible")
                field.setValue(collectionField.secure, forKey: "secure")
                field.setValue(collectionField.checked, forKey: "checked")
                fields.add(field)
            }
            form.setValue(fields, forKey: "data")
            data.add(form)
        }
        return data
    }
    
    static func agentToDictionary(agent: VivochaAgent?) -> NSDictionary? {
        if (agent == nil) {
            return nil
        }
        return [
            "isBot": agent?.isBot,
            "name": agent?.name,
            "avatar": agent?.avatarURL
        ]
    }

    static func contactToDictionary(contact: VivochaContact?) -> NSDictionary? {
        if (contact == nil) {
            return nil
        }
        return [
            "contactId": contact?.contactID,
            "connected": !(contact?.isTerminated ?? true),
            "agent": agentToDictionary(agent: contact?.agent())
        ]
    }

    static func conversationToDictionary(conversation: VivochaConversation?) -> NSDictionary? {
        if (conversation == nil) {
            return nil
        }
        return [
            "json": conversation?.jsonString,
            "conversationId": conversation?.conversationID
        ]
    }
    
    static func objToLocalization(language: NSString, localization: NSDictionary) -> VivochaLocalization? {
        let loc = VivochaLocalization(language: language as String)
        for entry in localization {
            loc?.setTranslation(entry.value as! String, forKey: entry.key as! String)
        }
        return loc
    }
    
    static func colorToHex(color: UIColor) -> String? {
        var red: CGFloat = 0
        var green: CGFloat = 0
        var blue: CGFloat = 0
        var alpha: CGFloat = 0
        
        let multiplier = CGFloat(255.999999)
        
        guard color.getRed(&red, green: &green, blue: &blue, alpha: &alpha) else {
            return nil
        }
        
        if alpha == 1.0 {
            return String(
                format: "#%02lX%02lX%02lX",
                Int(red * multiplier),
                Int(green * multiplier),
                Int(blue * multiplier)
            )
        } else {
            return String(
                format: "#%02lX%02lX%02lX%02lX",
                Int(red * multiplier),
                Int(green * multiplier),
                Int(blue * multiplier),
                Int(alpha * multiplier)
            )
        }
    }
    
    static func colorComponentFrom(color: String, start: Int, length: Int) -> CGFloat {
        let startIndex = color.index(color.startIndex, offsetBy: start)
        let endIndex = color.index(startIndex, offsetBy: length)
        let subString = color[startIndex..<endIndex]
        let fullHexString = length == 2 ? subString : "\(subString)\(subString)"
        var hexComponent: UInt64 = 0
        guard Scanner(string: String(fullHexString)).scanHexInt64(&hexComponent) else {
            return 0
        }
        let hexFloat: CGFloat = CGFloat(hexComponent)
        let floatValue: CGFloat = CGFloat(hexFloat / 255.0)
        return floatValue
    }

    static func hexToColor(hex: String) -> UIColor {
        var colorString = hex.trimmingCharacters(in: .whitespacesAndNewlines)
        colorString = colorString.replacingOccurrences(of: "#", with: "").uppercased()
        
        let alpha: CGFloat = 1.0
        let red: CGFloat = colorComponentFrom(color: colorString, start: 0, length: 2)
        let green: CGFloat = colorComponentFrom(color: colorString, start: 2, length: 2)
        let blue: CGFloat = colorComponentFrom(color: colorString, start: 4, length: 2)

        let color = UIColor(red: red, green: green, blue: blue, alpha: alpha)
        return color
    }
    
    static func themeToObj(theme: VivochaTheme?) -> NSDictionary? {
        if (theme == nil) { return nil }
        return [
            "chatBackgroundColor": colorToHex(color: theme!.chatBackgroundColor),
            "chatBubbleCornerRadius": theme!.chatBubbleCornerRadius,
            "chatBubbleIncomingColor": colorToHex(color: theme!.chatBubbleIncomingColor),
            "chatBubbleIncomingTextColor": colorToHex(color: theme!.chatBubbleIncomingTextColor),
            "chatBubbleOutgoingColor": colorToHex(color: theme!.chatBubbleOutgoingColor),
            "chatBubbleOutgoingTextColor": colorToHex(color: theme!.chatBubbleOutgoingTextColor),
            "chatInputViewBackgroundColor": colorToHex(color: theme!.chatInputViewBackgroundColor),
            "chatInputViewTextColor": colorToHex(color: theme!.chatInputViewTextColor),
            "chatLoadingBackgroundColor": colorToHex(color: theme!.chatLoadingBackgroundColor),
            "chatLoadingSpinnerColor": colorToHex(color: theme!.chatLoadingSpinnerColor),
            "chatLoadingTextColor": colorToHex(color: theme!.chatLoadingTextColor),
            "chatSendButtonBackgroundColor": colorToHex(color: theme!.chatSendButtonBackgroundColor),
            "chatSendButtonTextColor": colorToHex(color: theme!.chatSendButtonTextColor),
            "chatStatusTextColor": colorToHex(color: theme!.chatStatusTextColor),
            "chatTopViewBackgroundColor": colorToHex(color: theme!.chatTopViewBackgroundColor),
            "chatTopViewButtonTextColor": colorToHex(color: theme!.chatTopViewButtonTextColor),
            "enableChatViewNavBarTranslucency": theme!.enableChatViewNavBarTranslucency,
            "showReadReceiptOnChatBubble": theme!.showReadReceiptOnChatBubble,
            "showReceiptsOnChatBubble": theme!.showReceiptsOnChatBubble,
            "sideButtonBackgroundColor": colorToHex(color: theme!.sideButtonBackgroundColor),
            "sideButtonPosition": theme!.sideButtonPosition,
            "sideButtonSide": theme!.sideButtonSide,
            "sideButtonText": theme!.sideButtonText,
            "sideButtonTextColor": colorToHex(color: theme!.sideButtonTextColor),
        ]
    }
    
    static func objToTheme(obj: NSDictionary) -> VivochaTheme {
        let theme: VivochaTheme = VivochaTheme()
        if let value = obj["chatBackgroundColor"] {
            theme.chatBackgroundColor = hexToColor(hex: value as! String)
        }
        if let value = obj["chatBubbleCornerRadius"] {
            theme.chatBubbleCornerRadius = value as! CGFloat
        }
        if let value = obj["chatBubbleIncomingColor"] {
            theme.chatBubbleIncomingColor = hexToColor(hex: value as! String)
        }
        if let value = obj["chatBubbleIncomingTextColor"] {
            theme.chatBubbleIncomingTextColor = hexToColor(hex: value as! String)
        }
        if let value = obj["chatBubbleOutgoingColor"] {
            theme.chatBubbleOutgoingColor = hexToColor(hex: value as! String)
        }
        if let value = obj["chatBubbleOutgoingTextColor"] {
            theme.chatBubbleOutgoingTextColor = hexToColor(hex: value as! String)
        }
        if let value = obj["chatInputViewBackgroundColor"] {
            theme.chatInputViewBackgroundColor = hexToColor(hex: value as! String)
        }
        if let value = obj["chatInputViewTextColor"] {
            theme.chatInputViewTextColor = hexToColor(hex: value as! String)
        }
        if let value = obj["chatLoadingBackgroundColor"] {
            theme.chatLoadingBackgroundColor = hexToColor(hex: value as! String)
        }
        if let value = obj["chatLoadingSpinnerColor"] {
            theme.chatLoadingSpinnerColor = hexToColor(hex: value as! String)
        }
        if let value = obj["chatLoadingTextColor"] {
            theme.chatLoadingTextColor = hexToColor(hex: value as! String)
        }
        if let value = obj["chatSendButtonBackgroundColor"] {
            theme.chatSendButtonBackgroundColor = hexToColor(hex: value as! String)
        }
        if let value = obj["chatSendButtonTextColor"] {
            theme.chatSendButtonTextColor = hexToColor(hex: value as! String)
        }
        if let value = obj["chatStatusTextColor"] {
            theme.chatStatusTextColor = hexToColor(hex: value as! String)
        }
        if let value = obj["chatTopViewBackgroundColor"] {
            theme.chatTopViewBackgroundColor = hexToColor(hex: value as! String)
        }
        if let value = obj["chatTopViewButtonTextColor"] {
            theme.chatTopViewButtonTextColor = hexToColor(hex: value as! String)
        }
        if let value = obj["enableChatViewNavBarTranslucency"] {
            theme.enableChatViewNavBarTranslucency = value as! String
        }
        if let value = obj["showReadReceiptOnChatBubble"] {
            theme.showReadReceiptOnChatBubble = value as! String
        }
        if let value = obj["showReceiptsOnChatBubble"] {
            theme.showReceiptsOnChatBubble = value as! String
        }
        if let value = obj["sideButtonBackgroundColor"] {
            theme.sideButtonBackgroundColor = hexToColor(hex: value as! String)
        }
        if let value = obj["sideButtonPosition"] {
            theme.sideButtonPosition = value as! VivochaPosition
        }
        if let value = obj["sideButtonSide"] {
            theme.sideButtonSide = value as! VivochaPositionSide
        }
        if let value = obj["sideButtonText"] {
            theme.sideButtonText = value as! String
        }
        if let value = obj["sideButtonTextColor"] {
            theme.sideButtonTextColor = hexToColor(hex: value as! String)
        }
        return theme
    }
    
    static func mediaToObj(media: VivochaMedia?) -> NSDictionary? {
        if (media == nil) { return nil }
        return [
            "isLocalAudioEnabled": media?.isLocalAudioEnabled,
            "isLocalVideoEnabled": media?.isLocalVideoEnabled,
            "isRemoteAudioEnabled": media?.isRemoteAudioEnabled,
            "isRemoteVideoEnabled": media?.isRemoteVideoEnabled
        ]
    }
    
    static func messageToObj(message: VivochaMessage) -> NSDictionary {
        return [
            "messageText": message.messageText,
            "id": message.objectID,
            "remotePeer": message.remotePeer
        ]
    }
    
    static func presenceToObj(presence: VivochaChatPresence) -> NSDictionary {
        return [
            "type": presence.type.rawValue,
            "isOnline": presence.isOnline(),
            "isOutgoing": presence.isOutgoing,
            "isReceived": presence.isReceived(),
            "isRead": presence.isRead(),
            "agent": agentToDictionary(agent: presence.agent)
        ]
    }
    
    private static func dateToIso8601(date: Date) -> String {
        let formatter = ISO8601DateFormatter()
        return formatter.string(from: date)
    }
    
    static func ackToObj(ack: VivochaChatAck) -> NSDictionary {
        let data: NSMutableDictionary = [:]
        data.setValue(ack.messageId, forKey: "messageId")
        data.setValue(dateToIso8601(date: ack.timestamp), forKey: "timestamp")
        if (ack.type == VivochaChatAckType.read) { data.setValue("read", forKey: "type") }
        else if (ack.type == VivochaChatAckType.received) { data.setValue("received", forKey: "type") }
        else { data.setValue("", forKey: "type") }
        return data
    }
}
