package com.sortug.thaiinput
import android.graphics.Color
import android.graphics.Typeface
import android.inputmethodservice.InputMethodService
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.InputConnection
import kotlinx.coroutines.*
import android.util.Log
import com.google.gson.Gson
// options box
import android.widget.Button
import android.widget.HorizontalScrollView
import android.widget.LinearLayout
import android.widget.TextView
import androidx.core.content.res.ResourcesCompat
import kotlin.properties.Delegates


class MyKeyboardService : InputMethodService() {
    private val coroutineScope = CoroutineScope(Dispatchers.Main + Job())
    private var currentInput: String by Delegates.observable("") { _, _, newValue ->
        updateCurrentInputDisplay(newValue)
    }
    private val gson = Gson()
    private lateinit var keyboardContainer: LinearLayout
    private lateinit var suggestionsContainer: LinearLayout
    private lateinit var currentInputDisplay: TextView
    private lateinit var currentTitle: TextView

    private var isShiftActive = false
    private fun updateCurrentInputDisplay(text: String) {
        currentInputDisplay.text = text
    }
    private val syms = listOf(
        "1234567890".toList(),
        "!@#$%^&*()".toList(),
        "\".:?/-=+".toList()
    )
    private val letters = listOf(
        "QWERTYUIOP".toList(),
        "ASDFGHJKL".toList(),
        "ZXCVBNM".toList()
    )
    data class FontInfo(val resourceId: Int, val name: String)
    private val fonts = listOf(
        FontInfo(R.font.charm_regular,"charm"),
        FontInfo(R.font.ibmplexsansthai_regular,"ibm"),
        FontInfo(R.font.chonburi_regular,"chonburi"),
        FontInfo(R.font.judson_regular,"judson"),
        FontInfo(R.font.kanit_regular, "kanit")
        )

    private var currentFontIndex = 0

    override fun onCreateInputView(): View {
        Log.d("THAI_IME", "onCreateInputView called") // Add this debug log
        val inputView = layoutInflater.inflate(R.layout.keyboard_layout, null)

        // Initialize views using findViewById
        currentTitle = inputView.findViewById(R.id.keyboard_title)
        currentInputDisplay = inputView.findViewById(R.id.current_input_display)
        suggestionsContainer = inputView.findViewById(R.id.suggestions_container)
        keyboardContainer = inputView.findViewById(R.id.keyboard_container)

        // Set up the keyboard
        setKeyboard(letters)

        Log.d("THAI_IME", "Keyboard container child count: ${keyboardContainer.childCount}")
        return inputView
    }


    private fun setSpecialKey(row: LinearLayout, txt: String, onClick: (String) -> Unit, width: Float = 1.5f){
        val button = Button(this).apply{
            text = txt
            layoutParams = LinearLayout.LayoutParams(
                0,
                LinearLayout.LayoutParams.WRAP_CONTENT,
                width
            ).apply {
                setMargins(4, 4, 4, 4)
            }
            setTextColor(Color.LTGRAY)
            setBackgroundColor(Color.BLACK)
            setOnClickListener {onClick(txt)}
        }
        row.addView(button)
    }
    private fun setKeyboard(rows: List<List<Char>>) {
        rows.forEachIndexed { rowIndex, row ->
            Log.d("THAI_IME", "setting row :$row $rowIndex")
            val rowLayout = LinearLayout(this).apply {
                orientation = LinearLayout.HORIZONTAL
                layoutParams = LinearLayout.LayoutParams(
                    LinearLayout.LayoutParams.MATCH_PARENT,
                    LinearLayout.LayoutParams.WRAP_CONTENT
                )
            }
            if (rowIndex == 2){setSpecialKey(rowLayout, "1!", ::handleShift)}
            // set keys proper
            row.forEach { char ->
                Log.d("THAI_IME", "setting char :$char")
                val button = Button(this).apply {
                    text = char.toString()
                    layoutParams = LinearLayout.LayoutParams(
                        0,
                        LinearLayout.LayoutParams.WRAP_CONTENT,
                        1f
                    ).apply{
                        setMargins(4, 4, 4, 4)
                    }
                    setTextColor(Color.LTGRAY)
                    textSize = 18f
                    setBackgroundColor(Color.BLACK)
                    setOnClickListener {
                        if (isShiftActive) {
                            noApiCall(char.toString())
                        }else{
                            onKeyPressed(char.lowercaseChar().toString())
                        }
                    }
                }
                rowLayout.addView(button)
            }

            if (rowIndex == 2) {setSpecialKey(rowLayout,"⌫", ::onBackspace)}
            keyboardContainer.addView(rowLayout)
        }
        val spaceRow = LinearLayout(this).apply {
            orientation = LinearLayout.HORIZONTAL
            layoutParams = LinearLayout.LayoutParams(
                LinearLayout.LayoutParams.MATCH_PARENT,
                LinearLayout.LayoutParams.WRAP_CONTENT
            )
        }
        setSpecialKey(spaceRow, "F", ::changeFont, 0.4f)
        setSpecialKey(spaceRow, "␣", {_ -> noApiCall(" ")}, 1f)
        setSpecialKey(spaceRow, "↵", {_ -> noApiCall("\n")}, 0.4f)
        keyboardContainer.addView(spaceRow)
    }

    private fun createSpecialButton(text: String, onClickListener: () -> Unit): Button {
        return Button(this).apply {
            this.text = text
            layoutParams = LinearLayout.LayoutParams(
                0,
                LinearLayout.LayoutParams.WRAP_CONTENT,
                1.5f
            )
            setOnClickListener { onClickListener() }
        }
    }


    private fun onBackspace(_thing: String) {
        Log.d("MyKeyboardService", "onBackspace called")
        val inputConnection = currentInputConnection ?: return

        // Only make API request if we still have text
        if (currentInput.isNotEmpty()) {
            currentInput = currentInput.substring(0, currentInput.length - 1)
            apiCall()
        } else {
            inputConnection.deleteSurroundingText(1, 0)
            // Clear suggestions if we've deleted all text
            suggestionsContainer.removeAllViews()
        }
              Log.d("MyKeyboardService", "Current input after backspace: $currentInput")
    }
    override fun onDestroy() {
        super.onDestroy()
        coroutineScope.cancel()
    }
    private fun onKeyPressed(text: String) {
        Log.d("MyKeyboardService", "onKeyPressed called with text: $text")
        currentInput += text
        Log.d("MyKeyboardService", "Current input: $currentInput")
        Log.d("MyKeyboardService", "Key pressed: $text")
        apiCall()
    }
    private fun noApiCall(text: String){
        val inputConnection: InputConnection = currentInputConnection ?: return
        inputConnection.commitText(text, 1)
    }
    private fun apiCall(){
        if (currentInput.isNotEmpty()){
        coroutineScope.launch {
            try {
                Log.d("THAI_IME", "API request input: $currentInput")
                val response = withContext(Dispatchers.IO) {
                    RetrofitClient.googleInputToolsApiService.getInputSuggestions(currentInput)
                }
                Log.d("THAI_IME", "raw API response: $response")
                when (val apiResponse = parseResponse(response)){
                    is InputToolsResponse.Success -> {
                        val options = apiResponse.results.flatMap{it.options}
                        Log.d("MyKeyboardService", "Parsed options after backspace: $options")
                        displaySuggestions((options))
                    }
                    is InputToolsResponse.FailedToParse -> {
                        Log.e("THAI_IME", "Failed to parse request body: $currentInput")
                    }
                }
            } catch (e: Exception) {
                Log.e("MyKeyboardService", "Error in API call after backspace", e)
                displaySuggestions(listOf("Error: ${e.message}"))
            }
        }
        }
    }


    private fun displaySuggestions(options: List<String>){
        suggestionsContainer.removeAllViews()
        options.forEach{ option ->
            val button = Button(this).apply{
                text = option
                textSize = 20f
                setOnClickListener { onSuggestionClicked(option) }
                layoutParams = LinearLayout.LayoutParams(
                    LinearLayout.LayoutParams.WRAP_CONTENT,
                    LinearLayout.LayoutParams.WRAP_CONTENT,
                ).apply{
                    setMargins(5, 5, 5, 5)
                }
            }
            suggestionsContainer.addView(button)
        }

    }
    private fun onSuggestionClicked(selectedText: String) {
        val inputConnection: InputConnection = currentInputConnection ?: return
        // Commit the selected text
        inputConnection.commitText(selectedText, 1)
        // Update the current input
        currentInput = ""
        // Clear suggestions
        suggestionsContainer.removeAllViews()
    }

    private fun handleShift(_thing: String){
        Log.d("THAI_IME", "shift pressed")
        isShiftActive = !isShiftActive
        val keys = if (isShiftActive) syms else letters
        keyboardContainer.removeAllViews()
        setKeyboard(keys)
    }
    private fun changeFont(_thing: String){
        currentFontIndex = (currentFontIndex + 1) % fonts.size
        val currentFont = fonts[currentFontIndex]
        currentTitle.text = currentFont.name
        val typeface = ResourcesCompat.getFont(this, currentFont.resourceId)
        for (i in 0 until suggestionsContainer.childCount) {
            val button = suggestionsContainer.getChildAt(i) as? Button
            button?.let{
                it.typeface = typeface
            }
        }
    }

}
object ViewDebugUtils {
    fun getViewHierarchy(view: View?, level: Int = 0): String {
        if (view == null) return "null"

        val indent = "  ".repeat(level)
        val builder = StringBuilder()

        // Basic view information
        builder.append("$indent${view.javaClass.simpleName} {")
        builder.append("\n${indent}  id: ${getViewId(view)}")
        builder.append("\n${indent}  width: ${view.width}, height: ${view.height}")
        builder.append("\n${indent}  visibility: ${getVisibilityString(view.visibility)}")

        // Layout parameters
        val params = view.layoutParams
        if (params != null) {
            builder.append("\n${indent}  layout_width: ${getLayoutParamSize(params.width)}")
            builder.append("\n${indent}  layout_height: ${getLayoutParamSize(params.height)}")
        }

        // For ViewGroups, recursively print children
        if (view is ViewGroup) {
            builder.append("\n${indent}  children: [")
            for (i in 0 until view.childCount) {
                builder.append("\n${getViewHierarchy(view.getChildAt(i), level + 2)}")
            }
            if (view.childCount > 0) builder.append("\n$indent  ]")
            else builder.append("]")
        }

        builder.append("\n$indent}")
        return builder.toString()
    }

    private fun getViewId(view: View): String {
        val id = view.id
        return when {
            id == View.NO_ID -> "NO_ID"
            else -> try {
                view.resources.getResourceEntryName(id)
            } catch (e: Exception) {
                id.toString()
            }
        }
    }

    private fun getVisibilityString(visibility: Int): String = when (visibility) {
        View.VISIBLE -> "VISIBLE"
        View.INVISIBLE -> "INVISIBLE"
        View.GONE -> "GONE"
        else -> visibility.toString()
    }

    private fun getLayoutParamSize(size: Int): String = when (size) {
        ViewGroup.LayoutParams.MATCH_PARENT -> "MATCH_PARENT"
        ViewGroup.LayoutParams.WRAP_CONTENT -> "WRAP_CONTENT"
        else -> size.toString()
    }
}