package com.amz.genie.activities

import android.Manifest
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Bundle
import android.view.View
import android.widget.ArrayAdapter
import android.widget.AutoCompleteTextView
import android.widget.ImageButton
import android.widget.TextView
import androidx.activity.OnBackPressedCallback
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.content.ContextCompat
import androidx.core.content.FileProvider
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.amz.genie.R
import com.amz.genie.adapters.AttachmentAdapter
import com.amz.genie.adapters.RecipientAdapter
import com.amz.genie.adapters.RecipientPickerAdapter
import com.amz.genie.helpers.Preferences
import com.amz.genie.helpers.Utils.forceLogoutAndGoLogin
import com.amz.genie.helpers.Utils.isNetworkAvailable
import com.amz.genie.helpers.Utils.uriToMultipartPart
import com.amz.genie.models.AttachmentItem
import com.amz.genie.models.Message
import com.amz.genie.models.Pegawai
import com.amz.genie.models.Pengguna
import com.amz.genie.models.PostAksi
import com.amz.genie.models.Tentang
import com.amz.genie.models.TipeKomunikasi
import com.amz.genie.services.APIMain
import com.google.android.material.button.MaterialButton
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.snackbar.Snackbar
import com.google.android.material.textfield.TextInputEditText
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.JsonParser
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.MultipartBody
import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import java.io.File

class AddCustomActionActivity : BaseActivity() {

    private lateinit var ibBack: ImageButton
    private lateinit var actvTipeKomunikasi: AutoCompleteTextView
    private lateinit var actvTentang: AutoCompleteTextView

    private lateinit var rvRecipient: RecyclerView
    private lateinit var tvEmpty: TextView
    private lateinit var tietDescription: TextInputEditText
    private lateinit var btAttachment: MaterialButton
    private lateinit var btSend: MaterialButton
    private lateinit var llAttachmentsContainer: View
    private lateinit var rvAttachments: RecyclerView
    private lateinit var tvAddRecipient: TextView
    private lateinit var attachmentAdapter: AttachmentAdapter

    private lateinit var recipientAdapter: RecipientAdapter
    private val recipientOptions = mutableListOf<Pegawai>()
    private val selectedRecipients = mutableListOf<Pegawai>()
    private var idTipeKomunikasi = ""
    private var idTentang = ""
    private var cameraOutputUri: Uri? = null
    private val attachments = mutableListOf<AttachmentItem>()
    private val takePictureLauncher =
        registerForActivityResult(ActivityResultContracts.TakePicture()) { success ->
            if (success) {
                cameraOutputUri?.let { addAttachment(it) }
            }
        }

    private val pickFileLauncher =
        registerForActivityResult(ActivityResultContracts.OpenDocument()) { uri ->
            if (uri != null) {
                contentResolver.takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION)
                addAttachment(uri)
            }
        }

    private val requestCameraPermissionLauncher =
        registerForActivityResult(ActivityResultContracts.RequestPermission()) { granted ->
            if (granted) {
                openCamera()
            } else {
                showSnack("Izin kamera ditolak")
            }
        }

    private fun openCameraWithPermission() {
        val granted = ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) ==
                PackageManager.PERMISSION_GRANTED

        if (granted) {
            openCamera()
        } else {
            requestCameraPermissionLauncher.launch(Manifest.permission.CAMERA)
        }
    }

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

        initUI(savedInstanceState)
        renderAttachments()
        setupDropdowns()
    }

    private fun initUI(savedInstanceState: Bundle?) {
        ibBack = findViewById(R.id.ib_back_add_custom_action)
        actvTipeKomunikasi = findViewById(R.id.actv_tipe_komunikasi_add_custom_action)
        actvTentang = findViewById(R.id.actv_tentang_add_custom_action)
        rvRecipient = findViewById(R.id.rv_recipient_add_custom_action)
        tvEmpty = findViewById(R.id.tv_empty_add_custom_action)
        btAttachment = findViewById(R.id.btn_attachment_add_custom_action)
        btSend = findViewById(R.id.btn_send_add_custom_action)
        llAttachmentsContainer = findViewById(R.id.ll_attachments_container_add_custom_action)
        rvAttachments = findViewById(R.id.rv_attachments_add_custom_action)
        tvAddRecipient = findViewById(R.id.tv_lbl_recipient_add_custom_action)
        tietDescription = findViewById(R.id.et_description_add_custom_action)

        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

        attachmentAdapter = AttachmentAdapter { item ->
            attachments.remove(item)
            renderAttachments()
        }

        rvAttachments.layoutManager = GridLayoutManager(this, 2)
        rvAttachments.adapter = attachmentAdapter

        setupActions()
    }

    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 setupDropdowns() {
        val communicationTypeList = ArrayList<String>()
        APIMain.require().selectionServices.communicationTypes(
                Preferences.getAccessToken(this))
            .enqueue(object: Callback<ArrayList<TipeKomunikasi>> {
                override fun onResponse(
                    call: Call<ArrayList<TipeKomunikasi>>,
                    response: Response<ArrayList<TipeKomunikasi>>
                ) {
                    if (response.isSuccessful) {
                        val body = response.body().orEmpty()
                        communicationTypeList.clear()
                        body.forEach { communicationTypeList.add(it.tipe_komunikasi) }

                        val adapterTipe = ArrayAdapter(this@AddCustomActionActivity,
                            android.R.layout.simple_list_item_1,
                            communicationTypeList)
                        actvTipeKomunikasi.setAdapter(adapterTipe)

                        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@AddCustomActionActivity)
                            "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<TipeKomunikasi>>,
                    t: Throwable
                ) {
                    showSnack(t.message ?: "Terjadi kesalahan")
                }

            })
    }

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

        ibBack.setOnClickListener { handleBackPress(0) }

        actvTipeKomunikasi.setOnItemClickListener { parent, _, position, _ ->
            val selected = parent.getItemAtPosition(position).toString()
            idTipeKomunikasi = when (selected) {
                "Bertanya" -> "A"
                "Informasi" -> "I"
                "Laporan" -> "L"
                "Approval" -> "P"
                "Pengajuan" -> "R"
                "Penugasan" -> "T"
                else -> ""
            }

            val tentangList = ArrayList<String>()
            APIMain.require().selectionServices.tentangs(
                Preferences.getAccessToken(this), idTipeKomunikasi)
                .enqueue(object: Callback<ArrayList<Tentang>> {
                    override fun onResponse(
                        call: Call<ArrayList<Tentang>>,
                        response: Response<ArrayList<Tentang>>
                    ) {
                        if (response.isSuccessful) {
                            val body = response.body().orEmpty()
                            body.forEach { tentangList.add(it.tentang) }

                            val adapterTentang = ArrayAdapter(this@AddCustomActionActivity,
                                android.R.layout.simple_list_item_1,tentangList)
                            actvTentang.setAdapter(adapterTentang)

                            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@AddCustomActionActivity)
                                "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<Tentang>>,
                        t: Throwable
                    ) {
                        showSnack(t.message.toString())
                    }

                })
        }

        actvTipeKomunikasi.setOnClickListener { actvTipeKomunikasi.showDropDown() }

        actvTentang.setOnClickListener { actvTentang.showDropDown() }

        actvTentang.setOnItemClickListener { parent, _, position, _ ->
            selectedRecipients.clear()
            renderRecipients()

            val selectedTentang = parent.getItemAtPosition(position).toString()
            idTentang = when (selectedTentang) {
                "Aturan" -> "A"
                "Barang" -> "B"
                "Kegiatan" -> "G"
                "Jadwal" -> "J"
                "Keadaan" -> "K"
                "Layanan" -> "L"
                "Orang" -> "O"
                "Sistem" -> "S"
                "Transaksi" -> "T"
                "Uang" -> "U"
                else -> ""
            }

            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()
                            val userData = Gson().fromJson(Preferences.getUserData(this@AddCustomActionActivity),
                                Pengguna::class.java)

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

                            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@AddCustomActionActivity)
                                "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())
                    }

                })
        }

        btAttachment.setOnClickListener {
            showAttachmentPickerDialog()
        }

        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@AddCustomActionActivity),
                                    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@AddCustomActionActivity)
                                    "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@AddCustomActionActivity,
                        R.string.no_internet_message),
                    Snackbar.LENGTH_LONG
                ).show()
            }
        }

        btSend.setOnClickListener {
            showProgressDialog(true)
            val semuaKodePegawai: List<String> = selectedRecipients.map { it.kode }

            val newAksi = PostAksi(
                null, semuaKodePegawai, idTentang, idTipeKomunikasi,
                tietDescription.text.toString(), null
            )

            val gson = GsonBuilder()
                .serializeNulls()
                .create()

            val jsonData = gson.toJson(newAksi)
            val dataBody: RequestBody =
                jsonData.toRequestBody("application/json; charset=utf-8".toMediaType())

            val filesParts: List<MultipartBody.Part> =
                attachments.map { a ->
                    this.uriToMultipartPart(
                        partName = "files",
                        uri = a.uri,
                        filenameOverride = a.name
                    )
                }
            val filesPartsOrNull = filesParts.takeIf { it.isNotEmpty() }
            APIMain.require().actionServices.add(
                token = Preferences.getAccessToken(this@AddCustomActionActivity),
                data = dataBody,
                files = filesPartsOrNull
            ).enqueue(object : Callback<Message> {
                override fun onResponse(call: Call<Message>, response: Response<Message>) {
                    if (response.isSuccessful) {
                        showProgressDialog(false)
                        showSnack("Berhasil kirim aksi")
                        finish()
                        return
                    }

                    showProgressDialog(false)

                    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@AddCustomActionActivity)
                            "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<Message>, t: Throwable) {
                    showProgressDialog(false)
                    showSnack(t.message ?: "Gagal kirim")
                }
            })
        }

    }

    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@AddCustomActionActivity),
            Pengguna::class.java)

        // ✅ buang pengirim dulu
        val cleaned = allRecipient.filter { it.kode.trim() != userData.pegawai?.kode }

        if (cleaned.isEmpty()) {
            showSnack("Daftar penerima kosong")
            return
        }

        // Base list: hanya yang belum ada di selectedRecipients
        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)

        // tampil awal
        pickerAdapter.submitList(baseList)

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

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

    private fun showAttachmentPickerDialog() {
        val items = arrayOf("Kamera", "File Manager")

        MaterialAlertDialogBuilder(this)
            .setTitle("Pilih Attachment")
            .setItems(items) { _, which ->
                when (which) {
                    0 -> openCameraWithPermission()
                    1 -> openFileManager()
                }
            }
            .setNegativeButton("Batal", null)
            .show()
    }

    private fun openCamera() {
        val imageFile = File.createTempFile(
            "ATTACH_",
            ".jpg",
            cacheDir
        )

        val uri = FileProvider.getUriForFile(
            this,
            "${packageName}.fileprovider",
            imageFile
        )

        cameraOutputUri = uri
        takePictureLauncher.launch(uri)
    }

    private fun openFileManager() {
        pickFileLauncher.launch(arrayOf("image/*", "application/pdf"))
    }

    private fun addAttachment(uri: Uri) {
        if (attachments.any { it.uri == uri }) {
            showSnack("Lampiran sudah ditambahkan")
            return
        }
        val mime = contentResolver.getType(uri).orEmpty()
        val name = queryDisplayName(uri) ?: "Attachment"
        attachments.add(AttachmentItem(uri, name, mime))
        renderAttachments()
    }

    private fun renderAttachments() {
        val hasData = attachments.isNotEmpty()
        llAttachmentsContainer.visibility = if (hasData) View.VISIBLE else View.GONE

        attachmentAdapter.submitList(attachments.toList())
        rvAttachments.visibility = if (hasData) View.VISIBLE else View.GONE

        val count = attachments.size
        btAttachment.text = if (count > 0) "Lampiran ($count)" else getString(R.string.lbl_lampiran)
    }

    private fun queryDisplayName(uri: Uri): String? {
        val projection = arrayOf(android.provider.OpenableColumns.DISPLAY_NAME)
        return runCatching {
            contentResolver.query(uri, projection, null, null, null)?.use { cursor ->
                val nameIndex = cursor.getColumnIndex(android.provider.OpenableColumns.DISPLAY_NAME)
                if (nameIndex == -1) return@use null
                cursor.moveToFirst()
                cursor.getString(nameIndex)
            }
        }.getOrNull()
    }
}