//
//  MessagesExtension.swift
//  WoWonder
//
//  Created by Mohammed Hamad on 02/08/2022.
//  Copyright © 2022 ScriptSun. All rights reserved.
//

import Foundation
import CoreData
import UIKit

extension Messages: CoreDataObject {
    
    static var fetcher: CoreDataFetcher<Messages> {
        get {
            return CoreDataFetcher<Messages>()
        }
    }
    
    convenience init(chat_id: String, message: MessageModel) {
        self.init(context: CoreDataManager.getInstance().context)
        self.chat_id = chat_id
        self.my_id = Messages.getMaxID() + 1
        self.setMessageModelToFields(message)
        self.created_at = Date()
    }
    
    enum MessageTypes: String, CaseIterable, Codable {
        case leftAudio = "left_audio"
        case rightAudio = "right_audio"
        case leftVideo = "left_video"
        case rightVideo = "right_video"
        case leftSticker = "left_sticker"
        case rightSticker = "right_sticker"
        case leftImage = "left_image"
        case rightImage = "right_image"
        case leftGif = "left_gif"
        case rightGif = "right_gif"
        case leftFile = "left_file"
        case rightFile = "right_file"
        case leftText = "left_text"
        case rightText = "right_text"
        case leftContact = "left_contact"
        case rightContact = "right_contact"
        case leftProduct = "left_product"
        case rightProduct = "right_product"
        case leftMap = "left_map"
        case rightMap = "right_map"
        case none = "None"
    }
    
    var _message_id: String {
        get {
            return self.message_id ?? ""
        }
    }
    
    var _from_id: String {
        get {
            return self.from_id ?? ""
        }
    }
    
    var _group_id: String {
        get {
            return self.group_id ?? ""
        }
    }
    
    var _page_id: String {
        get {
            return self.page_id ?? ""
        }
    }
    
    var _to_id: String {
        get {
            return self.to_id ?? ""
        }
    }
    
    var _text: String {
        get {
            return self.text ?? ""
        }
    }
    
    var _media: String {
        get {
            return self.media ?? ""
        }
    }
    
    var _media_file_name: String {
        get {
            return self.media_file_name ?? ""
        }
    }
    
    var _time: String {
        get {
            return self.time ?? ""
        }
    }
    
    var date: Date? {
        get {
            guard let double = Double(self._time) else { return nil }
            return Date(timeIntervalSince1970: double)
        }
    }
    
    var _seen: String {
        get {
            return self.seen ?? ""
        }
    }
    
    var _deleted_one: String {
        get {
            return self.deleted_one ?? ""
        }
    }
    
    var _deleted_two: String {
        get {
            return self.deleted_two ?? ""
        }
    }
    
    var _product_id: String {
        get {
            return self.product_id ?? ""
        }
    }
    
    var _lat: String {
        get {
            return self.lat ?? ""
        }
    }
    
    var _lng: String {
        get {
            return self.lng ?? ""
        }
    }
    
    var _reply_id: String {
        get {
            return self.reply_id ?? ""
        }
    }
    
    var _story_id: String {
        get {
            return self.story_id ?? ""
        }
    }
    
    var _pin: String {
        get {
            return self.pin ?? ""
        }
    }
    
    var _fav: String {
        get {
            return self.fav ?? ""
        }
    }
    
    var _time_text: String {
        get {
            return self.time_text ?? ""
        }
    }
    
    var _position: String {
        get {
            return self.position ?? ""
        }
    }
    
    var _type: String {
        get {
            return self.type ?? ""
        }
    }
    
    var _typeObject: MessageTypes? {
        get {
            return MessageTypes(rawValue: self._type)
        }
    }
    
    var _file_size: String {
        get {
            return self.file_size ?? ""
        }
    }
    
    var _stickers: String {
        get {
            return self.stickers ?? ""
        }
    }
    
    var _chat_color: String {
        get {
            return self.chat_color ?? ""
        }
    }
    
    var _hash_id: String {
        get {
            return self.hash_id ?? ""
        }
    }
    
    var _date_time: Date {
        get {
            return self.date_time ?? Date()
        }
    }
    
    var _created_at: Date {
        get {
            return self.created_at ?? Date()
        }
    }
    
    var _reaction: String {
        get {
            if self.reaction?.the1 != nil {
                return "1"
            } else if self.reaction?.the2 != nil {
                return "2"
            } else if self.reaction?.the3 != nil {
                return "3"
            } else if self.reaction?.the4 != nil {
                return "4"
            } else if self.reaction?.the5 != nil {
                return "5"
            } else if self.reaction?.the6 != nil {
                return "6"
            } else {
                return ""
            }
        }
    }
    
    func save() {
        self.setValue(message_id, forKey: #keyPath(Messages.message_id))
        self.setValue(from_id, forKey: #keyPath(Messages.from_id))
        self.setValue(group_id, forKey: #keyPath(Messages.group_id))
        self.setValue(page_id, forKey: #keyPath(Messages.page_id))
        self.setValue(to_id, forKey: #keyPath(Messages.to_id))
        self.setValue(broadcast_id, forKey: #keyPath(Messages.broadcast_id))
        self.setValue(text, forKey: #keyPath(Messages.text))
        self.setValue(media, forKey: #keyPath(Messages.media))
        self.setValue(media_file_name, forKey: #keyPath(Messages.media_file_name))
        self.setValue(time, forKey: #keyPath(Messages.time))
        self.setValue(seen, forKey: #keyPath(Messages.seen))
        self.setValue(deleted_one, forKey: #keyPath(Messages.deleted_one))
        self.setValue(deleted_two, forKey: #keyPath(Messages.deleted_two))
        self.setValue(product_id, forKey: #keyPath(Messages.product_id))
        self.setValue(lat, forKey: #keyPath(Messages.lat))
        self.setValue(lng, forKey: #keyPath(Messages.lng))
        self.setValue(reply_id, forKey: #keyPath(Messages.reply_id))
        self.setValue(story_id, forKey: #keyPath(Messages.story_id))
        self.setValue(pin, forKey: #keyPath(Messages.pin))
        self.setValue(fav, forKey: #keyPath(Messages.fav))
        self.setValue(time_text, forKey: #keyPath(Messages.time_text))
        self.setValue(position, forKey: #keyPath(Messages.position))
        self.setValue(type, forKey: #keyPath(Messages.type))
        self.setValue(file_size, forKey: #keyPath(Messages.file_size))
        self.setValue(stickers, forKey: #keyPath(Messages.stickers))
        self.setValue(reply, forKey: #keyPath(Messages.reply))
        self.setValue(chat_color, forKey: #keyPath(Messages.chat_color))
        self.setValue(hash_id, forKey: #keyPath(Messages.hash_id))
        self.setValue(is_favourite, forKey: #keyPath(Messages.is_favourite))
        self.setValue(created_at, forKey: #keyPath(Messages.created_at))
        self.setValue(chat_id, forKey: #keyPath(Messages.chat_id))
        self.setValue(date_time, forKey: #keyPath(Messages.date_time))
        self.setValue(reaction, forKey: #keyPath(Messages.reaction))
        self.setValue(user_data, forKey: #keyPath(Messages.user_data))
        do {
            try self.managedObjectContext!.save()
        } catch let err {
            print("ERROR \(err.localizedDescription)")
        }
    }
    
    func setMessageModelToFields(_ message: MessageModel) {
        self.message_id = message.id
        self.from_id = message.from_id
        self.group_id = message.group_id
        self.page_id = message.page_id
        self.to_id = message.to_id
        self.broadcast_id = message.broadcast_id
        self.text = message.text
        self.media = message.media
        self.media_file_name = message.mediaFileName
        self.time = message.time
        self.seen = message.seen
        self.deleted_one = message.deleted_one
        self.deleted_two = message.deleted_two
        self.product_id = message.product_id
        self.lat = message.lat
        self.lng = message.lng
        self.reply_id = message.reply_id
        self.story_id = message.story_id
        self.pin = message.pin
        self.fav = message.fav
        self.time_text = message.time_text
        self.position = message.position
        self.type = message.type
        self.stickers = message.stickers
        if let userData = message.user_data {
            if let user = Users.getUserByID(userData.user_id ?? "") {
                user.updateUser(user: userData)
                self.user_data = user
            }
        }
        if let replyMessage = message.reply?.message {
            if let message = Messages.getMessageByID(replyMessage.id ?? "") {
                message.updateMessage(message: replyMessage)
                self.reply = message
            }
        }
        if let double = Double(message.time ?? "") {
            self.date_time = Date(timeIntervalSince1970: double)
            self.my_time = Int64(double)
        }
        self.file_size = message.file_size?.stringValue
        if let reaction = message.reaction {
            self.reaction = Reactions(id: message.id ?? "", reaction: reaction)
        }
        self.forward = message.forward
        if let story = message.story?.story {
            self.story = Story(story: story)
        }
    }
    
    func updateMessage(message: MessageModel) {
        self.message_id = message.id
        self.from_id = message.from_id
        self.group_id = message.group_id
        self.page_id = message.page_id
        self.to_id = message.to_id
        self.broadcast_id = message.broadcast_id
        self.text = message.text
        self.media = message.media
        self.media_file_name = message.mediaFileName
        self.time = message.time
        self.seen = message.seen
        self.deleted_one = message.deleted_one
        self.deleted_two = message.deleted_two
        self.product_id = message.product_id
        self.lat = message.lat
        self.lng = message.lng
        self.reply_id = message.reply_id
        self.story_id = message.story_id
        self.pin = message.pin
        self.fav = message.fav
        self.time_text = message.time_text
        self.position = message.position
        self.type = message.type
        self.stickers = message.stickers
        if let userData = message.user_data {
            if let user = Users.getUserByID(userData.user_id ?? "") {
                user.updateUser(user: userData)
                self.user_data = user
            }
        }
        if let replyMessage = message.reply?.message {
            if let message = Messages.getMessageByID(replyMessage.id ?? "") {
                message.updateMessage(message: replyMessage)
                self.reply = message
            }
        }
        if let double = Double(message.time ?? "") {
            self.date_time = Date(timeIntervalSince1970: double)
            self.my_time = Int64(double)
        }
        self.file_size = message.file_size?.stringValue
        self.reaction = Reactions(id: message.id ?? "", reaction: message.reaction)
        self.forward = message.forward
        if let story = message.story?.story {
            self.story = Story(story: story)
        }
        self.save()
    }
    
    func getMessageByReplyID() -> Messages? {
        guard !self._reply_id.isEmpty && self._reply_id != "0" else { return nil }
        let predicate = NSPredicate(format: "%K == %@", #keyPath(Messages.message_id), self._reply_id)
        return Self.fetcher.fetchResults(limit: 1, predicate: predicate).first
    }
    
    func getMessageByHashID() -> Messages? {
        guard !self._hash_id.isEmpty && self._hash_id != "0" else { return nil }
        let predicate = NSPredicate(format: "%K == %@", #keyPath(Messages.hash_id), self._hash_id)
        return Self.fetcher.fetchResults(limit: 1, predicate: predicate).first
    }
    
}

extension Messages {
    
    @discardableResult
    static func saveMessages(chatID: String, _ messages: [MessageModel]) -> [Messages] {
        var msgs = [Messages]()
        
        for message in messages {
            let localMessage = Messages(chat_id: chatID, message: message)
            guard !isMessageExists(localMessage) else { continue }
            localMessage.save()
            msgs.append(localMessage)
        }
        
        return msgs.sorted(by: { $0.my_time < $1.my_time })
    }
    
    static func isMessageExists(_ message: Messages) -> Bool {
        let predicate = NSPredicate(format: "%K == %@", #keyPath(Messages.message_id), message._message_id)
        let result = fetcher.fetchResults(limit: 1, predicate: predicate)
        return !result.isEmpty
    }
    
    static func getFavouriteMessage() -> [Messages] {
        let predicate = NSPredicate(format: "%K == %@", #keyPath(Messages.is_favourite), true)
        return fetcher.fetchResults(predicate: predicate)
    }
    
    static func getMessageByHashID(_ id: String) -> Messages? {
        let predicate = NSPredicate(format: "%K == %@", #keyPath(Messages.hash_id), id)
        return fetcher.fetchResults(limit: 1, predicate: predicate).first
    }
    
    static func getMessageByID(_ id: String) -> Messages? {
        let predicate = NSPredicate(format: "%K == %@", #keyPath(Messages.message_id), id)
        return fetcher.fetchResults(limit: 1, predicate: predicate).first
    }
    
    static func getMessagesByChatID(_ id: String, limit: Int = 50) -> [Messages] {
        let predicate = NSPredicate(format: "%K == %@", #keyPath(Messages.chat_id), id)
        let sortSortDescriptor = NSSortDescriptor(key: #keyPath(Messages.date_time), ascending: true)
        return fetcher.fetchResults(limit: limit, predicate: predicate, sortDescriptors: [sortSortDescriptor])
    }
    
    static func getMessagesByGroupID(_ id: String, limit: Int = 50) -> [Messages] {
        let predicate = NSPredicate(format: "%K == %@", #keyPath(Messages.group_id), id)
        let sortSortDescriptor = NSSortDescriptor(key: #keyPath(Messages.date_time), ascending: true)
        return fetcher.fetchResults(limit: limit, predicate: predicate, sortDescriptors: [sortSortDescriptor])
    }
    
    static func getMessagesByBroadcastID(_ id: String, limit: Int = 50) -> [Messages] {
        let predicate = NSPredicate(format: "%K == %@", #keyPath(Messages.broadcast_id), id)
        let sortSortDescriptor = NSSortDescriptor(key: #keyPath(Messages.date_time), ascending: true)
        return fetcher.fetchResults(limit: limit, predicate: predicate, sortDescriptors: [sortSortDescriptor])
    }
    
    static func getMaxID() -> Int32 {
        let sortDescriptor = NSSortDescriptor(key: #keyPath(Chats.my_id), ascending: false)
        let results = fetcher.fetchResults(limit: 1, sortDescriptors: [sortDescriptor])
        return results.first?.my_id ?? 0
    }
}

extension Date: CVarArg {
    
}
