import Foundation struct PrivateChatListData: Decodable { let items: [PrivateChatListItem] let hasMore: Bool } struct PrivateChatHistoryData: Decodable { let items: [MessageItem] let hasMore: Bool } struct PrivateChatListItem: Decodable, Identifiable { enum ChatType: String, Decodable { case `self` case privateChat = "private" case unknown init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() let rawValue = try container.decode(String.self) self = ChatType(rawValue: rawValue) ?? .unknown } } let chatId: String let chatType: ChatType let chatData: ChatProfile? let lastMessage: MessageItem? let createdAt: Date? let unreadCount: Int var id: String { chatId } } struct MessageItem: Decodable, Identifiable { let messageId: String let messageType: String let chatId: String let senderId: String let senderData: ChatProfile? let content: String? let mediaLink: String? let isViewed: Bool? let createdAt: Date? let updatedAt: Date? let forwardMetadata: ForwardMetadata? var id: String { messageId } private enum CodingKeys: String, CodingKey { case messageId case messageType case chatId case senderId case senderData case content case mediaLink case isViewed case createdAt case updatedAt case forwardMetadata } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) self.messageId = try container.decodeFlexibleString(forKey: .messageId) self.messageType = try container.decodeFlexibleStringOrArray(forKey: .messageType) self.chatId = try container.decodeFlexibleString(forKey: .chatId) self.senderId = try container.decodeFlexibleString(forKey: .senderId) self.senderData = try container.decodeIfPresent(ChatProfile.self, forKey: .senderData) self.content = try container.decodeIfPresent(String.self, forKey: .content) self.mediaLink = try container.decodeIfPresent(String.self, forKey: .mediaLink) self.isViewed = try container.decodeIfPresent(Bool.self, forKey: .isViewed) self.createdAt = try container.decodeIfPresent(Date.self, forKey: .createdAt) self.updatedAt = try container.decodeIfPresent(Date.self, forKey: .updatedAt) self.forwardMetadata = try container.decodeIfPresent(ForwardMetadata.self, forKey: .forwardMetadata) } } struct ForwardMetadata: Decodable { let forwardType: String? let forwardSenderId: String? let forwardMessageId: String? let forwardChatData: ChatProfile? private enum CodingKeys: String, CodingKey { case forwardType case forwardSenderId case forwardMessageId case forwardChatData } } struct ChatProfile: Decodable { let userId: String let login: String? let fullName: String? let customName: String? let bio: String? let lastSeen: Int? let createdAt: Date? let stories: [JSONValue] let permissions: ChatPermissions? let profilePermissions: ChatProfilePermissions? let relationship: RelationshipStatus? private enum CodingKeys: String, CodingKey { case userId case login case fullName case customName case bio case lastSeen case createdAt case stories case permissions case profilePermissions case relationship } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) self.userId = try container.decodeFlexibleString(forKey: .userId) self.login = try container.decodeIfPresent(String.self, forKey: .login) self.fullName = try container.decodeIfPresent(String.self, forKey: .fullName) self.customName = try container.decodeIfPresent(String.self, forKey: .customName) self.bio = try container.decodeIfPresent(String.self, forKey: .bio) self.lastSeen = try container.decodeIfPresent(Int.self, forKey: .lastSeen) self.createdAt = try container.decodeIfPresent(Date.self, forKey: .createdAt) self.stories = try container.decodeIfPresent([JSONValue].self, forKey: .stories) ?? [] self.permissions = try container.decodeIfPresent(ChatPermissions.self, forKey: .permissions) self.profilePermissions = try container.decodeIfPresent(ChatProfilePermissions.self, forKey: .profilePermissions) self.relationship = try container.decodeIfPresent(RelationshipStatus.self, forKey: .relationship) } } struct ChatPermissions: Decodable { let youCanSendMessage: Bool let youCanPublicInvitePermission: Bool let youCanGroupInvitePermission: Bool let youCanCallPermission: Bool } struct ChatProfilePermissions: Decodable { let isSearchable: Bool? let allowMessageForwarding: Bool let allowMessagesFromNonContacts: Bool let allowServerChats: Bool let forceAutoDeleteMessagesInPrivate: Bool let maxMessageAutoDeleteSeconds: Int? } struct RelationshipStatus: Decodable { let isCurrentUserInContactsOfTarget: Bool let isTargetUserBlockedByCurrentUser: Bool let isCurrentUserInBlacklistOfTarget: Bool } enum JSONValue: Decodable { case string(String) case int(Int) case double(Double) case bool(Bool) case array([JSONValue]) case object([String: JSONValue]) case null init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() if container.decodeNil() { self = .null return } if let value = try? container.decode(Bool.self) { self = .bool(value) return } if let value = try? container.decode(Int.self) { self = .int(value) return } if let value = try? container.decode(Double.self) { self = .double(value) return } if let value = try? container.decode(String.self) { self = .string(value) return } if let value = try? container.decode([JSONValue].self) { self = .array(value) return } if let value = try? container.decode([String: JSONValue].self) { self = .object(value) return } throw DecodingError.dataCorruptedError(in: container, debugDescription: "Не удалось декодировать значение JSONValue") } } private extension KeyedDecodingContainer { func decodeFlexibleString(forKey key: Key) throws -> String { if let string = try? decode(String.self, forKey: key) { return string } if let int = try? decode(Int.self, forKey: key) { return String(int) } if let double = try? decode(Double.self, forKey: key) { return String(double) } throw DecodingError.typeMismatch(String.self, DecodingError.Context(codingPath: codingPath + [key], debugDescription: "Expected to decode String or number for key \(key.stringValue)")) } func decodeFlexibleStringOrArray(forKey key: Key) throws -> String { if let string = try? decode(String.self, forKey: key) { return string } if let stringArray = try? decode([String].self, forKey: key), let first = stringArray.first { return first } if let intArray = try? decode([Int].self, forKey: key), let first = intArray.first { return String(first) } if let doubleArray = try? decode([Double].self, forKey: key), let first = doubleArray.first { return String(first) } throw DecodingError.typeMismatch(String.self, DecodingError.Context(codingPath: codingPath + [key], debugDescription: "Expected to decode String or array for key \(key.stringValue)")) } }