//
//  EmotionHelper.swift
//  TUILiveKit
//
//  Created by krabyu on 2024/4/3.
//

import UIKit

class EmotionHelper {
    static let shared = {
        EmotionHelper()
    }()

    private init() {
        useDefaultEmotions()
    }

    var emotions: [Emotion] = []
    private var cacheTotalImageDictionary: [String: UIImage] = [:]
    private var cacheAttributedDictionary: [String: NSAttributedString] = [:]
    private var regularExpression: NSRegularExpression = try! NSRegularExpression(pattern: "\\[[a-zA-Z0-9_\\u4e00-\\u9fa5]+\\]", options: [])

    func useDefaultEmotions() {
        createTotalEmotions()
        cacheTotalImage()
    }

    func setEmotions(emotions: [Emotion]) {
        self.emotions = emotions
        cacheTotalImageDictionary = [:]
        cacheTotalImage()
    }

    func cacheTotalImage() {
        if cacheTotalImageDictionary.count == 0 {
            var emotionImageDictionary: [String: UIImage] = [:]
            for emotion in emotions {
                if emotion.image.size.width != 0 {
                    emotion.image = UIImage(named: emotion.identifier, in: tuiRoomKitBundle(), compatibleWith: nil) ?? UIImage()
                }
                emotionImageDictionary[emotion.displayName] = emotion.image
            }
            cacheTotalImageDictionary = emotionImageDictionary
        }
    }

    func obtainImagesAttributedString(byText text: String, font: UIFont) -> NSMutableAttributedString {
        let matches = regularExpression.matches(in: text, range: NSRange(location: 0, length: text.count))
        let intactAttributedString = NSMutableAttributedString(string: text)
        for match in matches.reversed() {
            guard let emojiRange = Range(match.range, in: text) else { return NSMutableAttributedString(string: "") }
            let emojiKey = String(text[emojiRange])

            var useCache = true
            if #available(iOS 15.0, *) {
                // Cached NSAttributedString cannot be used on ios15, only one expression will appear, but it can be used on ios14 and before.
                useCache = false
            }
            let imageAttributedString = obtainImageAttributedString(byImageKey: emojiKey, font: font, useCache: useCache)
            intactAttributedString.replaceCharacters(in: match.range, with: imageAttributedString)
        }
        // Fixed an issue where font changed due to inserting AttributeString;
        // Prevents the textView font from getting smaller after inserting an expression
        intactAttributedString.addAttribute(.font, value: font, range: NSRange(location: 0, length: intactAttributedString.length))
        intactAttributedString.addAttribute(.foregroundColor, value:  UIColor.tui_color(withHex: "D5E0F2"), range: NSRange(location: 0, length: intactAttributedString.length))
        return intactAttributedString
    }

    func obtainImageAttributedString(byImageKey imageKey: String, font: UIFont, useCache: Bool) -> NSAttributedString {
        if !useCache {
            let image = cacheTotalImageDictionary[imageKey]
            if image == nil {
                return NSAttributedString(string: "")
            }
            let emotionAttachment = EmotionAttachment()
            emotionAttachment.displayText = imageKey
            emotionAttachment.image = image
            emotionAttachment.bounds = CGRect(x: 0, y: font.descender, width: font.lineHeight, height: font.lineHeight)
            let imageAttributedString = NSAttributedString(attachment: emotionAttachment)
            return imageAttributedString
        }

        let keyFont = String(format: "%@%.1f", imageKey, font.pointSize)
        if let result = cacheAttributedDictionary[keyFont] {
            return result
        }
        guard let image = cacheTotalImageDictionary[imageKey] else {
            return NSAttributedString(string: "")
        }

        let emotionAttachment = EmotionAttachment()
        emotionAttachment.displayText = imageKey
        emotionAttachment.image = image
        emotionAttachment.bounds = CGRect(x: 0, y: font.descender, width: font.lineHeight, height: font.lineHeight)
        let result = NSAttributedString(attachment: emotionAttachment)
        cacheAttributedDictionary[keyFont] = result
        return result
    }

    private func createTotalEmotions() {
        emotions = []
        emotions.append(Emotion(identifier: "room_floatChat_emoji_0", displayName: "[TUIEmoji_Smile]"))
        emotions.append(Emotion(identifier: "room_floatChat_emoji_1", displayName: "[TUIEmoji_Expect]"))
        emotions.append(Emotion(identifier: "room_floatChat_emoji_2", displayName: "[TUIEmoji_Blink]"))
        emotions.append(Emotion(identifier: "room_floatChat_emoji_3", displayName: "[TUIEmoji_Guffaw]"))
        emotions.append(Emotion(identifier: "room_floatChat_emoji_4", displayName: "[TUIEmoji_KindSmile]"))
        emotions.append(Emotion(identifier: "room_floatChat_emoji_5", displayName: "[TUIEmoji_Haha]"))
        emotions.append(Emotion(identifier: "room_floatChat_emoji_6", displayName: "[TUIEmoji_Cheerful]"))
        emotions.append(Emotion(identifier: "room_floatChat_emoji_7", displayName: "[TUIEmoji_Speechless]"))
        emotions.append(Emotion(identifier: "room_floatChat_emoji_8", displayName: "[TUIEmoji_Amazed]"))
        emotions.append(Emotion(identifier: "room_floatChat_emoji_9", displayName: "[TUIEmoji_Sorrow]"))

        emotions.append(Emotion(identifier: "room_floatChat_emoji_10", displayName: "[TUIEmoji_Complacent]"))
        emotions.append(Emotion(identifier: "room_floatChat_emoji_11", displayName: "[TUIEmoji_Silly]"))
        emotions.append(Emotion(identifier: "room_floatChat_emoji_12", displayName: "[TUIEmoji_Lustful]"))
        emotions.append(Emotion(identifier: "room_floatChat_emoji_13", displayName: "[TUIEmoji_Giggle]"))
        emotions.append(Emotion(identifier: "room_floatChat_emoji_14", displayName: "[TUIEmoji_Kiss]"))
        emotions.append(Emotion(identifier: "room_floatChat_emoji_15", displayName: "[TUIEmoji_Wail]"))
        emotions.append(Emotion(identifier: "room_floatChat_emoji_16", displayName: "[TUIEmoji_TearsLaugh]"))
        emotions.append(Emotion(identifier: "room_floatChat_emoji_17", displayName: "[TUIEmoji_Trapped]"))
        emotions.append(Emotion(identifier: "room_floatChat_emoji_18", displayName: "[TUIEmoji_Mask]"))
        emotions.append(Emotion(identifier: "room_floatChat_emoji_19", displayName: "[TUIEmoji_Fear]"))

        emotions.append(Emotion(identifier: "room_floatChat_emoji_20", displayName: "[TUIEmoji_BareTeeth]"))
        emotions.append(Emotion(identifier: "room_floatChat_emoji_21", displayName: "[TUIEmoji_FlareUp]"))
        emotions.append(Emotion(identifier: "room_floatChat_emoji_22", displayName: "[TUIEmoji_Yawn]"))
        emotions.append(Emotion(identifier: "room_floatChat_emoji_23", displayName: "[TUIEmoji_Tact]"))
        emotions.append(Emotion(identifier: "room_floatChat_emoji_24", displayName: "[TUIEmoji_Stareyes]"))
        emotions.append(Emotion(identifier: "room_floatChat_emoji_25", displayName: "[TUIEmoji_ShutUp]"))
        emotions.append(Emotion(identifier: "room_floatChat_emoji_26", displayName: "[TUIEmoji_Sigh]"))
        emotions.append(Emotion(identifier: "room_floatChat_emoji_27", displayName: "[TUIEmoji_Hehe]"))
        emotions.append(Emotion(identifier: "room_floatChat_emoji_28", displayName: "[TUIEmoji_Silent]"))
        emotions.append(Emotion(identifier: "room_floatChat_emoji_29", displayName: "[TUIEmoji_Surprised]"))

        emotions.append(Emotion(identifier: "room_floatChat_emoji_30", displayName: "[TUIEmoji_Askance]"))
        emotions.append(Emotion(identifier: "room_floatChat_emoji_31", displayName: "[TUIEmoji_Ok]"))
        emotions.append(Emotion(identifier: "room_floatChat_emoji_32", displayName: "[TUIEmoji_Shit]"))
        emotions.append(Emotion(identifier: "room_floatChat_emoji_33", displayName: "[TUIEmoji_Monster]"))
        emotions.append(Emotion(identifier: "room_floatChat_emoji_34", displayName: "[TUIEmoji_Daemon]"))
        emotions.append(Emotion(identifier: "room_floatChat_emoji_35", displayName: "[TUIEmoji_Rage]"))
        emotions.append(Emotion(identifier: "room_floatChat_emoji_36", displayName: "[TUIEmoji_Fool]"))
        emotions.append(Emotion(identifier: "room_floatChat_emoji_37", displayName: "[TUIEmoji_Pig]"))
        emotions.append(Emotion(identifier: "room_floatChat_emoji_38", displayName: "[TUIEmoji_Cow]"))
        emotions.append(Emotion(identifier: "room_floatChat_emoji_39", displayName: "[TUIEmoji_Ai]"))

        emotions.append(Emotion(identifier: "room_floatChat_emoji_40", displayName: "[TUIEmoji_Skull]"))
        emotions.append(Emotion(identifier: "room_floatChat_emoji_41", displayName: "[TUIEmoji_Bombs]"))
        emotions.append(Emotion(identifier: "room_floatChat_emoji_42", displayName: "[TUIEmoji_Coffee]"))
        emotions.append(Emotion(identifier: "room_floatChat_emoji_43", displayName: "[TUIEmoji_Cake]"))
        emotions.append(Emotion(identifier: "room_floatChat_emoji_44", displayName: "[TUIEmoji_Beer]"))
        emotions.append(Emotion(identifier: "room_floatChat_emoji_45", displayName: "[TUIEmoji_Flower]"))
        emotions.append(Emotion(identifier: "room_floatChat_emoji_46", displayName: "[TUIEmoji_Watermelon]"))
        emotions.append(Emotion(identifier: "room_floatChat_emoji_47", displayName: "[TUIEmoji_Rich]"))
        emotions.append(Emotion(identifier: "room_floatChat_emoji_48", displayName: "[TUIEmoji_Heart]"))
        emotions.append(Emotion(identifier: "room_floatChat_emoji_49", displayName: "[TUIEmoji_Moon]"))

        emotions.append(Emotion(identifier: "room_floatChat_emoji_50", displayName: "[TUIEmoji_Sun]"))
        emotions.append(Emotion(identifier: "room_floatChat_emoji_51", displayName: "[TUIEmoji_Star]"))
        emotions.append(Emotion(identifier: "room_floatChat_emoji_52", displayName: "[TUIEmoji_RedPacket]"))
        emotions.append(Emotion(identifier: "room_floatChat_emoji_53", displayName: "[TUIEmoji_Celebrate]"))
        emotions.append(Emotion(identifier: "room_floatChat_emoji_54", displayName: "[TUIEmoji_Bless]"))
        emotions.append(Emotion(identifier: "room_floatChat_emoji_55", displayName: "[TUIEmoji_Fortune]"))
        emotions.append(Emotion(identifier: "room_floatChat_emoji_56", displayName: "[TUIEmoji_Convinced]"))
        emotions.append(Emotion(identifier: "room_floatChat_emoji_57", displayName: "[TUIEmoji_Prohibit]"))
        emotions.append(Emotion(identifier: "room_floatChat_emoji_58", displayName: "[TUIEmoji_666]"))
        emotions.append(Emotion(identifier: "room_floatChat_emoji_59", displayName: "[TUIEmoji_857]"))

        emotions.append(Emotion(identifier: "room_floatChat_emoji_60", displayName: "[TUIEmoji_Knife]"))
        emotions.append(Emotion(identifier: "room_floatChat_emoji_61", displayName: "[TUIEmoji_Like]"))

        for emotion in emotions {
            emotion.image = UIImage(named: emotion.identifier, in: tuiRoomKitBundle(), compatibleWith: nil) ?? UIImage()
        }
    }
}

