package com.mistral.chat.ui

import android.content.Context
import android.content.SharedPreferences
import android.os.Bundle
import android.view.KeyEvent
import android.view.View
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputMethodManager
import android.widget.ImageButton
import android.widget.ImageView
import android.widget.PopupMenu
import android.widget.TextView
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.progressindicator.LinearProgressIndicator
import com.google.android.material.textfield.TextInputEditText
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.mistral.chat.R
import com.mistral.chat.api.MistralClient
import com.mistral.chat.data.Message
import com.mistral.chat.data.UserProfile
import kotlinx.coroutines.launch

class MainActivity : AppCompatActivity() {

    private lateinit var recyclerView: RecyclerView
    private lateinit var adapter: MessageAdapter
    private lateinit var inputField: TextInputEditText
    private lateinit var sendButton: ImageView
    private lateinit var progressIndicator: LinearProgressIndicator
    private lateinit var logoButton: ImageView
    private lateinit var menuButton: ImageButton
    private lateinit var toolbarTitle: TextView
    private lateinit var gson: Gson
    private var currentJob: kotlinx.coroutines.Job? = null

    private var client: MistralClient? = null
    private val messages = mutableListOf<Message>()
    private var availableModels: List<Pair<String, String>> = emptyList()
    private var selectedModelName: String = "mistral-small-latest"
    private lateinit var prefs: SharedPreferences

    companion object {
        private const val API_KEY = "YW0IjDBRLuyEBcgNjVeVUFlMI6fcZYLA"
        private const val PREFS_NAME = "mistral_chat_prefs"
        private const val KEY_USER_NAME = "user_name"
        private const val KEY_USER_BIO = "user_bio"
        private const val KEY_USER_PREFS = "user_preferences"
        private const val KEY_MESSAGES = "chat_messages"
        private const val KEY_PROFILE_HASH = "profile_hash"
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        gson = Gson()
        prefs = getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
        client = MistralClient(API_KEY)

        loadMessages()
        
        logoButton = findViewById(R.id.logoButton)
        menuButton = findViewById(R.id.menuButton)
        toolbarTitle = findViewById(R.id.toolbarTitle)
        recyclerView = findViewById(R.id.recyclerView)
        inputField = findViewById(R.id.inputField)
        sendButton = findViewById(R.id.sendButton)
        progressIndicator = findViewById(R.id.progressIndicator)

        setupToolbar()
        setupRecyclerView()
        loadModels()
        setupInput()

        inputField.postDelayed({
            val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
            inputField.requestFocus()
            imm.showSoftInput(inputField, InputMethodManager.SHOW_IMPLICIT)
        }, 300)
    }

    private fun setupToolbar() {
        logoButton.setOnClickListener {
            showModelSelectorDialog()
        }
        
        menuButton.setOnClickListener { view ->
            val popup = PopupMenu(this, view)
            popup.menuInflater.inflate(R.menu.main_menu, popup.menu)
            popup.setOnMenuItemClickListener { menuItem ->
                when (menuItem.itemId) {
                    R.id.action_profile -> {
                        showProfileDialog()
                        true
                    }
                    R.id.action_clear -> {
                        showClearChatDialog()
                        true
                    }
                    R.id.action_about -> {
                        showAboutDialog()
                        true
                    }
                    else -> false
                }
            }
            popup.show()
        }
    }

    private fun showModelSelectorDialog() {
        val modelNames = availableModels.map { it.second }.toTypedArray()
        val currentModelId = availableModels.find { it.first == selectedModelName }?.second ?: modelNames.firstOrNull() ?: ""
        val currentIndex = modelNames.indexOf(currentModelId).coerceAtLeast(0)

        AlertDialog.Builder(this)
            .setTitle(R.string.select_model)
            .setSingleChoiceItems(modelNames, currentIndex) { dialog, which ->
                selectedModelName = availableModels[which].first
                dialog.dismiss()
            }
            .setNegativeButton(R.string.cancel, null)
            .show()
    }

    private fun setupRecyclerView() {
        adapter = MessageAdapter(messages)
        recyclerView.layoutManager = LinearLayoutManager(this).apply {
            stackFromEnd = true
        }
        recyclerView.adapter = adapter
    }

    private fun setupInput() {
        sendButton.setOnClickListener {
            if (currentJob?.isActive == true) {
                cancelRequest()
            } else {
                sendInput()
            }
        }
        
        inputField.setOnEditorActionListener { _, actionId, event ->
            if (actionId == EditorInfo.IME_ACTION_SEND || actionId == EditorInfo.IME_ACTION_GO || actionId == EditorInfo.IME_ACTION_DONE || (event?.keyCode == KeyEvent.KEYCODE_ENTER && event.action == KeyEvent.ACTION_DOWN)) {
                sendInput()
                true
            } else {
                false
            }
        }
    }
    
    private fun sendInput() {
        val userInput = inputField.text?.toString()?.trim()
        if (userInput.isNullOrEmpty()) return

        addMessage(Message(content = userInput, isUser = true))
        inputField.text?.clear()

        sendMessage(userInput)
    }

    private fun loadModels() {
        lifecycleScope.launch {
            val result = client?.getModels()
            result?.onSuccess { models ->
                availableModels = models
                runOnUiThread {
                    val codestralIndex = models.indexOfFirst { it.first.contains("codestral", ignoreCase = true) }
                    if (codestralIndex >= 0) {
                        selectedModelName = models[codestralIndex].first
                    } else if (models.isNotEmpty()) {
                        selectedModelName = models[0].first
                    }
                }
            }?.onFailure {
                availableModels = MistralClient.AVAILABLE_MODELS
                runOnUiThread {
                    selectedModelName = MistralClient.AVAILABLE_MODELS.firstOrNull()?.first ?: "mistral-small-latest"
                }
            }
        }
    }

    private fun addMessage(message: Message) {
        messages.add(message)
        adapter.notifyItemInserted(messages.size - 1)
        saveMessages()
        
        recyclerView.postDelayed({
            recyclerView.scrollToPosition(messages.size - 1)
        }, 100)
    }

    private fun loadMessages() {
        val json = prefs.getString(KEY_MESSAGES, null)
        if (json != null) {
            try {
                val type = object : TypeToken<List<Message>>() {}.type
                val loaded: List<Message> = gson.fromJson(json, type)
                messages.clear()
                messages.addAll(loaded)
            } catch (e: Exception) {
                // Ignore parse errors
            }
        }
    }

    private fun saveMessages() {
        val json = gson.toJson(messages)
        prefs.edit().putString(KEY_MESSAGES, json).apply()
    }

    private fun sendMessage(userInput: String) {
        val selectedModel = selectedModelName
        
        sendButton.isEnabled = false
        sendButton.setImageResource(R.drawable.ic_stop)
        progressIndicator.isVisible = true

        currentJob = lifecycleScope.launch {
            try {
                val userProfile = loadUserProfile()
                
                val profileContext = if (!userProfile.isEmpty()) {
                    userProfile.toContextString()
                } else ""

                val apiMessages = messages.map { msg ->
                    Message(
                        content = msg.content,
                        isUser = msg.isUser
                    )
                }.toMutableList()

                if (profileContext.isNotEmpty()) {
                    apiMessages.add(0, Message(content = profileContext, isUser = true))
                }

                val result = client?.chat(selectedModel, apiMessages)

                result?.onSuccess { (response, usedModel) ->
                    addMessage(Message(content = response, isUser = false, senderName = usedModel))
                }?.onFailure { error ->
                    val errorMessage = error.message ?: "Unknown error"
                    val userFriendlyMessage = getUserFriendlyError(errorMessage)
                    addMessage(Message(content = userFriendlyMessage, isUser = false, senderName = "Error"))
                }
            } catch (e: kotlinx.coroutines.CancellationException) {
                addMessage(Message(content = "❌ Отменено пользователем", isUser = false, senderName = "Cancelled"))
            } finally {
                sendButton.isEnabled = true
                sendButton.setImageResource(R.drawable.ic_mistral_logo)
                progressIndicator.isVisible = false
            }
        }
    }
    
    private fun cancelRequest() {
        currentJob?.cancel()
        client?.cancelRequest()
    }

    private fun loadUserProfile(): UserProfile {
        return UserProfile(
            name = prefs.getString(KEY_USER_NAME, "") ?: "",
            bio = prefs.getString(KEY_USER_BIO, "") ?: "",
            preferences = prefs.getString(KEY_USER_PREFS, "") ?: ""
        )
    }

    private fun saveUserProfile(profile: UserProfile) {
        prefs.edit()
            .putString(KEY_USER_NAME, profile.name)
            .putString(KEY_USER_BIO, profile.bio)
            .putString(KEY_USER_PREFS, profile.preferences)
            .remove(KEY_PROFILE_HASH)
            .apply()
    }

    private fun deleteUserProfile() {
        prefs.edit()
            .remove(KEY_USER_NAME)
            .remove(KEY_USER_BIO)
            .remove(KEY_USER_PREFS)
            .remove(KEY_PROFILE_HASH)
            .apply()
    }

    private fun showProfileDialog() {
        val profile = loadUserProfile()
        val dialogView = layoutInflater.inflate(R.layout.dialog_profile, null)
        
        val nameInput = dialogView.findViewById<TextInputEditText>(R.id.nameInput)
        val bioInput = dialogView.findViewById<TextInputEditText>(R.id.bioInput)
        val preferencesInput = dialogView.findViewById<TextInputEditText>(R.id.preferencesInput)

        nameInput.setText(profile.name)
        bioInput.setText(profile.bio)
        preferencesInput.setText(profile.preferences)

        AlertDialog.Builder(this)
            .setView(dialogView)
            .setPositiveButton(R.string.save) { _, _ ->
                val newProfile = UserProfile(
                    name = nameInput.text?.toString() ?: "",
                    bio = bioInput.text?.toString() ?: "",
                    preferences = preferencesInput.text?.toString() ?: ""
                )
                saveUserProfile(newProfile)
            }
            .setNegativeButton(R.string.cancel, null)
            .setNeutralButton(R.string.delete) { _, _ ->
                deleteUserProfile()
            }
            .show()
    }

    private fun showClearChatDialog() {
        AlertDialog.Builder(this)
            .setMessage(R.string.clear_chat_confirm)
            .setPositiveButton(R.string.yes) { _, _ ->
                messages.clear()
                adapter.notifyDataSetChanged()
                prefs.edit().remove(KEY_MESSAGES).apply()
            }
            .setNegativeButton(R.string.no, null)
            .show()
    }

    private fun showAboutDialog() {
        AlertDialog.Builder(this)
            .setMessage(R.string.about_text)
            .setPositiveButton(android.R.string.ok, null)
            .show()
    }

    private fun getUserFriendlyError(error: String): String {
        return when {
            error.contains("timeout", ignoreCase = true) ||
            error.contains("TimedOut", ignoreCase = true) ||
            error.contains("SocketTimeoutException", ignoreCase = true) || 
            error.contains("connection abort", ignoreCase = true) ||
            error.contains("Software caused connection abort", ignoreCase = true) ->
                "⚠️ Время ожидания истекло. Проверьте интернет-соединение и попробуйте снова."
            
            error.contains("network", ignoreCase = true) ||
            error.contains("Unable to resolve host", ignoreCase = true) ||
            error.contains("No route to host", ignoreCase = true) ->
                "🌐 Нет подключения к интернету. Проверьте соединение и попробуйте снова."
            
            error.contains("401", ignoreCase = true) ||
            error.contains("unauthorized", ignoreCase = true) ->
                "🔑 Ошибка авторизации. Проверьте API ключ в настройках приложения."
            
            error.contains("403", ignoreCase = true) ||
            error.contains("forbidden", ignoreCase = true) ->
                "🚫 Доступ запрещён. Возможно, API ключ истёк или недействителен."
            
            error.contains("429", ignoreCase = true) ||
            error.contains("rate limit", ignoreCase = true) ||
            error.contains("too many requests", ignoreCase = true) ->
                "⏳ Слишком много запросов. Подождите немного и попробуйте снова."
            
            error.contains("500", ignoreCase = true) ||
            error.contains("internal server error", ignoreCase = true) ->
                "🔧 Ошибка сервера Mistral. Попробуйте выбрать другую модель или повторите позже."
            
            error.contains("503", ignoreCase = true) ||
            error.contains("service unavailable", ignoreCase = true) ->
                "🛠️ Сервис временно недоступен. Попробуйте позже."
            
            error.contains("404", ignoreCase = true) ||
            error.contains("not found", ignoreCase = true) ->
                "❓ Ресурс не найден. Попробуйте выбрать другую модель."
            
            error.contains("null", ignoreCase = true) ||
            error.contains("empty response", ignoreCase = true) ->
                "📭 Пустой ответ от сервера. Попробуйте ещё раз."
            
            else -> "❌ Произошла ошибка: $error"
        }
    }
}