package com.crm.chat.ui.chat

import android.content.Intent
import android.net.Uri
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.crm.chat.data.model.ChatMessage
import com.crm.chat.data.model.ChatMessageFile
import com.crm.chat.databinding.ItemMessageBinding
import kotlinx.coroutines.launch
import java.text.SimpleDateFormat
import java.util.*

class MessageAdapter(
    private val getUserName: (Long) -> String,
    private val chatUsers: List<com.crm.chat.data.model.ChatUserItem>? = null,
    private val onScrollToMessage: ((Long) -> Unit)? = null,
    private val onReplyToMessage: ((ChatMessage) -> Unit)? = null,
    private val onEditMessage: ((ChatMessage) -> Unit)? = null,
    private val onDeleteMessage: ((ChatMessage) -> Unit)? = null,
    private val onAddReaction: ((ChatMessage, String) -> Unit)? = null,
    private val onRemoveReaction: ((ChatMessage, Long) -> Unit)? = null,
    private val onReactionAdded: (() -> Unit)? = null, // New callback for reaction updates
    serverUrl: String? = null,
    token: String? = null,
    apiKey: String? = null,
    private val currentUserId: Long? = null // Optional current user ID parameter
) : ListAdapter<ChatMessage, MessageAdapter.MessageViewHolder>(MessageDiffCallback()) {

    private val dateFormat = SimpleDateFormat("dd.MM.yyyy HH:mm", Locale.getDefault())

    // For file downloads
    private val chatRepository: com.crm.chat.data.repository.ChatRepository? = if (serverUrl != null && token != null && apiKey != null) {
        val apiClient = com.crm.chat.data.api.ApiClient(serverUrl, apiKey, token)
        com.crm.chat.data.repository.ChatRepository(apiClient)
    } else {
        null
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MessageViewHolder {
        val binding = ItemMessageBinding.inflate(
            LayoutInflater.from(parent.context),
            parent,
            false
        )
        return MessageViewHolder(binding, dateFormat, getUserName, chatUsers, onScrollToMessage, onReplyToMessage, chatRepository, onEditMessage, onDeleteMessage, onAddReaction, onRemoveReaction, currentUserId)
    }

    override fun onBindViewHolder(holder: MessageViewHolder, position: Int) {
        holder.bind(getItem(position))
    }

    class MessageViewHolder(
        private val binding: ItemMessageBinding,
        private val dateFormat: SimpleDateFormat,
        private val getUserName: (Long) -> String,
        private val chatUsers: List<com.crm.chat.data.model.ChatUserItem>?,
        private val onScrollToMessage: ((Long) -> Unit)?,
        private val onReplyToMessage: ((ChatMessage) -> Unit)?,
        private val chatRepository: com.crm.chat.data.repository.ChatRepository?,
        private val onEditMessage: ((ChatMessage) -> Unit)?,
        private val onDeleteMessage: ((ChatMessage) -> Unit)?,
        private val onAddReaction: ((ChatMessage, String) -> Unit)?,
        private val onRemoveReaction: ((ChatMessage, Long) -> Unit)?,
        private val currentUserId: Long? // Add currentUserId parameter
    ) : RecyclerView.ViewHolder(binding.root) {

    // Cache for downloaded images
    private val imageCache = mutableMapOf<String, java.io.File>()

    private fun loadImageToCache(imageUrl: String, fileName: String, onSuccess: (java.io.File) -> Unit, onFailure: (() -> Unit)? = null) {
        // Check if already cached
        imageCache[imageUrl]?.let { cachedFile ->
            if (cachedFile.exists()) {
                onSuccess(cachedFile)
                return
            } else {
                imageCache.remove(imageUrl)
            }
        }

        val repository = chatRepository ?: run {
            onFailure?.invoke()
            return
        }

        kotlinx.coroutines.GlobalScope.launch(kotlinx.coroutines.Dispatchers.Main) {
            try {
                val result = repository.downloadFile(imageUrl, fileName, binding.root.context)
                result.fold(
                    onSuccess = { cacheFile ->
                        imageCache[imageUrl] = cacheFile
                        onSuccess(cacheFile)
                    },
                    onFailure = { exception ->
                        android.util.Log.w("MessageAdapter", "Failed to download image to cache: ${exception.message}")
                        onFailure?.invoke()
                    }
                )
            } catch (e: Exception) {
                android.util.Log.e("MessageAdapter", "Error downloading image to cache", e)
                onFailure?.invoke()
            }
        }
    }

        // Utility function to check if a file is an image
        private fun isImageFile(file: ChatMessageFile): Boolean {
            val fileName = file.fileName?.lowercase() ?: ""
            val fileType = file.fileType?.lowercase() ?: ""

            // Check by file extension
            val imageExtensions = listOf("jpg", "jpeg", "png", "gif", "bmp", "webp")
            val extension = fileName.substringAfterLast(".", "")

            // Check by MIME type
            val imageMimeTypes = listOf("image/jpeg", "image/png", "image/gif", "image/bmp", "image/webp")

            return imageExtensions.contains(extension) || imageMimeTypes.contains(fileType)
        }

        fun bind(message: ChatMessage) {
            // Resolve chatUserId to actual userId
            val chatUserItem = chatUsers?.find { it.id == message.chatUserId }
            val actualUserId = chatUserItem?.userId ?: message.chatUserId

            // Get current user ID from constructor parameter or use default
            val currentUserId = currentUserId ?: 12033923L
            val isSentMessage = actualUserId == currentUserId
            val timestamp = formatTimestamp(message.createdAt)

            // Handle reply indicator - different for sent vs received messages
            if (message.replyTo != null) {
                // Resolve original sender
                val originalChatUserItem = chatUsers?.find { it.id == message.replyTo.chatUserId }
                val originalUserId = originalChatUserItem?.userId ?: message.replyTo.chatUserId
                // If original sender is current user, show "Я" instead of their name
                val originalSenderName = if (originalUserId == currentUserId) "Я" else getUserName(originalUserId)

                if (isSentMessage) {
                    // Show reply indicator inside sent message bubble
                    binding.sentReplyIndicator.visibility = android.view.View.VISIBLE
                    binding.sentReplySenderText.text = originalSenderName
                    binding.sentReplyMessageText.text = message.replyTo.text

                    // Make reply indicator clickable to scroll to original message
                    binding.sentReplyIndicator.setOnClickListener {
                        onScrollToMessage?.invoke(message.replyTo.id)
                    }
                } else {
                    // Show reply indicator inside received message bubble
                    binding.receivedReplyIndicator.visibility = android.view.View.VISIBLE
                    binding.receivedReplySenderText.text = originalSenderName
                    binding.receivedReplyMessageText.text = message.replyTo.text

                    // Make reply indicator clickable to scroll to original message
                    binding.receivedReplyIndicator.setOnClickListener {
                        onScrollToMessage?.invoke(message.replyTo.id)
                    }
                }
            } else {
                // Hide both reply indicators
                binding.sentReplyIndicator.visibility = android.view.View.GONE
                binding.receivedReplyIndicator.visibility = android.view.View.GONE
            }

            if (isSentMessage) {
                // Show sent message
                binding.sentMessageCard.visibility = android.view.View.VISIBLE
                binding.receivedMessageCard.visibility = android.view.View.GONE
                binding.senderNameText.visibility = android.view.View.GONE

                // Handle files
                if (!message.files.isNullOrEmpty()) {
                    val file = message.files.first() // Show first file
                    if (isImageFile(file)) {
                        // Show image preview
                        binding.sentImagePreview.visibility = android.view.View.VISIBLE
                        binding.sentFileLayout.visibility = android.view.View.GONE

                        // Load image to cache first, then display
                        val imageUrl = "${chatRepository?.getBaseUrl()}/api/storage/file/${file.fileId}"
                        loadImageToCache(imageUrl, file.fileName ?: "image",
                            onSuccess = { cacheFile ->
                                Glide.with(binding.sentImagePreview.context)
                                    .load(cacheFile)
                                    .override(400, 400) // Limit size for preview
                                    .centerCrop()
                                    .into(binding.sentImagePreview)
                            },
                            onFailure = {
                                // Fallback: try to load directly (might work for some servers)
                                Glide.with(binding.sentImagePreview.context)
                                    .load(imageUrl)
                                    .override(400, 400) // Limit size for preview
                                    .centerCrop()
                                    .into(binding.sentImagePreview)
                            }
                        )

                        // Click listener to open full-size image
                        binding.sentImagePreview.setOnClickListener {
                            openImageViewer(imageUrl, file.fileName ?: "image")
                        }
                    } else {
                        // Show regular file layout
                        binding.sentFileLayout.visibility = android.view.View.VISIBLE
                        binding.sentImagePreview.visibility = android.view.View.GONE

                        binding.sentFileNameText.text = file.fileName ?: "Unknown file"
                        binding.sentFileNameText.setOnClickListener {
                            downloadFile(file.fileId, file.fileName ?: "file")
                        }
                        // Make paperclip clickable too - find the first TextView (paperclip)
                        val sentFileLayout = binding.sentFileLayout
                        if (sentFileLayout is android.widget.LinearLayout && sentFileLayout.childCount > 0) {
                            val paperclipView = sentFileLayout.getChildAt(0) as? android.widget.TextView
                            paperclipView?.setOnClickListener {
                                downloadFile(file.fileId, file.fileName ?: "file")
                            }
                        }
                    }
                } else {
                    binding.sentFileLayout.visibility = android.view.View.GONE
                    binding.sentImagePreview.visibility = android.view.View.GONE
                }

                // Handle text - show below files if files exist, otherwise normal padding
                binding.sentMessageText.text = message.text
                if (!message.files.isNullOrEmpty() && message.text.isNotBlank()) {
                    // Files present and text exists - adjust padding
                    binding.sentMessageText.setPadding(12, 0, 12, 12) // No top padding since files are above
                } else {
                    binding.sentMessageText.setPadding(12, 12, 12, 12) // Normal padding
                }

                // Hide text if no text and no files (shouldn't happen but safety check)
                if (message.text.isBlank() && message.files.isNullOrEmpty()) {
                    binding.sentMessageText.visibility = android.view.View.GONE
                } else {
                    binding.sentMessageText.visibility = android.view.View.VISIBLE
                }

                // Add click listener for replying to sent messages
                binding.sentMessageCard.setOnClickListener {
                    onReplyToMessage?.invoke(message)
                }

                // Add long-press listener for edit/delete actions on sent messages
                binding.sentMessageCard.setOnLongClickListener {
                    showMessageActionsDialog(message)
                    true
                }

                // Show read status if message has been seen by others
                val hasBeenRead = message.statuses?.any { status ->
                    status.status == "seen" && status.chatUserId != message.chatUserId
                } ?: false

                // Include checkmark outside parentheses if read
                val readIndicator = if (hasBeenRead) " ✓" else ""
                binding.timestampText.text = "Я ($timestamp)$readIndicator"
                binding.timestampText.visibility = android.view.View.VISIBLE

                // Display reactions for sent messages
                displayReactions(message, true)
            } else {
                // Show received message
                binding.sentMessageCard.visibility = android.view.View.GONE
                binding.receivedMessageCard.visibility = android.view.View.VISIBLE
                binding.timestampText.visibility = android.view.View.GONE

                val userName = getUserName(actualUserId)

                // Handle files
                if (!message.files.isNullOrEmpty()) {
                    val file = message.files.first() // Show first file
                    if (isImageFile(file)) {
                        // Show image preview
                        binding.receivedImagePreview.visibility = android.view.View.VISIBLE
                        binding.receivedFileLayout.visibility = android.view.View.GONE

                        // Load image to cache first, then display
                        val imageUrl = "${chatRepository?.getBaseUrl()}/api/storage/file/${file.fileId}"
                        loadImageToCache(imageUrl, file.fileName ?: "image",
                            onSuccess = { cacheFile ->
                                Glide.with(binding.receivedImagePreview.context)
                                    .load(cacheFile)
                                    .override(400, 400) // Limit size for preview
                                    .centerCrop()
                                    .into(binding.receivedImagePreview)
                            },
                            onFailure = {
                                // Fallback: try to load directly (might work for some servers)
                                Glide.with(binding.receivedImagePreview.context)
                                    .load(imageUrl)
                                    .override(400, 400) // Limit size for preview
                                    .centerCrop()
                                    .into(binding.receivedImagePreview)
                            }
                        )

                        // Click listener to open full-size image
                        binding.receivedImagePreview.setOnClickListener {
                            openImageViewer(imageUrl, file.fileName ?: "image")
                        }
                    } else {
                        // Show regular file layout
                        binding.receivedFileLayout.visibility = android.view.View.VISIBLE
                        binding.receivedImagePreview.visibility = android.view.View.GONE

                        binding.receivedFileNameText.text = file.fileName ?: "Unknown file"
                        binding.receivedFileNameText.setOnClickListener {
                            downloadFile(file.fileId, file.fileName ?: "file")
                        }
                        // Make paperclip clickable too - find the first TextView (paperclip)
                        val receivedFileLayout = binding.receivedFileLayout
                        if (receivedFileLayout is android.widget.LinearLayout && receivedFileLayout.childCount > 0) {
                            val paperclipView = receivedFileLayout.getChildAt(0) as? android.widget.TextView
                            paperclipView?.setOnClickListener {
                                downloadFile(file.fileId, file.fileName ?: "file")
                            }
                        }
                    }
                } else {
                    binding.receivedFileLayout.visibility = android.view.View.GONE
                    binding.receivedImagePreview.visibility = android.view.View.GONE
                }

                // Handle text - show below files if files exist, otherwise normal padding
                binding.receivedMessageText.text = message.text
                if (!message.files.isNullOrEmpty() && message.text.isNotBlank()) {
                    // Files present and text exists - adjust padding
                    binding.receivedMessageText.setPadding(12, 0, 12, 12) // No top padding since files are above
                } else {
                    binding.receivedMessageText.setPadding(12, 12, 12, 12) // Normal padding
                }

                // Hide text if no text and no files (shouldn't happen but safety check)
                if (message.text.isBlank() && message.files.isNullOrEmpty()) {
                    binding.receivedMessageText.visibility = android.view.View.GONE
                } else {
                    binding.receivedMessageText.visibility = android.view.View.VISIBLE
                }

                println("DEBUG: Message chatUserId=${message.chatUserId} -> userId=${actualUserId} -> name: $userName")
                // Show "Last Name First Name (time)" for received messages
                binding.senderNameText.text = "$userName ($timestamp)"
                binding.senderNameText.visibility = android.view.View.VISIBLE

                // Add click listener for replying to received messages
                binding.receivedMessageCard.setOnClickListener {
                    onReplyToMessage?.invoke(message)
                }

                // Add long-press listener for actions on received messages (including reactions)
                binding.receivedMessageCard.setOnLongClickListener {
                    showMessageActionsDialog(message)
                    true
                }

                // Display reactions for received messages
                displayReactions(message, false)
            }
        }

        private fun downloadFile(fileId: String, fileName: String) {
            val context = binding.root.context
            val repository = chatRepository ?: return

            // Show downloading progress
            android.widget.Toast.makeText(
                context,
                "Скачивание $fileName...",
                android.widget.Toast.LENGTH_SHORT
            ).show()

            // Try the correct endpoint pattern based on HAR file analysis
            // For images: /api/storage/image/{id}/{uuid}
            // For other files: /api/storage/file/{fileId}
            // Since we only have fileId, try both patterns

            // First try: /api/storage/file/{fileId} (current approach)
            val downloadUrl = "${repository.getBaseUrl()}/api/storage/file/$fileId"

            // Log the URL for debugging
            android.util.Log.d("FileDownload", "Download URL: $downloadUrl")
            android.util.Log.d("FileDownload", "File ID: $fileId")

            // Download file to cache first
            kotlinx.coroutines.GlobalScope.launch(kotlinx.coroutines.Dispatchers.Main) {
                try {
                    val result = repository.downloadFile(downloadUrl, fileName, context)
                    result.fold(
                        onSuccess = { cacheFile ->
                            // File downloaded to cache successfully
                            // Now offer to save it to phone storage
                            showSaveFileDialog(cacheFile, fileName)
                        },
                        onFailure = { exception ->
                            // If /api/storage/file/ fails, try alternative endpoint
                            android.util.Log.w("FileDownload", "Primary endpoint failed, trying alternative", exception)

                            // Try alternative: /api/storage/download/{fileId}
                            val altDownloadUrl = "${repository.getBaseUrl()}/api/storage/download/$fileId"
                            android.util.Log.d("FileDownload", "Trying alternative URL: $altDownloadUrl")

                            tryAlternativeDownload(altDownloadUrl, fileName, context)
                        }
                    )
                } catch (e: Exception) {
                    android.widget.Toast.makeText(
                        context,
                        "Ошибка скачивания: ${e.message}",
                        android.widget.Toast.LENGTH_SHORT
                    ).show()
                    android.util.Log.e("FileDownload", "Download error", e)
                }
            }
        }

        private fun tryAlternativeDownload(altDownloadUrl: String, fileName: String, context: android.content.Context) {
            val repository = chatRepository ?: return

            kotlinx.coroutines.GlobalScope.launch(kotlinx.coroutines.Dispatchers.Main) {
                try {
                    val result = repository.downloadFile(altDownloadUrl, fileName, context)
                    result.fold(
                        onSuccess = { cacheFile ->
                            showSaveFileDialog(cacheFile, fileName)
                        },
                        onFailure = { exception ->
                            android.widget.Toast.makeText(
                                context,
                                "Скачивание не удалось: ${exception.message}",
                                android.widget.Toast.LENGTH_SHORT
                            ).show()
                            android.util.Log.e("FileDownload", "Alternative download also failed", exception)
                        }
                    )
                } catch (e: Exception) {
                    android.widget.Toast.makeText(
                        context,
                        "Ошибка скачивания: ${e.message}",
                        android.widget.Toast.LENGTH_SHORT
                    ).show()
                    android.util.Log.e("FileDownload", "Alternative download error", e)
                }
            }
        }

        private fun showSaveFileDialog(cacheFile: java.io.File, fileName: String) {
            val context = binding.root.context
            val activity = context as? android.app.Activity ?: return

            android.app.AlertDialog.Builder(activity)
                .setTitle("Файл загружен")
                .setMessage("Сохранить '$fileName' на телефон?")
                .setPositiveButton("Сохранить") { _, _ ->
                    saveFileToPhone(cacheFile, fileName)
                }
                .setNegativeButton("Отмена", null)
                .show()
        }

        private fun saveFileToPhone(cacheFile: java.io.File, fileName: String) {
            val context = binding.root.context
            val activity = context as? android.app.Activity ?: run {
                android.widget.Toast.makeText(
                    context,
                    "Невозможно сохранить файл: активность недоступна",
                    android.widget.Toast.LENGTH_SHORT
                ).show()
                return
            }

            try {
                if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
                    // Android 10+ (API 29+) - Use MediaStore API
                    if (checkStoragePermission(activity)) {
                        saveFileUsingMediaStore(cacheFile, fileName, context)
                    } else {
                        requestStoragePermission(activity, cacheFile, fileName)
                    }
                } else {
                    // Android 9 and below - Direct file access
                    if (checkStoragePermission(activity)) {
                        saveFileDirectly(cacheFile, fileName, context)
                    } else {
                        requestStoragePermission(activity, cacheFile, fileName)
                    }
                }
            } catch (e: Exception) {
                android.util.Log.e("FileSave", "Failed to save file", e)
                android.widget.Toast.makeText(
                    context,
                    "Не удалось сохранить файл: ${e.message}",
                    android.widget.Toast.LENGTH_SHORT
                ).show()
            }
        }

        @Suppress("DEPRECATION")
        private fun saveFileDirectly(cacheFile: java.io.File, fileName: String, context: android.content.Context) {
            try {
                // Get the Downloads directory
                val downloadsDir = android.os.Environment.getExternalStoragePublicDirectory(android.os.Environment.DIRECTORY_DOWNLOADS)

                // Create destination file
                val destFile = java.io.File(downloadsDir, fileName)

                // Copy file from cache to downloads
                cacheFile.inputStream().use { input ->
                    destFile.outputStream().use { output ->
                        input.copyTo(output)
                    }
                }

                // Notify media scanner
                android.media.MediaScannerConnection.scanFile(
                    context,
                    arrayOf(destFile.absolutePath),
                    null,
                    null
                )

                android.widget.Toast.makeText(
                    context,
                    "Файл сохранен в Загрузки: $fileName",
                    android.widget.Toast.LENGTH_LONG
                ).show()

            } catch (e: Exception) {
                throw e // Re-throw to be handled by caller
            }
        }

        private fun saveFileUsingMediaStore(cacheFile: java.io.File, fileName: String, context: android.content.Context) {
            try {
                val contentResolver = context.contentResolver
                val contentValues = android.content.ContentValues().apply {
                    put(android.provider.MediaStore.MediaColumns.DISPLAY_NAME, fileName)
                    put(android.provider.MediaStore.MediaColumns.MIME_TYPE, getMimeType(fileName))
                    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
                        put(android.provider.MediaStore.MediaColumns.RELATIVE_PATH, android.os.Environment.DIRECTORY_DOWNLOADS)
                    }
                }

                // Use appropriate URI based on API level
                val collectionUri = if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
                    // Android 10+ - Use Downloads collection
                    android.provider.MediaStore.Downloads.EXTERNAL_CONTENT_URI
                } else {
                    // Android 9 and below - Use generic external storage
                    android.provider.MediaStore.Files.getContentUri("external")
                }

                val uri = contentResolver.insert(collectionUri, contentValues)

                if (uri != null) {
                    contentResolver.openOutputStream(uri)?.use { outputStream ->
                        cacheFile.inputStream().use { inputStream ->
                            inputStream.copyTo(outputStream)
                        }
                    }

                    android.widget.Toast.makeText(
                        context,
                        "File saved to Downloads: $fileName",
                        android.widget.Toast.LENGTH_LONG
                    ).show()
                } else {
                    throw Exception("Failed to create file in Downloads")
                }

            } catch (e: Exception) {
                // Fallback: Try to save in app's private Downloads directory
                saveFileToAppPrivateStorage(cacheFile, fileName, context)
            }
        }

        private fun saveFileToAppPrivateStorage(cacheFile: java.io.File, fileName: String, context: android.content.Context) {
            try {
                // Create app-private Downloads directory
                val appDownloadsDir = java.io.File(context.getExternalFilesDir(null), "Downloads")
                if (!appDownloadsDir.exists()) {
                    appDownloadsDir.mkdirs()
                }

                val destFile = java.io.File(appDownloadsDir, fileName)

                // Copy file from cache to app downloads
                cacheFile.inputStream().use { input ->
                    destFile.outputStream().use { output ->
                        input.copyTo(output)
                    }
                }

                android.widget.Toast.makeText(
                    context,
                    "Файл сохранен в хранилище приложения: $fileName",
                    android.widget.Toast.LENGTH_LONG
                ).show()

            } catch (e: Exception) {
                throw Exception("Failed to save file to any location: ${e.message}")
            }
        }

        private fun checkStoragePermission(activity: android.app.Activity): Boolean {
            return if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {
                // Android 11+ (API 30+) - Check MANAGE_EXTERNAL_STORAGE
                android.os.Environment.isExternalStorageManager()
            } else {
                // Android 6-10 - Check WRITE_EXTERNAL_STORAGE
                androidx.core.content.ContextCompat.checkSelfPermission(
                    activity,
                    android.Manifest.permission.WRITE_EXTERNAL_STORAGE
                ) == android.content.pm.PackageManager.PERMISSION_GRANTED
            }
        }

        private fun requestStoragePermission(activity: android.app.Activity, cacheFile: java.io.File, fileName: String) {
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {
                // Android 11+ - Request MANAGE_EXTERNAL_STORAGE via settings
                android.widget.Toast.makeText(
                    activity,
                    "Пожалуйста, предоставьте разрешение на хранение в Настройках > Приложения > ${activity.packageManager.getApplicationLabel(activity.applicationInfo)} > Хранилище",
                    android.widget.Toast.LENGTH_LONG
                ).show()

                // Try to open settings
                try {
                    val intent = android.content.Intent(android.provider.Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION).apply {
                        data = android.net.Uri.parse("package:${activity.packageName}")
                    }
                    activity.startActivity(intent)
                } catch (e: Exception) {
                    android.util.Log.e("Permission", "Failed to open settings", e)
                }

                // Fallback to app storage
                saveFileToAppPrivateStorage(cacheFile, fileName, activity)
            } else {
                // Android 6-10 - Request WRITE_EXTERNAL_STORAGE permission
                androidx.core.app.ActivityCompat.requestPermissions(
                    activity,
                    arrayOf(android.Manifest.permission.WRITE_EXTERNAL_STORAGE),
                    STORAGE_PERMISSION_REQUEST_CODE
                )
                // Store file info for later retry
                pendingFileSave = Pair(cacheFile, fileName)
            }
        }

        private fun getMimeType(fileName: String): String {
            return when (fileName.substringAfterLast(".", "")) {
                "pdf" -> "application/pdf"
                "doc" -> "application/msword"
                "docx" -> "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
                "xls" -> "application/vnd.ms-excel"
                "xlsx" -> "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
                "txt" -> "text/plain"
                "jpg", "jpeg" -> "image/jpeg"
                "png" -> "image/png"
                "gif" -> "image/gif"
                "mp4" -> "video/mp4"
                "mp3" -> "audio/mpeg"
                "zip" -> "application/zip"
                else -> "application/octet-stream"
            }
        }

        companion object {
            private const val STORAGE_PERMISSION_REQUEST_CODE = 2001
            private var pendingFileSave: Pair<java.io.File, String>? = null
        }

        private fun openImageViewer(imageUrl: String, fileName: String) {
            val context = binding.root.context
            try {
                val intent = Intent(context, ImageViewerActivity::class.java).apply {
                    putExtra(ImageViewerActivity.EXTRA_IMAGE_URL, imageUrl)
                    putExtra(ImageViewerActivity.EXTRA_FILE_NAME, fileName)
                    // Pass server credentials if available
                    chatRepository?.let { repo ->
                        putExtra(ImageViewerActivity.EXTRA_SERVER_URL, repo.getBaseUrl())
                        // For now, we'll get credentials from preferences in the activity
                        // In a production app, these should be securely stored and passed
                    }
                }
                context.startActivity(intent)
            } catch (e: Exception) {
                android.util.Log.e("ImageViewer", "Failed to open image viewer", e)
                android.widget.Toast.makeText(
                    context,
                    "Невозможно открыть просмотр изображений",
                    android.widget.Toast.LENGTH_SHORT
                ).show()
            }
        }

        private fun showMessageActionsDialog(message: ChatMessage) {
            val context = binding.root.context
            val activity = context as? android.app.Activity ?: return

            // Resolve chatUserId to actual userId
            val chatUserItem = chatUsers?.find { it.id == message.chatUserId }
            val actualUserId = chatUserItem?.userId ?: message.chatUserId
            val currentUserId = currentUserId ?: 12033923L
            val isOwnMessage = actualUserId == currentUserId

            // Build options based on message ownership
            val options = mutableListOf("Ответить", "Добавить реакцию")
            if (isOwnMessage) {
                options.add(1, "Редактировать") // Insert after Reply
                options.add(2, "Удалить") // Insert after Edit
            }

            android.app.AlertDialog.Builder(activity)
                .setTitle("Действия с сообщением")
                .setItems(options.toTypedArray()) { _, which ->
                    when (options[which]) {
                        "Ответить" -> {
                            onReplyToMessage?.invoke(message)
                        }
                        "Редактировать" -> {
                            onEditMessage?.invoke(message)
                        }
                        "Удалить" -> {
                            // Show confirmation dialog for delete
                            android.app.AlertDialog.Builder(activity)
                                .setTitle("Удалить сообщение")
                                .setMessage("Вы уверены, что хотите удалить это сообщение?")
                                .setPositiveButton("Удалить") { _, _ ->
                                    onDeleteMessage?.invoke(message)
                                }
                                .setNegativeButton("Отмена", null)
                                .show()
                        }
                        "Добавить реакцию" -> {
                            showReactionPickerDialog(message)
                        }
                    }
                }
                .setNegativeButton("Отмена", null)
                .show()
        }

        private fun showReactionPickerDialog(message: ChatMessage) {
            val context = binding.root.context
            val activity = context as? android.app.Activity ?: return

            // Create custom dialog with horizontal emoji picker
            val dialog = android.app.AlertDialog.Builder(activity)
                .setTitle("Добавить реакцию")
                .setNegativeButton("Отмена", null)
                .create()

            val container = createHorizontalEmojiPicker(context, message, dialog)

            dialog.setView(container)
            dialog.show()
        }

        private fun createHorizontalEmojiPicker(context: android.content.Context, message: ChatMessage, dialog: android.app.AlertDialog): android.view.View {
            val allowedEmojis = listOf("👍", "👎", "❤️", "🔥", "👏", "😀", "🥰", "🤣")

            // Create horizontal LinearLayout for emojis
            val container = android.widget.LinearLayout(context).apply {
                orientation = android.widget.LinearLayout.HORIZONTAL
                gravity = android.view.Gravity.CENTER
                setPadding(16, 16, 16, 16)
            }

            // Create emoji buttons
            allowedEmojis.forEach { emoji ->
                val emojiButton = android.widget.TextView(context).apply {
                    text = emoji
                    textSize = 24f
                    setPadding(16, 16, 16, 16)
                    background = android.graphics.drawable.GradientDrawable().apply {
                        setColor(android.graphics.Color.parseColor("#F5F5F5"))
                        cornerRadius = 24f
                        setStroke(1, android.graphics.Color.parseColor("#E0E0E0"))
                    }
                    layoutParams = android.widget.LinearLayout.LayoutParams(
                        android.widget.LinearLayout.LayoutParams.WRAP_CONTENT,
                        android.widget.LinearLayout.LayoutParams.WRAP_CONTENT
                    ).apply {
                        setMargins(8, 0, 8, 0)
                    }

                    // Make emoji clickable
                    setOnClickListener {
                        onAddReaction?.invoke(message, emoji)
                        // Dismiss the dialog
                        dialog.dismiss()
                    }
                }

                container.addView(emojiButton)
            }

            return container
        }

        private fun displayReactions(message: ChatMessage, isSentMessage: Boolean) {
            val reactions = message.reactions ?: emptyList()
            if (reactions.isEmpty()) {
                if (isSentMessage) {
                    binding.sentReactionsContainer.visibility = android.view.View.GONE
                } else {
                    binding.receivedReactionsContainer.visibility = android.view.View.GONE
                }
                return
            }

            // Clear existing reactions
            val container = if (isSentMessage) binding.sentReactionsContainer else binding.receivedReactionsContainer
            container.removeAllViews()

            // Group reactions by emoji
            val reactionGroups = reactions.groupBy { it.reaction }

            // Show reactions container
            container.visibility = android.view.View.VISIBLE

            // Create reaction views for each unique emoji
            reactionGroups.forEach { (emoji, reactionList) ->
                val reactionView = android.widget.TextView(container.context).apply {
                    text = emoji
                    textSize = 16f
                    setPadding(8, 4, 8, 4)
                    background = android.graphics.drawable.GradientDrawable().apply {
                        setColor(android.graphics.Color.parseColor("#E0E0E0"))
                        cornerRadius = 16f
                        setStroke(1, android.graphics.Color.parseColor("#B0B0B0"))
                    }
                    layoutParams = android.widget.LinearLayout.LayoutParams(
                        android.widget.LinearLayout.LayoutParams.WRAP_CONTENT,
                        android.widget.LinearLayout.LayoutParams.WRAP_CONTENT
                    ).apply {
                        setMargins(0, 0, 8, 0)
                    }

                    // Show count if more than 1
                    if (reactionList.size > 1) {
                        text = "$emoji ${reactionList.size}"
                    }

                    // Make reaction clickable to show who reacted
                    setOnClickListener {
                        showReactionDetailsDialog(message, emoji, reactionList)
                    }

                    // Make reaction long-clickable to remove (if it's the current user's reaction)
                    setOnLongClickListener {
                        // Get the current user's chatUserId (not the global userId)
                        val currentChatUserId = chatUsers?.find { it.userId == (currentUserId ?: 12033923L) }?.id
                        val userReaction = reactionList.find { it.chatUserId == currentChatUserId }
                        if (userReaction != null) {
                            showRemoveReactionConfirmation(message, userReaction.id)
                        } else {
                            // Show toast if user tries to remove reaction they don't have
                            val context = binding.root.context
                            android.widget.Toast.makeText(
                                context,
                                "Вы не можете удалить эту реакцию",
                                android.widget.Toast.LENGTH_SHORT
                            ).show()
                        }
                        true
                    }
                }

                container.addView(reactionView)
            }
        }

        private fun showReactionDetailsDialog(message: ChatMessage, emoji: String, reactions: List<com.crm.chat.data.model.ChatMessageReaction>) {
            val context = binding.root.context
            val activity = context as? android.app.Activity ?: return

            // Build list of users who reacted
            val userNames = reactions.mapNotNull { reaction ->
                val chatUserItem = chatUsers?.find { it.id == reaction.chatUserId }
                val userId = chatUserItem?.userId ?: reaction.chatUserId
                getUserName(userId)
            }.joinToString(", ")

            android.app.AlertDialog.Builder(activity)
                .setTitle("Реакция $emoji")
                .setMessage("Пользователи: $userNames")
                .setPositiveButton("OK", null)
                .show()
        }

        private fun showRemoveReactionConfirmation(message: ChatMessage, reactionId: Long) {
            val context = binding.root.context
            val activity = context as? android.app.Activity ?: return

            android.app.AlertDialog.Builder(activity)
                .setTitle("Удалить реакцию")
                .setMessage("Вы уверены, что хотите удалить свою реакцию?")
                .setPositiveButton("Удалить") { _, _ ->
                    onRemoveReaction?.invoke(message, reactionId)
                }
                .setNegativeButton("Отмена", null)
                .show()
        }

        private fun formatTimestamp(timestamp: String): String {
            return try {
                // Assuming timestamp is in ISO format
                val date = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.getDefault())
                    .parse(timestamp)
                dateFormat.format(date ?: Date())
            } catch (e: Exception) {
                dateFormat.format(Date())
            }
        }
    }

    class MessageDiffCallback : DiffUtil.ItemCallback<ChatMessage>() {
        override fun areItemsTheSame(oldItem: ChatMessage, newItem: ChatMessage): Boolean {
            return oldItem.id == newItem.id
        }

        override fun areContentsTheSame(oldItem: ChatMessage, newItem: ChatMessage): Boolean {
            return oldItem == newItem
        }
    }
}
