import Foundation

class MessageModel : Codable {
	var id : String?
	var from_id : String?
	var group_id : String?
	var page_id : String?
	var to_id : String?
	var text : String?
	var media : String?
	var mediaFileName : String?
	var mediaFileNames : String?
	var time : String?
	var seen : String?
	var deleted_one : String?
	var deleted_two : String?
	var sent_push : String?
	var notification_id : String?
	var type_two : String?
	var stickers : String?
	var product_id : String?
	var lat : String?
	var lng : String?
	var reply_id : String?
	var story_id : String?
	var broadcast_id : String?
	var forward : String?
	var listening : String?
    var remove_at : String?
	var messageUser : UserData?
    var user_data : UserData?
	var or_text : String?
	var onwer : Int?
	var reaction : ReactionModel?
	var pin : String?
	var fav : String?
    var reply : ReplyUnion?
    var chat_data : Chat_data?
    var story : StoryUnion?
	var time_text : String?
	var position : String?
	var type : String?
	var product : String?
	var file_size : FileSize?
    var orginal_text : String?
    var message_hash_id : String?
    
	enum CodingKeys: String, CodingKey {
		case id = "id"
		case from_id = "from_id"
		case group_id = "group_id"
		case page_id = "page_id"
		case to_id = "to_id"
		case text = "text"
		case media = "media"
		case mediaFileName = "mediaFileName"
		case mediaFileNames = "mediaFileNames"
		case time = "time"
		case seen = "seen"
		case deleted_one = "deleted_one"
		case deleted_two = "deleted_two"
		case sent_push = "sent_push"
		case notification_id = "notification_id"
		case type_two = "type_two"
		case stickers = "stickers"
		case product_id = "product_id"
		case lat = "lat"
		case lng = "lng"
		case reply_id = "reply_id"
		case story_id = "story_id"
		case broadcast_id = "broadcast_id"
		case forward = "forward"
		case listening = "listening"
        case remove_at = "remove_at"
		case messageUser = "messageUser"
        case user_data = "user_data"
		case or_text = "or_text"
		case onwer = "onwer"
		case reaction = "reaction"
		case pin = "pin"
		case fav = "fav"
        case reply = "reply"
        case chat_data = "chat_data"
        case story = "story"
		case time_text = "time_text"
		case position = "position"
		case type = "type"
		case product = "product"
		case file_size = "file_size"
        case orginal_text = "orginal_text"
        case message_hash_id = "message_hash_id"
	}
    
    init(id : String?, from_id : String?, to_id : String?, media : String?, seen : String?, time : String?, position : String?, time_text : String?, type: String, message_hash_id : String?, user_data : UserData?, text : String?, messageUser : UserData?) {
        self.id = id
        self.from_id = from_id
        self.to_id = to_id
        self.media = media
        self.seen = seen
        self.time = time
        self.position = position
        self.time_text = time_text
        self.type = type
        self.message_hash_id = message_hash_id
        self.user_data = user_data
        self.text = text
        self.messageUser = messageUser
    }

	/*init(from decoder: Decoder) throws {
		let values = try decoder.container(keyedBy: CodingKeys.self)
		id = try values.decodeIfPresent(String.self, forKey: .id)
		from_id = try values.decodeIfPresent(String.self, forKey: .from_id)
		group_id = try values.decodeIfPresent(String.self, forKey: .group_id)
		page_id = try values.decodeIfPresent(String.self, forKey: .page_id)
		to_id = try values.decodeIfPresent(String.self, forKey: .to_id)
		text = try values.decodeIfPresent(String.self, forKey: .text)
		media = try values.decodeIfPresent(String.self, forKey: .media)
		mediaFileName = try values.decodeIfPresent(String.self, forKey: .mediaFileName)
		mediaFileNames = try values.decodeIfPresent(String.self, forKey: .mediaFileNames)
		time = try values.decodeIfPresent(String.self, forKey: .time)
		seen = try values.decodeIfPresent(String.self, forKey: .seen)
		deleted_one = try values.decodeIfPresent(String.self, forKey: .deleted_one)
		deleted_two = try values.decodeIfPresent(String.self, forKey: .deleted_two)
		sent_push = try values.decodeIfPresent(String.self, forKey: .sent_push)
		notification_id = try values.decodeIfPresent(String.self, forKey: .notification_id)
		type_two = try values.decodeIfPresent(String.self, forKey: .type_two)
		stickers = try values.decodeIfPresent(String.self, forKey: .stickers)
		product_id = try values.decodeIfPresent(String.self, forKey: .product_id)
		lat = try values.decodeIfPresent(String.self, forKey: .lat)
		lng = try values.decodeIfPresent(String.self, forKey: .lng)
		reply_id = try values.decodeIfPresent(String.self, forKey: .reply_id)
		story_id = try values.decodeIfPresent(String.self, forKey: .story_id)
		broadcast_id = try values.decodeIfPresent(String.self, forKey: .broadcast_id)
		forward = try values.decodeIfPresent(String.self, forKey: .forward)
		listening = try values.decodeIfPresent(String.self, forKey: .listening)
        remove_at = try values.decodeIfPresent(String.self, forKey: .remove_at)
		messageUser = try values.decodeIfPresent(UserData.self, forKey: .messageUser)
        user_data = try values.decodeIfPresent(UserData.self, forKey: .user_data)
		or_text = try values.decodeIfPresent(String.self, forKey: .or_text)
		onwer = try values.decodeIfPresent(Int.self, forKey: .onwer)
		reaction = try values.decodeIfPresent(ReactionModel.self, forKey: .reaction)
		pin = try values.decodeIfPresent(String.self, forKey: .pin)
		fav = try values.decodeIfPresent(String.self, forKey: .fav)
        reply = try values.decodeIfPresent(ReplyUnion.self, forKey: .reply)
        chat_data = try values.decodeIfPresent(Chat_data.self, forKey: .chat_data)
        story = try values.decodeIfPresent(StoryUnion.self, forKey: .story)
		time_text = try values.decodeIfPresent(String.self, forKey: .time_text)
		position = try values.decodeIfPresent(String.self, forKey: .position)
		type = try values.decodeIfPresent(String.self, forKey: .type)
		product = try values.decodeIfPresent(String.self, forKey: .product)
		file_size = try values.decodeIfPresent(FileSize.self, forKey: .file_size)
        orginal_text = try values.decodeIfPresent(String.self, forKey: .orginal_text)
        message_hash_id = try values.decodeIfPresent(String.self, forKey: .message_hash_id)
	}*/

    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 ""
            }
        }
    }
    
}

enum ReplyUnion: Codable {
    
    case anythingArray([JSONAny])
    case reply(MessageModel)
    
    var message: MessageModel? {
        guard case let .reply(value) = self else { return nil }
        return value
    }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        if let x = try? container.decode([JSONAny].self) {
            self = .anythingArray(x)
            return
        }
        if let x = try? container.decode(MessageModel.self) {
            self = .reply(x)
            return
        }
        throw DecodingError.typeMismatch(ReplyUnion.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for ReplyUnion"))
    }
    
    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        switch self {
        case .anythingArray(let x):
            try container.encode(x)
        case .reply(let x):
            try container.encode(x)
        }
    }
    
}

enum StoryUnion: Codable {
    case anythingArray([JSONAny])
    case story(UserDataStory)
    
    var story: UserDataStory? {
        guard case let .story(value) = self else { return nil }
        return value
    }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        if let x = try? container.decode([JSONAny].self) {
            self = .anythingArray(x)
            return
        }
        if let x = try? container.decode(UserDataStory.self) {
            self = .story(x)
            return
        }
        throw DecodingError.typeMismatch(StoryUnion.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for StoryUnion"))
    }
    
    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        switch self {
        case .anythingArray(let x):
            try container.encode(x)
        case .story(let x):
            try container.encode(x)
        }
    }
    
}
