import Foundation
import Postbox
import TelegramApi

public struct EmojiInteraction: Equatable {
    public struct Animation: Equatable {
        public let index: Int
        public let timeOffset: Float
        
        public init(index: Int, timeOffset: Float) {
            self.index = index
            self.timeOffset = timeOffset
        }
    }
    
    public let animations: [Animation]
    
    public init(animations: [Animation]) {
        self.animations = animations
    }
    
    public init?(apiDataJson: Api.DataJSON) {
        if case let .dataJSON(string) = apiDataJson, let data = string.data(using: .utf8) {
            do {
                let decodedData = try JSONSerialization.jsonObject(with: data, options: [])
                guard let item = decodedData as? [String: Any] else {
                    return nil
                }
                guard let version = item["v"] as? Int, version == 1 else {
                    return nil
                }
                guard let animationsArray = item["a"] as? [Any] else {
                    return nil
                }
                var animations: [EmojiInteraction.Animation] = []
                for animationDict in animationsArray {
                    if let animationDict = animationDict as? [String: Any] {
                        if let index = animationDict["i"] as? Int, let timeOffset = animationDict["t"] as? Double {
                            animations.append(EmojiInteraction.Animation(index: index, timeOffset: Float(timeOffset)))
                        }
                    }
                }
                self.animations = animations
            } catch {
                return nil
            }
        } else {
            return nil
        }
    }
    
    fileprivate let roundingBehavior = NSDecimalNumberHandler(roundingMode: .plain, scale: 2, raiseOnExactness: false, raiseOnOverflow: false, raiseOnUnderflow: false, raiseOnDivideByZero: true)

    public var apiDataJson: Api.DataJSON {
        let dict = ["v": 1, "a": self.animations.map({ ["i": $0.index, "t": NSDecimalNumber(value: $0.timeOffset).rounding(accordingToBehavior: roundingBehavior)] as [String : Any] })] as [String : Any]
        if let data = try? JSONSerialization.data(withJSONObject: dict, options: []), let dataString = String(data: data, encoding: .utf8) {
            return .dataJSON(data: dataString)
        } else {
            return .dataJSON(data: "")
        }
    }
}

public enum PeerInputActivity: Comparable {
    case typingText
    case uploadingFile(progress: Int32)
    case recordingVoice
    case uploadingPhoto(progress: Int32)
    case uploadingVideo(progress: Int32)
    case playingGame
    case recordingInstantVideo
    case uploadingInstantVideo(progress: Int32)
    case speakingInGroupCall(timestamp: Int32)
    case choosingSticker
    case interactingWithEmoji(emoticon: String, messageId: MessageId, interaction: EmojiInteraction?)
    case seeingEmojiInteraction(emoticon: String)
    
    public var key: Int32 {
        switch self {
            case .typingText:
                return 0
            case .speakingInGroupCall:
                return 1
            case .uploadingFile:
                return 2
            case .recordingVoice:
                return 3
            case .uploadingPhoto:
                return 4
            case .uploadingVideo:
                return 5
            case .recordingInstantVideo:
                return 6
            case .uploadingInstantVideo:
                return 7
            case .playingGame:
                return 8
            case .choosingSticker:
                return 9
            case .interactingWithEmoji:
                return 10
            case .seeingEmojiInteraction:
                return 11
        }
    }
    
    public static func <(lhs: PeerInputActivity, rhs: PeerInputActivity) -> Bool {
        return lhs.key < rhs.key
    }
}

extension PeerInputActivity {
    init?(apiType: Api.SendMessageAction, peerId: PeerId?, timestamp: Int32) {
        switch apiType {
            case .sendMessageCancelAction, .sendMessageChooseContactAction, .sendMessageGeoLocationAction, .sendMessageRecordVideoAction:
                return nil
            case .sendMessageGamePlayAction:
                self = .playingGame
            case .sendMessageRecordAudioAction, .sendMessageUploadAudioAction:
                self = .recordingVoice
            case .sendMessageTypingAction:
                self = .typingText
            case let .sendMessageUploadDocumentAction(progress):
                self = .uploadingFile(progress: progress)
            case let .sendMessageUploadPhotoAction(progress):
                self = .uploadingPhoto(progress: progress)
            case let .sendMessageUploadVideoAction(progress):
                self = .uploadingVideo(progress: progress)
            case .sendMessageRecordRoundAction:
                self = .recordingInstantVideo
            case let .sendMessageUploadRoundAction(progress):
                self = .uploadingInstantVideo(progress: progress)
            case .speakingInGroupCallAction:
                self = .speakingInGroupCall(timestamp: timestamp)
            case .sendMessageChooseStickerAction:
                self = .choosingSticker
            case .sendMessageHistoryImportAction:
                return nil
            case let .sendMessageEmojiInteraction(emoticon, messageId, interaction):
                if let peerId = peerId {
                    self = .interactingWithEmoji(emoticon: emoticon, messageId: MessageId(peerId: peerId, namespace: Namespaces.Message.Cloud, id: messageId), interaction: EmojiInteraction(apiDataJson: interaction))
                } else {
                    return nil
                }
            case let .sendMessageEmojiInteractionSeen(emoticon):
                self = .seeingEmojiInteraction(emoticon: emoticon)
        }
    }
}