package com.amz.genie.activities

import android.app.DatePickerDialog
import android.app.TimePickerDialog
import android.os.Bundle
import android.provider.OpenableColumns
import android.text.InputType
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.widget.Button
import android.widget.ImageButton
import android.widget.LinearLayout
import android.widget.TextView
import androidx.activity.OnBackPressedCallback
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.amz.genie.R
import com.amz.genie.adapters.RecipientAdapter
import com.amz.genie.adapters.RecipientPickerAdapter
import com.amz.genie.helpers.Preferences
import com.amz.genie.helpers.SimpleTextWatcher
import com.amz.genie.helpers.Utils.forceLogoutAndGoLogin
import com.amz.genie.helpers.Utils.isNetworkAvailable
import com.amz.genie.models.AddActionItem
import com.amz.genie.models.FormAttachment
import com.amz.genie.models.KomunikasiDetail
import com.amz.genie.models.Message
import com.amz.genie.models.Pegawai
import com.amz.genie.models.Pengguna
import com.amz.genie.services.APIMain
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.snackbar.Snackbar
import com.google.android.material.textfield.TextInputEditText
import com.google.android.material.textfield.TextInputLayout
import com.google.gson.Gson
import com.google.gson.JsonParser
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.MultipartBody
import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.asRequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import java.io.File
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
import kotlin.collections.emptyList

class AddTemplateActionActivity : BaseActivity() {

    private lateinit var ibBack: ImageButton
    private lateinit var tvKomunikasi: TextView
    private lateinit var rvRecipient: RecyclerView
    private lateinit var tvEmpty: TextView
    private lateinit var tvAddRecipient: TextView
    private lateinit var recipientAdapter: RecipientAdapter
    private lateinit var actionItem: AddActionItem
    private lateinit var btSend: Button

    private val recipientOptions = mutableListOf<Pegawai>()
    private val selectedRecipients = mutableListOf<Pegawai>()

    // value form dinamis: Int / Double / String / MutableList<String> / MutableList<FormAttachment>
    private val formValues = linkedMapOf<Int, Any?>()

    // untuk validasi & setError field angka/pecahan/text/tanggal/waktu/jam/string
    private val fieldTilByKode = linkedMapOf<Int, TextInputLayout>()
    private val fieldEtByKode = linkedMapOf<Int, TextInputEditText>()

    // untuk list (error wajib list)
    private val listInputEtByKode = linkedMapOf<Int, TextInputEditText>()

    // untuk lampiran (tampilan list nama file + error text)
    private val lampiranTvFilesByKode = linkedMapOf<Int, TextView>()
    private val lampiranTvErrorByKode = linkedMapOf<Int, TextView>()

    private val sdfDate = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
    private val sdfDateTime = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault())
    private val sdfTime = SimpleDateFormat("HH:mm:ss", Locale.getDefault())

    private var currentLampiranKode: Int? = null

    private val pickLampiranLauncher =
        registerForActivityResult(ActivityResultContracts.OpenMultipleDocuments()) { uris ->
            val kode = currentLampiranKode ?: return@registerForActivityResult
            currentLampiranKode = null

            val list = (formValues[kode] as? MutableList<FormAttachment>) ?: mutableListOf()

            for (u in uris) {
                val meta = readUriMeta(u) ?: continue
                if (list.any { it.uri == u }) continue // avoid duplicate
                list.add(meta)
            }

            formValues[kode] = list

            // refresh UI
            refreshLampiranUI(kode)
        }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_add_template_action)
        initUI()
    }

    private fun initUI() {
        ibBack = findViewById(R.id.ib_back_add_template_action)
        tvKomunikasi = findViewById(R.id.tv_komunikasi_add_template_action)
        rvRecipient = findViewById(R.id.rv_recipient_add_template_action)
        tvEmpty = findViewById(R.id.tv_empty_add_template_action)
        tvAddRecipient = findViewById(R.id.tv_lbl_recipient_add_template_action)
        btSend = findViewById(R.id.bt_send_add_template_action)

        val intentDataJson = intent.getStringExtra("data") ?: return
        actionItem = Gson().fromJson(intentDataJson, AddActionItem::class.java)

        tvKomunikasi.text = actionItem.title.orEmpty()

        recipientAdapter = RecipientAdapter { pegawai ->
            val idx = selectedRecipients.indexOfFirst { it.kode == pegawai.kode }
            if (idx != -1) {
                selectedRecipients.removeAt(idx)
                renderRecipients()
                showSnack("Penerima dihapus")
            }
        }

        rvRecipient.layoutManager = LinearLayoutManager(this)
        rvRecipient.adapter = recipientAdapter

        val details = actionItem.komunikasi_detail.orEmpty()
        if (details.isNotEmpty()) {
            renderDynamicForm(details)
        } else {
            findViewById<LinearLayout>(R.id.ll_add_template_action).removeAllViews()
        }

        initData()
        setupActions()
    }

    // =========================
    // Dynamic Form Renderer
    // =========================
    private fun renderDynamicForm(details: List<KomunikasiDetail>) {
        val container = findViewById<LinearLayout>(R.id.ll_add_template_action)

        container.removeAllViews()
        formValues.clear()
        fieldTilByKode.clear()
        fieldEtByKode.clear()
        listInputEtByKode.clear()
        lampiranTvFilesByKode.clear()
        lampiranTvErrorByKode.clear()

        val fields = details
            .filter { it.is_aktif == 1 }
            .sortedBy { it.urutan ?: Int.MAX_VALUE }

        val inflater = LayoutInflater.from(this)

        for (d in fields) {
            val kode = d.kode ?: continue
            val label = d.isian?.trim().orEmpty().ifBlank { "Field" }
            val wajib = d.is_wajib == 1
            val jenisId = d.id_jenis_isian ?: 6 // fallback string

            when (jenisId) {

                // 4 = angka
                4 -> {
                    val v = inflater.inflate(R.layout.item_dynamic_input, container, false)
                    val til = v.findViewById<TextInputLayout>(R.id.til)
                    val et = v.findViewById<TextInputEditText>(R.id.et)

                    til.hint = if (wajib) "$label *" else label
                    et.inputType = InputType.TYPE_CLASS_NUMBER

                    fieldTilByKode[kode] = til
                    fieldEtByKode[kode] = et

                    et.setText("0")
                    formValues[kode] = 0

                    et.addTextChangedListener(SimpleTextWatcher { text ->
                        til.error = null
                        val value = text.trim()
                        formValues[kode] = value.toIntOrNull() ?: 0
                    })

                    container.addView(v)
                }

                // 5 = pecahan
                5 -> {
                    val v = inflater.inflate(R.layout.item_dynamic_input, container, false)
                    val til = v.findViewById<TextInputLayout>(R.id.til)
                    val et = v.findViewById<TextInputEditText>(R.id.et)

                    til.hint = if (wajib) "$label *" else label
                    et.inputType = InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_FLAG_DECIMAL

                    fieldTilByKode[kode] = til
                    fieldEtByKode[kode] = et

                    et.setText("0.00")
                    formValues[kode] = 0.00

                    et.addTextChangedListener(SimpleTextWatcher { text ->
                        til.error = null
                        val value = text.trim().replace(",", ".")
                        formValues[kode] = value.toDoubleOrNull() ?: 0.00
                    })

                    container.addView(v)
                }

                // 2 = tanggal (yyyy-MM-dd)
                2 -> {
                    val v = inflater.inflate(R.layout.item_dynamic_input, container, false)
                    val til = v.findViewById<TextInputLayout>(R.id.til)
                    val et = v.findViewById<TextInputEditText>(R.id.et)

                    til.hint = if (wajib) "$label *" else label
                    fieldTilByKode[kode] = til
                    fieldEtByKode[kode] = et

                    setupDateField(kode, et, til)
                    container.addView(v)
                }

                // 1 = waktu (yyyy-MM-dd HH:mm:ss)
                1 -> {
                    val v = inflater.inflate(R.layout.item_dynamic_input, container, false)
                    val til = v.findViewById<TextInputLayout>(R.id.til)
                    val et = v.findViewById<TextInputEditText>(R.id.et)

                    til.hint = if (wajib) "$label *" else label
                    fieldTilByKode[kode] = til
                    fieldEtByKode[kode] = et

                    setupDateTimeField(kode, et, til)
                    container.addView(v)
                }

                // 3 = jam (HH:mm:ss)
                3 -> {
                    val v = inflater.inflate(R.layout.item_dynamic_input, container, false)
                    val til = v.findViewById<TextInputLayout>(R.id.til)
                    val et = v.findViewById<TextInputEditText>(R.id.et)

                    til.hint = if (wajib) "$label *" else label
                    fieldTilByKode[kode] = til
                    fieldEtByKode[kode] = et

                    setupTimeField(kode, et, til)
                    container.addView(v)
                }

                // 10 = list
                10 -> {
                    val v = inflater.inflate(R.layout.item_dynamic_list, container, false)
                    val tvLabel = v.findViewById<TextView>(R.id.tv_label)
                    val etItem = v.findViewById<TextInputEditText>(R.id.et_item)
                    val btnAdd = v.findViewById<View>(R.id.btn_add)
                    val tvItems = v.findViewById<TextView>(R.id.tv_items)

                    tvLabel.text = if (wajib) "$label *" else label

                    val items = mutableListOf<String>()
                    formValues[kode] = items
                    listInputEtByKode[kode] = etItem

                    fun refreshItems() {
                        tvItems.text =
                            if (items.isEmpty()) "Belum ada item"
                            else items.joinToString(", ")
                    }

                    btnAdd.setOnClickListener {
                        etItem.error = null
                        val t = etItem.text?.toString().orEmpty().trim()
                        if (t.isEmpty()) {
                            etItem.error = "Item tidak boleh kosong"
                            return@setOnClickListener
                        }
                        if (items.any { it.equals(t, true) }) {
                            showSnack("Item sudah ada")
                            return@setOnClickListener
                        }

                        items.add(t)
                        etItem.setText("")
                        refreshItems()
                    }

                    refreshItems()
                    container.addView(v)
                }

                // 11 = lampiran (multi)
                11 -> {
                    val v = inflater.inflate(R.layout.item_dynamic_attachment, container, false)
                    val tvLabel = v.findViewById<TextView>(R.id.tv_label)
                    val btnPick = v.findViewById<View>(R.id.btn_pick)
                    val btnClear = v.findViewById<View>(R.id.btn_clear)
                    val tvFiles = v.findViewById<TextView>(R.id.tv_files)
                    val tvError = v.findViewById<TextView>(R.id.tv_error)

                    tvLabel.text = if (wajib) "$label *" else label

                    val list = mutableListOf<FormAttachment>()
                    formValues[kode] = list

                    lampiranTvFilesByKode[kode] = tvFiles
                    lampiranTvErrorByKode[kode] = tvError

                    btnPick.setOnClickListener {
                        tvError.visibility = View.GONE
                        currentLampiranKode = kode
                        pickLampiranLauncher.launch(arrayOf("*/*"))
                    }

                    btnClear.setOnClickListener {
                        list.clear()
                        formValues[kode] = list
                        refreshLampiranUI(kode)
                    }

                    refreshLampiranUI(kode)
                    container.addView(v)
                }

                // 0 = teks (multiline)
                0 -> {
                    val v = inflater.inflate(R.layout.item_dynamic_input, container, false)
                    val til = v.findViewById<TextInputLayout>(R.id.til)
                    val et = v.findViewById<TextInputEditText>(R.id.et)

                    til.hint = if (wajib) "$label *" else label

                    et.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_MULTI_LINE
                    et.minLines = 3
                    et.maxLines = 8
                    et.setSingleLine(false)
                    et.setHorizontallyScrolling(false)
                    et.gravity = Gravity.TOP

                    fieldTilByKode[kode] = til
                    fieldEtByKode[kode] = et

                    et.addTextChangedListener(SimpleTextWatcher { text ->
                        til.error = null
                        formValues[kode] = text
                    })

                    container.addView(v)
                }

                // 6 = string (single line) + fallback default
                else -> {
                    val v = inflater.inflate(R.layout.item_dynamic_input, container, false)
                    val til = v.findViewById<TextInputLayout>(R.id.til)
                    val et = v.findViewById<TextInputEditText>(R.id.et)

                    til.hint = if (wajib) "$label *" else label
                    et.inputType = InputType.TYPE_CLASS_TEXT

                    fieldTilByKode[kode] = til
                    fieldEtByKode[kode] = et

                    et.addTextChangedListener(SimpleTextWatcher { text ->
                        til.error = null
                        formValues[kode] = text
                    })

                    container.addView(v)
                }
            }
        }
    }

    private fun refreshLampiranUI(kode: Int) {
        val tvFiles = lampiranTvFilesByKode[kode] ?: return
        val list = (formValues[kode] as? List<FormAttachment>).orEmpty()

        tvFiles.text = if (list.isEmpty()) {
            "Belum ada file"
        } else {
            list.joinToString("\n") { "• ${it.fileName}" }
        }
    }

    private fun setupDateField(kode: Int, et: TextInputEditText, til: TextInputLayout) {
        et.isFocusable = false
        et.isFocusableInTouchMode = false
        et.isClickable = true

        val today = sdfDate.format(Calendar.getInstance().time)
        if (et.text.isNullOrBlank()) et.setText(today)
        formValues[kode] = et.text?.toString().orEmpty()

        fun openPicker() {
            val cal = Calendar.getInstance()

            val currentText = et.text?.toString().orEmpty().trim()
            if (currentText.isNotEmpty()) {
                runCatching {
                    sdfDate.isLenient = false
                    cal.time = sdfDate.parse(currentText)!!
                }
            }

            DatePickerDialog(
                this,
                { _, y, m, d ->
                    val picked = String.format(Locale.getDefault(), "%04d-%02d-%02d", y, m + 1, d)
                    til.error = null
                    et.setText(picked)
                    formValues[kode] = picked
                },
                cal.get(Calendar.YEAR),
                cal.get(Calendar.MONTH),
                cal.get(Calendar.DAY_OF_MONTH)
            ).show()
        }

        et.setOnClickListener { openPicker() }
        et.setOnFocusChangeListener { _, hasFocus -> if (hasFocus) openPicker() }
    }

    private fun setupTimeField(kode: Int, et: TextInputEditText, til: TextInputLayout) {
        et.isFocusable = false
        et.isFocusableInTouchMode = false
        et.isClickable = true

        val now = Calendar.getInstance()
        val def = String.format(
            Locale.getDefault(),
            "%02d:%02d:%02d",
            now.get(Calendar.HOUR_OF_DAY),
            now.get(Calendar.MINUTE),
            0
        )
        if (et.text.isNullOrBlank()) et.setText(def)
        formValues[kode] = et.text?.toString().orEmpty()

        fun openPicker() {
            val cal = Calendar.getInstance()
            val current = et.text?.toString().orEmpty().trim()
            if (current.isNotEmpty()) {
                val parts = current.split(":")
                if (parts.size >= 2) {
                    cal.set(Calendar.HOUR_OF_DAY, parts[0].toIntOrNull() ?: cal.get(Calendar.HOUR_OF_DAY))
                    cal.set(Calendar.MINUTE, parts[1].toIntOrNull() ?: cal.get(Calendar.MINUTE))
                    cal.set(Calendar.SECOND, parts.getOrNull(2)?.toIntOrNull() ?: 0)
                }
            }

            TimePickerDialog(
                this,
                { _, h, m ->
                    val picked = String.format(Locale.getDefault(), "%02d:%02d:%02d", h, m, 0)
                    til.error = null
                    et.setText(picked)
                    formValues[kode] = picked
                },
                cal.get(Calendar.HOUR_OF_DAY),
                cal.get(Calendar.MINUTE),
                true
            ).show()
        }

        et.setOnClickListener { openPicker() }
        et.setOnFocusChangeListener { _, hasFocus -> if (hasFocus) openPicker() }
    }

    private fun setupDateTimeField(kode: Int, et: TextInputEditText, til: TextInputLayout) {
        et.isFocusable = false
        et.isFocusableInTouchMode = false
        et.isClickable = true

        val nowStr = sdfDateTime.format(Calendar.getInstance().time)
        if (et.text.isNullOrBlank()) et.setText(nowStr)
        formValues[kode] = et.text?.toString().orEmpty()

        fun openDateThenTime() {
            val cal = Calendar.getInstance()

            val currentText = et.text?.toString().orEmpty().trim()
            if (currentText.isNotEmpty()) {
                runCatching {
                    sdfDateTime.isLenient = false
                    cal.time = sdfDateTime.parse(currentText)!!
                }
            }

            DatePickerDialog(
                this,
                { _, y, m, d ->
                    TimePickerDialog(
                        this,
                        { _, hh, mm ->
                            cal.set(Calendar.YEAR, y)
                            cal.set(Calendar.MONTH, m)
                            cal.set(Calendar.DAY_OF_MONTH, d)
                            cal.set(Calendar.HOUR_OF_DAY, hh)
                            cal.set(Calendar.MINUTE, mm)
                            cal.set(Calendar.SECOND, 0)

                            val picked = sdfDateTime.format(cal.time)
                            til.error = null
                            et.setText(picked)
                            formValues[kode] = picked
                        },
                        cal.get(Calendar.HOUR_OF_DAY),
                        cal.get(Calendar.MINUTE),
                        true
                    ).show()
                },
                cal.get(Calendar.YEAR),
                cal.get(Calendar.MONTH),
                cal.get(Calendar.DAY_OF_MONTH)
            ).show()
        }

        et.setOnClickListener { openDateThenTime() }
        et.setOnFocusChangeListener { _, hasFocus -> if (hasFocus) openDateThenTime() }
    }

    // =========================
    // Validasi Form Dinamis (PAKAI ID JENIS)
    // =========================
    private fun validateDynamicForm(details: List<KomunikasiDetail>): Boolean {
        val fields = details
            .filter { it.is_aktif == 1 }
            .sortedBy { it.urutan ?: Int.MAX_VALUE }

        // clear error
        fieldTilByKode.values.forEach { it.error = null }
        listInputEtByKode.values.forEach { it.error = null }
        lampiranTvErrorByKode.values.forEach {
            it.text = ""
            it.visibility = View.GONE
        }

        for (d in fields) {
            if (d.is_wajib != 1) continue

            val kode = d.kode ?: continue
            val label = d.isian?.trim().orEmpty().ifBlank { "Field" }
            val jenisId = d.id_jenis_isian ?: continue
            val value = formValues[kode]

            val valid = when (jenisId) {
                4 -> value is Int // angka (default 0 valid)
                5 -> value is Double // pecahan (default 0.00 valid)
                2 -> (value as? String)?.isNotBlank() == true // tanggal
                1 -> { // waktu yyyy-MM-dd HH:mm:ss
                    val s = (value as? String).orEmpty().trim()
                    s.isNotBlank() && runCatching {
                        sdfDateTime.isLenient = false
                        sdfDateTime.parse(s) != null
                    }.getOrDefault(false)
                }
                3 -> { // jam HH:mm:ss
                    val s = (value as? String).orEmpty().trim()
                    s.isNotBlank() && Regex("""^\d{2}:\d{2}:\d{2}$""").matches(s)
                }
                10 -> (value as? List<*>)?.isNotEmpty() == true // list
                11 -> (value as? List<*>)?.isNotEmpty() == true // lampiran
                0, 6 -> (value as? String)?.isNotBlank() == true // teks/string
                else -> (value as? String)?.isNotBlank() == true
            }

            if (!valid) {
                when (jenisId) {
                    10 -> listInputEtByKode[kode]?.error = "Wajib diisi"
                    11 -> {
                        lampiranTvErrorByKode[kode]?.apply {
                            text = "Wajib lampirkan minimal 1 file"
                            visibility = View.VISIBLE
                        }
                    }
                    else -> fieldTilByKode[kode]?.error = "Wajib diisi"
                }
                showSnack("Field wajib belum diisi: $label")
                return false
            }
        }

        return true
    }

    // =========================
    // Build komunikasiDetail payload (sesuai ID)
    // =========================
    private fun buildKomunikasiDetailPayload(details: List<KomunikasiDetail>): List<Map<String, Any?>> {
        val fields = details
            .filter { it.is_aktif == 1 }
            .sortedBy { it.urutan ?: Int.MAX_VALUE }

        return fields.mapNotNull { d ->
            val kode = d.kode ?: return@mapNotNull null
            val jenisId = d.id_jenis_isian ?: return@mapNotNull null

            val rawValue = formValues[kode]

            val isianForServer: Any? = when (jenisId) {
                4 -> ((rawValue as? Int) ?: 0).toString()

                5 -> {
                    val v = (rawValue as? Double) ?: 0.0
                    String.format(Locale.US, "%.2f", v)
                }

                2 -> (rawValue as? String).orEmpty() // yyyy-MM-dd

                1 -> (rawValue as? String).orEmpty() // yyyy-MM-dd HH:mm:ss

                3 -> (rawValue as? String).orEmpty() // HH:mm:ss

                10 -> { // list => JSON [{"text":"a"},...]
                    val items = rawValue as? List<*>
                    val arr = items.orEmpty()
                        .mapNotNull { it?.toString()?.trim() }
                        .filter { it.isNotBlank() }
                        .map { mapOf("text" to it) }
                    Gson().toJson(arr)
                }

                11 -> {
                    // lampiran => isian metadata JSON (opsional), file fisiknya via multipart
                    val atts = (rawValue as? List<FormAttachment>).orEmpty()
                    val meta = atts.map { mapOf("name" to it.fileName, "mime" to it.mimeType) }
                    Gson().toJson(meta)
                }

                0, 6 -> rawValue?.toString() // teks (multiline) / string
                else -> rawValue?.toString()
            }

            mapOf(
                "kode" to kode,
                "id_jenis_isian" to jenisId,
                "isian" to isianForServer
            )
        }
    }

    private fun buildJsonDataBody(
        actionItem: AddActionItem,
        selectedRecipients: List<Pegawai>,
        komunikasiDetail: List<Map<String, Any?>>
    ): RequestBody {
        val payload = mapOf(
            "kode" to actionItem.id,
            "tentang" to actionItem.idTentang,
            "topic" to actionItem.idKomunikasi,
            "uraian" to "",
            "kepada" to selectedRecipients.map { it.kode },
            "komunikasiDetail" to komunikasiDetail
        )

        val json = Gson().toJson(payload)
        return json.toRequestBody("text/plain".toMediaType())
    }

    // =========================
    // Lampiran -> Multipart
    // =========================
    private fun collectLampiranParts(): List<MultipartBody.Part> {
        val parts = mutableListOf<MultipartBody.Part>()
        formValues.forEach { (kodeDetail, v) ->
            val atts = (v as? List<*>)?.filterIsInstance<FormAttachment>().orEmpty()
            for (att in atts) {
                val part = uriToMultipart(
                    uri = att.uri,
                    fileName = att.fileName,
                    mimeType = att.mimeType,
                    fieldName = "isian_$kodeDetail"   // ✅ penting!
                )
                if (part != null) parts.add(part)
            }
        }

        return parts
    }

    private fun uriToMultipart(
        uri: android.net.Uri,
        fileName: String,
        mimeType: String,
        fieldName: String
    ): MultipartBody.Part? {
        return runCatching {
            val input = contentResolver.openInputStream(uri) ?: return null

            val outFile = File(cacheDir, "${System.currentTimeMillis()}_$fileName")
            outFile.outputStream().use { out ->
                input.use { it.copyTo(out) }
            }

            val reqBody = outFile.asRequestBody(mimeType.toMediaType())
            MultipartBody.Part.createFormData(fieldName, fileName, reqBody)
        }.getOrNull()
    }

    private fun readUriMeta(uri: android.net.Uri): FormAttachment? {
        val cr = contentResolver
        val mime = cr.getType(uri) ?: "application/octet-stream"

        var name: String? = null
        cr.query(uri, arrayOf(OpenableColumns.DISPLAY_NAME), null, null, null)?.use { c ->
            if (c.moveToFirst()) {
                name = c.getString(0)
            }
        }
        val fileName = name ?: "attachment"

        return FormAttachment(uri = uri, fileName = fileName, mimeType = mime)
    }

    // =========================
    // Existing stuff
    // =========================
    private fun initData() {
        val idTentang = actionItem.idTentang
        val idTipeKomunikasi = actionItem.idKomunikasi
        val userData = Gson().fromJson(Preferences.getUserData(this@AddTemplateActionActivity),
            Pengguna::class.java)

        APIMain.require().selectionServices.recipients(
            Preferences.getAccessToken(this), idTipeKomunikasi, idTentang
        ).enqueue(object : Callback<ArrayList<Pegawai>> {
            override fun onResponse(
                call: Call<ArrayList<Pegawai>>,
                response: Response<ArrayList<Pegawai>>
            ) {
                if (response.isSuccessful) {
                    val body = response.body().orEmpty()

                    // ✅ buang pengirim dari list
                    val myKode = userData.pegawai?.kode?.trim().orEmpty()
                    val filtered = body.filter { p ->
                        p.kode.trim() != myKode
                    }

                    recipientOptions.clear()
                    recipientOptions.addAll(filtered)

                    selectedRecipients.clear()
                    selectedRecipients.addAll(filtered)
                    renderRecipients()
                    return
                }

                val raw = runCatching { response.errorBody()?.string().orEmpty() }.getOrDefault("")
                val expired = raw.contains("Signature has expired", true) || raw.contains("token_expired", true)

                val message = when {
                    (response.code() == 401 || response.code() == 500) && expired -> {
                        forceLogoutAndGoLogin(this@AddTemplateActionActivity)
                        "Session expired. Please login again."
                    }
                    response.code() == 400 -> runCatching {
                        JsonParser.parseString(raw).asJsonObject["message"].asString
                    }.getOrDefault("Bad request")
                    else -> "${response.code()}, ${response.message()}"
                }

                showSnack(message)
            }

            override fun onFailure(call: Call<ArrayList<Pegawai>>, t: Throwable) {
                showSnack(t.message.toString())
            }
        })
    }

    private fun setupActions() {
        onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
            override fun handleOnBackPressed() {
                handleBackPress(0)
            }
        })

        ibBack.setOnClickListener { handleBackPress(0) }

        tvAddRecipient.setOnClickListener {
            if (isNetworkAvailable(this)) {
                showProgressDialog(true)
                APIMain.require().selectionServices.allRecipient(
                    Preferences.getAccessToken(this)
                ).enqueue(object : Callback<ArrayList<Pegawai>> {
                    override fun onResponse(
                        call: Call<ArrayList<Pegawai>>,
                        response: Response<ArrayList<Pegawai>>
                    ) {
                        showProgressDialog(false)
                        if (response.isSuccessful) {
                            val body = response.body().orEmpty()

                            val userData = Gson().fromJson(Preferences.getUserData(this@AddTemplateActionActivity),
                                Pengguna::class.java)

                            val filtered = body.filter { p ->
                                p.kode.trim() != userData.pegawai?.kode
                            }

                            showRecipientPickerDialog(ArrayList(filtered))
                            return
                        }

                        val raw = runCatching { response.errorBody()?.string().orEmpty() }.getOrDefault("")
                        val expired = raw.contains("Signature has expired", true) || raw.contains("token_expired", true)

                        val message = when {
                            (response.code() == 401 || response.code() == 500) && expired -> {
                                forceLogoutAndGoLogin(this@AddTemplateActionActivity)
                                "Session expired. Please login again."
                            }
                            response.code() == 400 -> runCatching {
                                JsonParser.parseString(raw).asJsonObject["message"].asString
                            }.getOrDefault("Bad request")
                            else -> "${response.code()}, ${response.message()}"
                        }

                        showSnack(message)
                    }

                    override fun onFailure(call: Call<ArrayList<Pegawai>>, t: Throwable) {
                        showProgressDialog(false)
                        showSnack(t.message.toString())
                    }
                })

            } else {
                showProgressDialog(false)
                Snackbar.make(
                    findViewById(android.R.id.content),
                    ContextCompat.getString(this@AddTemplateActionActivity, R.string.no_internet_message),
                    Snackbar.LENGTH_LONG
                ).show()
            }
        }

        btSend.setOnClickListener {
            val details = actionItem.komunikasi_detail.orEmpty()
            if (details.isEmpty()) {
                showSnack("Tidak ada form yang bisa dikirim")
                return@setOnClickListener
            }

            if (!validateDynamicForm(details)) return@setOnClickListener

            if (selectedRecipients.isEmpty()) {
                selectedRecipients.add(Pegawai(
                    kode = "0000000000000000",
                    nama = "Genie",
                    outlet = null,
                    jabatan = null,
                    mulai_bekerja = "0000-00-000",
                    id_kelamin = "L",
                    outlets = null
                ))
            }

            val komunikasiDetail = buildKomunikasiDetailPayload(details)
            val dataBody = buildJsonDataBody(actionItem, selectedRecipients, komunikasiDetail)
            val fileParts = collectLampiranParts()

            APIMain.require().actionServices.add(
                token = Preferences.getAccessToken(this),
                data = dataBody,
                files = fileParts
            ).enqueue(object : Callback<Message> {
                override fun onResponse(call: Call<Message>, response: Response<Message>) {
                    if (response.isSuccessful) {
                        showSnack(response.body()?.message ?: "Berhasil")
                        finish()
                        return
                    }
                    val raw = runCatching { response.errorBody()?.string().orEmpty() }.getOrDefault("")
                    showSnack(raw.ifBlank { "${response.code()} ${response.message()}" })
                }

                override fun onFailure(call: Call<Message>, t: Throwable) {
                    showSnack(t.message ?: "Gagal")
                }
            })
        }
    }

    private fun renderRecipients() {
        val hasData = selectedRecipients.isNotEmpty()
        rvRecipient.visibility = if (hasData) View.VISIBLE else View.GONE
        tvEmpty.visibility = if (hasData) View.GONE else View.VISIBLE
        recipientAdapter.submitList(selectedRecipients.toList())
    }

    private fun showSnack(message: String) {
        Snackbar.make(findViewById(android.R.id.content), message, Snackbar.LENGTH_LONG).show()
    }

    private fun showRecipientPickerDialog(allRecipient: ArrayList<Pegawai>) {
        val userData = Gson().fromJson(Preferences.getUserData(this@AddTemplateActionActivity),
            Pengguna::class.java)

        val cleaned = allRecipient.filter { it.kode.trim() != userData.pegawai?.kode }
        if (cleaned.isEmpty()) {
            showSnack("Daftar penerima kosong")
            return
        }

        val baseList = cleaned.filter { ar ->
            selectedRecipients.none { it.kode == ar.kode }
        }

        if (baseList.isEmpty()) {
            showSnack("Semua penerima sudah dipilih")
            return
        }

        val v = layoutInflater.inflate(R.layout.dialog_recipient_picker, null)
        val rv = v.findViewById<RecyclerView>(R.id.rv_recipient_picker)
        val sv = v.findViewById<androidx.appcompat.widget.SearchView>(R.id.sv_recipient)

        val dialog = MaterialAlertDialogBuilder(this)
            .setTitle("Pilih Penerima")
            .setView(v)
            .setNegativeButton("Tutup", null)
            .create()

        val pickerAdapter = RecipientPickerAdapter { picked ->
            val exists = selectedRecipients.any { it.kode == picked.kode }
            if (exists) {
                showSnack("Penerima sudah dipilih")
                return@RecipientPickerAdapter
            }

            selectedRecipients.add(picked)
            renderRecipients()
            dialog.dismiss()
        }

        rv.layoutManager = LinearLayoutManager(this)
        rv.adapter = pickerAdapter
        rv.setHasFixedSize(true)

        pickerAdapter.submitList(baseList)

        fun applyFilter(query: String?) {
            val q = query.orEmpty().trim()
            if (q.isEmpty()) {
                pickerAdapter.submitList(baseList)
                return
            }

            val filtered = baseList.filter { p ->
                p.nama.contains(q, ignoreCase = true) || p.kode.contains(q, ignoreCase = true)
            }

            pickerAdapter.submitList(filtered)
        }

        sv.setOnQueryTextListener(object : androidx.appcompat.widget.SearchView.OnQueryTextListener {
            override fun onQueryTextSubmit(query: String?): Boolean {
                applyFilter(query)
                return true
            }

            override fun onQueryTextChange(newText: String?): Boolean {
                applyFilter(newText)
                return true
            }
        })

        dialog.show()
        sv.requestFocus()
    }
}