import Foundation

struct ProfileDataPayload: Decodable {
    let userId: UUID
    let login: String
    let fullName: String?
    let bio: String?
    let avatars: Avatars?
    let balances: [WalletBalancePayload]
    let createdAt: Date?
    let isVerified: Bool
    let stories: [JSONValue]
    let profilePermissions: ProfilePermissionsPayload

    private enum CodingKeys: String, CodingKey {
        case userId
        case login
        case fullName
        case bio
        case avatars
        case balances
        case createdAt
        case isVerified
        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.avatars = try container.decodeIfPresent(Avatars.self, forKey: .avatars)
        self.balances = try container.decodeIfPresent([WalletBalancePayload].self, forKey: .balances) ?? []
        self.createdAt = try container.decodeIfPresent(Date.self, forKey: .createdAt)
        self.isVerified = try container.decode(Bool.self, forKey: .isVerified)
        self.stories = try container.decodeIfPresent([JSONValue].self, forKey: .stories) ?? []
        self.profilePermissions = try container.decode(ProfilePermissionsPayload.self, forKey: .profilePermissions)
    }
}

//struct AvatarInfo: Decodable {
//    let fileId: String
//    let mime: String?
//    let size: Int?
//    let width: Int?
//    let height: Int?
//    let createdAt: Date?
//}
//
//struct Avatars: Decodable {
//    let current: AvatarInfo?
//}

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<CodingKeys>, 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)
        if let seconds = maxMessageAutoDeleteSeconds {
            try container.encode(seconds, forKey: .maxMessageAutoDeleteSeconds)
        } else {
            try container.encodeNil(forKey: .maxMessageAutoDeleteSeconds)
        }

        if let days = autoDeleteAfterDays {
            try container.encode(days, forKey: .autoDeleteAfterDays)
        } else {
            try container.encodeNil(forKey: .autoDeleteAfterDays)
        }
    }
}

extension ProfilePermissionsRequestPayload {
    init(payload: ProfilePermissionsPayload) {
        self.init(
            isSearchable: payload.isSearchable,
            allowMessageForwarding: payload.allowMessageForwarding,
            allowMessagesFromNonContacts: payload.allowMessagesFromNonContacts,
            showProfilePhotoToNonContacts: payload.showProfilePhotoToNonContacts,
            lastSeenVisibility: payload.lastSeenVisibility,
            showBioToNonContacts: payload.showBioToNonContacts,
            showStoriesToNonContacts: payload.showStoriesToNonContacts,
            allowServerChats: payload.allowServerChats,
            publicInvitePermission: payload.publicInvitePermission,
            groupInvitePermission: payload.groupInvitePermission,
            callPermission: payload.callPermission,
            forceAutoDeleteMessagesInPrivate: payload.forceAutoDeleteMessagesInPrivate,
            maxMessageAutoDeleteSeconds: payload.maxMessageAutoDeleteSeconds,
            autoDeleteAfterDays: payload.autoDeleteAfterDays
        )
    }
}

struct ProfileUpdateRequestPayload: Encodable {
    let fullName: String?
    let bio: String?
    let profilePermissions: ProfilePermissionsRequestPayload

    init(fullName: String? = nil, bio: String? = nil, profilePermissions: ProfilePermissionsRequestPayload) {
        self.fullName = fullName
        self.bio = bio
        self.profilePermissions = profilePermissions
    }
}

struct UploadAvatarPayload: Decodable {
    let fileId: String
}
