package com.amz.genie.activities

import android.content.Intent
import android.os.Bundle
import android.widget.ImageView
import android.widget.TextView
import androidx.activity.OnBackPressedCallback
import androidx.activity.result.contract.ActivityResultContracts
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.amz.genie.R
import com.amz.genie.adapters.GeneralDetailAdapter
import com.amz.genie.helpers.Preferences
import com.amz.genie.helpers.Utils.forceLogoutAndGoLogin
import com.amz.genie.helpers.Utils.isFemale
import com.amz.genie.helpers.Utils.isNetworkAvailable
import com.amz.genie.models.GeneralDetailResponse
import com.amz.genie.models.GeneralThreadItem
import com.amz.genie.models.Message
import com.amz.genie.models.Pengguna
import com.amz.genie.services.APIMain
import com.google.android.material.imageview.ShapeableImageView
import com.google.android.material.snackbar.Snackbar
import com.google.gson.Gson
import com.google.gson.JsonParser
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response

class GeneralDetailActivity : BaseActivity() {

    private lateinit var ivBack: ImageView
    private lateinit var sivUser: ShapeableImageView
    private lateinit var tvName: TextView
    private lateinit var tvJobDesk: TextView
    private lateinit var tvOutlet: TextView
    private lateinit var rvgeneralDetail: RecyclerView

    private lateinit var adapter: GeneralDetailAdapter

    private val allItems = mutableListOf<GeneralThreadItem>()
    private var currentPage = 1
    private val perPage = 30
    private var hasMore = true
    private var isLoading = false

    private var counterpartKode: String? = null
    private var childNeedsRefresh = false

    private val subDetailLauncher =
        registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
            val needsRefresh = result.data?.getBooleanExtra("needs_refresh", false) ?: false
            if (result.resultCode == RESULT_OK && needsRefresh) {
                childNeedsRefresh = true
                refreshListFromFirstPage()
            }
        }

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

        initUI(savedInstanceState)
        setupActions()
    }

    private fun initUI(savedInstanceState: Bundle?) {
        ivBack = findViewById(R.id.ib_back_general_detail)
        sivUser = findViewById(R.id.siv_employee_general_detail)
        tvName = findViewById(R.id.tv_employeename_general_detail)
        tvJobDesk = findViewById(R.id.tv_jobdesk_general_detail)
        tvOutlet = findViewById(R.id.tv_outlet_general_detail)
        rvgeneralDetail = findViewById(R.id.rv_general_detail)

        val userData = Gson().fromJson(Preferences.getUserData(this), Pengguna::class.java)
        val myKodePegawai = userData.pegawai?.kode ?: ""

        adapter = GeneralDetailAdapter(
            kodePegawai = myKodePegawai,
            onItemClick = { item ->
                // ✅ klik item: mark as read dulu kalau unread, baru buka detail
                markReadIfNeeded(item) { openSubDetail(item) }
            },
            onDetailClick = { item ->
                // ✅ klik tombol detail juga sama
                markReadIfNeeded(item) { openSubDetail(item) }
            }
        )

        rvgeneralDetail.layoutManager = LinearLayoutManager(this)
        rvgeneralDetail.adapter = adapter
        rvgeneralDetail.setHasFixedSize(true)

        if (intent.hasExtra("data")) {
            initData()
        }
    }

    private fun bearerToken(): String {
        val raw = Preferences.getAccessToken(this).orEmpty().trim()
        // ✅ aman: kalau sudah ada "Bearer " jangan double
        return if (raw.startsWith("Bearer ", true)) raw else "Bearer $raw"
    }

    private fun openSubDetail(item: GeneralThreadItem) {
        val intent = Intent(this, GeneralSubDetailActivity::class.java)
        val dataJson = Gson().toJson(item, GeneralThreadItem::class.java)
        intent.putExtra("data", dataJson)
        intent.putExtra("counterpart", counterpartKode)
        subDetailLauncher.launch(intent)
    }

    private fun setupActions() {
        onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
            override fun handleOnBackPressed() {
                if (childNeedsRefresh) {
                    setResult(RESULT_OK, Intent().putExtra("needs_refresh", true))
                }
                handleBackPress(0)
            }
        })

        ivBack.setOnClickListener {
            if (childNeedsRefresh) {
                setResult(RESULT_OK, Intent().putExtra("needs_refresh", true))
            }
            handleBackPress(0)
        }

        rvgeneralDetail.addOnScrollListener(object : RecyclerView.OnScrollListener() {
            override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
                super.onScrolled(recyclerView, dx, dy)
                if (dy <= 0) return

                val lm = recyclerView.layoutManager as? LinearLayoutManager ?: return
                val totalItemCount = lm.itemCount
                val lastVisible = lm.findLastVisibleItemPosition()

                // trigger saat tinggal 5 item lagi
                if (!isLoading && hasMore && totalItemCount > 0 && lastVisible >= totalItemCount - 5) {
                    loadPage(currentPage + 1)
                }
            }
        })
    }

    private fun initData() {
        val intentDataJson = intent.getStringExtra("data") ?: return
        val data = Gson().fromJson(intentDataJson, GeneralThreadItem::class.java)

        counterpartKode = data.counterpart

        val tipe = data.tipe.uppercase()
        val aksi = data.aksi
        val reaksi = data.reaksi

        if (tipe == "REAKSI" && reaksi != null) {
            tvName.text = reaksi.pembuat.nama
            tvJobDesk.text = reaksi.pembuat.jabatan?.nama ?: "-"
            tvOutlet.text = reaksi.pembuat.outlet?.nama ?: "-"

            val female = isFemale(reaksi.pembuat.id_kelamin)
            sivUser.setImageResource(if (female) R.drawable.ic_woman else R.drawable.ic_man)
        } else {
            tvName.text = aksi.pembuat.nama
            tvJobDesk.text = aksi.pembuat.jabatan?.nama ?: "-"
            tvOutlet.text = aksi.pembuat.outlet?.nama ?: "-"

            val female = isFemale(aksi.pembuat.id_kelamin)
            sivUser.setImageResource(if (female) R.drawable.ic_woman else R.drawable.ic_man)
        }

        if (!isNetworkAvailable(this)) {
            showSnack(getString(R.string.no_internet_message))
            return
        }

        refreshListFromFirstPage()
    }

    private fun refreshListFromFirstPage() {
        allItems.clear()
        adapter.submitRawTimeline(emptyList())
        currentPage = 1
        hasMore = true
        isLoading = false
        loadPage(1)
    }

    private fun loadPage(page: Int) {
        val cp = counterpartKode ?: run {
            showSnack("counterpart_kode kosong")
            return
        }

        if (isLoading) return
        if (!hasMore && page != 1) return
        if (page <= currentPage && page != 1) return

        isLoading = true
        showProgressDialog(true)

        APIMain.require().generalServices
            .detail(bearerToken(), cp, page, perPage)
            .enqueue(object : Callback<GeneralDetailResponse> {

                override fun onResponse(
                    call: Call<GeneralDetailResponse>,
                    response: Response<GeneralDetailResponse>
                ) {
                    showProgressDialog(false)
                    isLoading = false

                    if (response.isSuccessful) {
                        val body = response.body()
                        val newItems = body?.items.orEmpty()

                        val meta = body?.meta
                        val metaPage = meta?.page
                        val metaHasMore = meta?.has_more
                        val metaNextPage = meta?.next_page

                        currentPage = metaPage ?: page

                        hasMore = when {
                            metaHasMore != null -> metaHasMore
                            metaNextPage != null -> true
                            else -> newItems.size >= perPage
                        }

                        if (page == 1) allItems.clear()

                        // ✅ anti-duplikat (penting banget karena backend union bisa double kalau ada data ganda)
                        val existingKeys = allItems.map { keyOf(it) }.toHashSet()
                        val filtered = newItems.filter { existingKeys.add(keyOf(it)) }

                        allItems.addAll(filtered)
                        adapter.submitRawTimeline(allItems.toList())

                        if (allItems.isEmpty()) showSnack("Tidak ada pesan")
                        return
                    }

                    handleError(response)
                }

                override fun onFailure(call: Call<GeneralDetailResponse>, t: Throwable) {
                    showProgressDialog(false)
                    isLoading = false
                    showSnack(t.message ?: "Terjadi kesalahan")
                }
            })
    }

    private fun keyOf(item: GeneralThreadItem): String {
        return if (item.tipe.equals("REAKSI", true)) {
            "R_${item.reaksi?.id ?: -1}"
        } else {
            "A_${item.aksi.id}"
        }
    }

    private fun handleError(response: Response<GeneralDetailResponse>) {
        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@GeneralDetailActivity)
                "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)
    }

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

    // ============================================================
    // MARK AS READ (FIX: REAKSI pakai reaksi.id, AKSI pakai aksi.id)
    // ============================================================
    private fun getReadPayload(item: GeneralThreadItem): Pair<Int, String>? {
        return if (item.tipe.equals("REAKSI", true)) {
            val rxId = item.reaksi?.id ?: return null
            Pair(rxId, "REAKSI")
        } else {
            Pair(item.aksi.id, "AKSI")
        }
    }

    private fun markReadIfNeeded(item: GeneralThreadItem, thenRun: () -> Unit) {
        // backend GetgeneralDetail kamu ngirim is_unread / is_aktif
        val isUnread = (item.is_unread == true) || ((item.is_aktif ?: 1) == 0)
        if (!isUnread) {
            thenRun()
            return
        }

        val payload = getReadPayload(item)
        if (payload == null) {
            thenRun()
            return
        }

        val (id, tipe) = payload

        APIMain.require().generalServices
            .readed(bearerToken(), id, tipe)
            .enqueue(object : Callback<Message> {
                override fun onResponse(call: Call<Message>, response: Response<Message>) {
                    if (response.isSuccessful) {
                        applyLocalReadState(id, tipe)
                    }
                    thenRun()
                }

                override fun onFailure(call: Call<Message>, t: Throwable) {
                    thenRun()
                }
            })
    }

    private fun applyLocalReadState(id: Int, tipe: String) {
        val upper = tipe.uppercase()
        var changed = false

        for (i in allItems.indices) {
            val it = allItems[i]
            val match = if (upper == "REAKSI") {
                it.tipe.equals("REAKSI", true) && it.reaksi?.id == id
            } else {
                !it.tipe.equals("REAKSI", true) && it.aksi.id == id
            }

            if (match) {
                allItems[i] = it.copy(
                    is_aktif = 1,
                    is_unread = false
                )
                changed = true
                break
            }
        }

        if (changed) adapter.submitRawTimeline(allItems.toList())
    }
}