import Foundation struct ProfileDataPayload: Decodable { let userId: UUID let login: String let fullName: String? let bio: String? let balances: [WalletBalancePayload] let createdAt: Date? let stories: [JSONValue] let profilePermissions: ProfilePermissionsPayload private enum CodingKeys: String, CodingKey { case userId case login case fullName case bio case balances case createdAt case stories case profilePermissions } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) self.userId = try container.decode(UUID.self, forKey: .userId) self.login = try container.decode(String.self, forKey: .login) self.fullName = try container.decodeIfPresent(String.self, forKey: .fullName) self.bio = try container.decodeIfPresent(String.self, forKey: .bio) self.balances = try container.decodeIfPresent([WalletBalancePayload].self, forKey: .balances) ?? [] self.createdAt = try container.decodeIfPresent(Date.self, forKey: .createdAt) self.stories = try container.decodeIfPresent([JSONValue].self, forKey: .stories) ?? [] self.profilePermissions = try container.decode(ProfilePermissionsPayload.self, forKey: .profilePermissions) } } struct WalletBalancePayload: Decodable { let currency: String let balance: Decimal let displayBalance: Double? private enum CodingKeys: String, CodingKey { case currency case balance case displayBalance } init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) self.currency = try container.decode(String.self, forKey: .currency) self.balance = try Self.decodeDecimal(from: container, forKey: .balance) if let doubleValue = try? container.decode(Double.self, forKey: .displayBalance) { self.displayBalance = doubleValue } else if let stringValue = try? container.decode(String.self, forKey: .displayBalance), let doubleValue = Double(stringValue) { self.displayBalance = doubleValue } else { self.displayBalance = nil } } private static func decodeDecimal(from container: KeyedDecodingContainer, forKey key: CodingKeys) throws -> Decimal { if let decimalValue = try? container.decode(Decimal.self, forKey: key) { return decimalValue } if let stringValue = try? container.decode(String.self, forKey: key), let decimal = Decimal(string: stringValue) { return decimal } if let doubleValue = try? container.decode(Double.self, forKey: key) { return Decimal(doubleValue) } throw DecodingError.dataCorruptedError( forKey: key, in: container, debugDescription: "Unable to decode decimal value for key \(key)" ) } } struct ProfilePermissionsPayload: Decodable { let isSearchable: Bool let allowMessageForwarding: Bool let allowMessagesFromNonContacts: Bool let showProfilePhotoToNonContacts: Bool let lastSeenVisibility: Int let showBioToNonContacts: Bool let showStoriesToNonContacts: Bool let allowServerChats: Bool let publicInvitePermission: Int let groupInvitePermission: Int let callPermission: Int let forceAutoDeleteMessagesInPrivate: Bool let maxMessageAutoDeleteSeconds: Int? let autoDeleteAfterDays: Int? } struct ProfilePermissionsRequestPayload: Encodable { let isSearchable: Bool let allowMessageForwarding: Bool let allowMessagesFromNonContacts: Bool let showProfilePhotoToNonContacts: Bool let lastSeenVisibility: Int let showBioToNonContacts: Bool let showStoriesToNonContacts: Bool let allowServerChats: Bool let publicInvitePermission: Int let groupInvitePermission: Int let callPermission: Int let forceAutoDeleteMessagesInPrivate: Bool let maxMessageAutoDeleteSeconds: Int? let autoDeleteAfterDays: Int? enum CodingKeys: String, CodingKey { case isSearchable = "is_searchable" case allowMessageForwarding = "allow_message_forwarding" case allowMessagesFromNonContacts = "allow_messages_from_non_contacts" case showProfilePhotoToNonContacts = "show_profile_photo_to_non_contacts" case lastSeenVisibility = "last_seen_visibility" case showBioToNonContacts = "show_bio_to_non_contacts" case showStoriesToNonContacts = "show_stories_to_non_contacts" case allowServerChats = "allow_server_chats" case publicInvitePermission = "public_invite_permission" case groupInvitePermission = "group_invite_permission" case callPermission = "call_permission" case forceAutoDeleteMessagesInPrivate = "force_auto_delete_messages_in_private" case maxMessageAutoDeleteSeconds = "max_message_auto_delete_seconds" case autoDeleteAfterDays = "auto_delete_after_days" } func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(isSearchable, forKey: .isSearchable) try container.encode(allowMessageForwarding, forKey: .allowMessageForwarding) try container.encode(allowMessagesFromNonContacts, forKey: .allowMessagesFromNonContacts) try container.encode(showProfilePhotoToNonContacts, forKey: .showProfilePhotoToNonContacts) try container.encode(lastSeenVisibility, forKey: .lastSeenVisibility) try container.encode(showBioToNonContacts, forKey: .showBioToNonContacts) try container.encode(showStoriesToNonContacts, forKey: .showStoriesToNonContacts) try container.encode(allowServerChats, forKey: .allowServerChats) try container.encode(publicInvitePermission, forKey: .publicInvitePermission) try container.encode(groupInvitePermission, forKey: .groupInvitePermission) try container.encode(callPermission, forKey: .callPermission) try container.encode(forceAutoDeleteMessagesInPrivate, forKey: .forceAutoDeleteMessagesInPrivate) try container.encodeIfPresent(maxMessageAutoDeleteSeconds, forKey: .maxMessageAutoDeleteSeconds) try container.encodeIfPresent(autoDeleteAfterDays, forKey: .autoDeleteAfterDays) } } struct ProfileUpdateRequestPayload: Encodable { let profilePermissions: ProfilePermissionsRequestPayload }