package com.jrz.nfcapp.ui.read

import android.animation.ValueAnimator
import android.content.ClipData
import android.content.ClipboardManager
import android.content.Context
import android.nfc.Tag
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.animation.DecelerateInterpolator
import androidx.fragment.app.Fragment
import com.google.android.material.snackbar.Snackbar
import com.jrz.nfcapp.R
import com.jrz.nfcapp.databinding.FragmentReadBinding
import com.jrz.nfcapp.model.TagDump
import com.jrz.nfcapp.util.NfcHelper
import java.io.File
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale

class ReadFragment : Fragment() {

    private var _binding: FragmentReadBinding? = null
    private val binding get() = _binding!!

    private var currentDump: TagDump? = null
    private var pulseAnimator: ValueAnimator? = null

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
        _binding = FragmentReadBinding.inflate(inflater, container, false)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        binding.btnCopyUid.setOnClickListener {
            currentDump?.let { dump ->
                val cm = requireContext().getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
                cm.setPrimaryClip(ClipData.newPlainText("NFC UID", dump.formattedUid()))
                Snackbar.make(binding.root, getString(R.string.uid_copied), Snackbar.LENGTH_SHORT).show()
            }
        }

        binding.btnSaveDump.setOnClickListener {
            currentDump?.let { saveDump(it) }
        }

        startPulseAnimation()
    }

    override fun onResume() {
        super.onResume()
        if (currentDump == null) startPulseAnimation()
    }

    override fun onPause() {
        super.onPause()
        stopPulseAnimation()
    }

    private fun startPulseAnimation() {
        pulseAnimator?.cancel()
        val animator = ValueAnimator.ofFloat(0f, 1f).apply {
            duration = 2000
            repeatCount = ValueAnimator.INFINITE
            interpolator = DecelerateInterpolator()

            addUpdateListener { anim ->
                val p = anim.animatedValue as Float

                // Ring 1: leads
                val p1 = p
                binding.ring1.alpha = (1f - p1) * 0.7f
                binding.ring1.scaleX = 0.3f + p1 * 0.7f
                binding.ring1.scaleY = 0.3f + p1 * 0.7f

                // Ring 2: delayed by 33%
                val p2 = ((p + 0.33f) % 1f)
                binding.ring2.alpha = (1f - p2) * 0.5f
                binding.ring2.scaleX = 0.3f + p2 * 0.7f
                binding.ring2.scaleY = 0.3f + p2 * 0.7f

                // Ring 3: delayed by 66%
                val p3 = ((p + 0.66f) % 1f)
                binding.ring3.alpha = (1f - p3) * 0.3f
                binding.ring3.scaleX = 0.3f + p3 * 0.7f
                binding.ring3.scaleY = 0.3f + p3 * 0.7f
            }
        }
        animator.start()
        pulseAnimator = animator
    }

    private fun stopPulseAnimation() {
        pulseAnimator?.cancel()
        pulseAnimator = null
        listOf(binding.ring1, binding.ring2, binding.ring3).forEach { it.alpha = 0f }
    }

    fun onTagScanned(tag: Tag) {
        try {
            val dump = NfcHelper.readTag(tag)
            currentDump = dump
            requireActivity().runOnUiThread { displayDump(dump) }
        } catch (e: Exception) {
            requireActivity().runOnUiThread {
                binding.tvStatus.text = getString(R.string.error_read, e.message)
            }
        }
    }

    private fun displayDump(dump: TagDump) {
        stopPulseAnimation()

        binding.tvStatus.text = "Tag erkannt  ·  ${dump.rawBytes.size} Bytes"

        // UID
        binding.cardUid.visibility = View.VISIBLE
        binding.tvUid.text = dump.formattedUid()

        // Tag Type
        binding.cardTagType.visibility = View.VISIBLE
        binding.tvTagType.text = dump.tagType
        binding.tvTechList.text = dump.techList.joinToString("\n") { "• ${it.substringAfterLast('.')}" }

        // NDEF
        if (dump.ndefMessage != null || dump.ndefCapacity > 0) {
            binding.cardNdef.visibility = View.VISIBLE
            binding.tvNdefContent.text = buildString {
                appendLine(dump.ndefContentSummary())
                if (dump.ndefMaxSize > 0) {
                    appendLine("\nKapazität: ${dump.ndefCapacity} / ${dump.ndefMaxSize} Bytes")
                    append("Schreibbar: ${if (dump.isNdefWritable) "Ja" else "Nein"}")
                }
            }.trimEnd()
        }

        // Raw + Diagnose log
        binding.cardRaw.visibility = View.VISIBLE
        binding.tvRawPages.text = buildString {
            if (dump.rawPages.isNotEmpty()) {
                appendLine(dump.rawPagesFormatted())
                appendLine()
            }
            appendLine("── Diagnose ──")
            append(dump.debugLog)
        }

        binding.btnSaveDump.visibility = View.VISIBLE
    }

    private fun saveDump(dump: TagDump) {
        try {
            val sdf = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.getDefault())
            val filename = "jrz_dump_${sdf.format(Date())}.csv"
            val dir = requireContext().getExternalFilesDir(null) ?: requireContext().filesDir
            val file = File(dir, filename)
            file.writeText(dump.toCsvDump())
            Snackbar.make(binding.root, getString(R.string.dump_saved, file.absolutePath), Snackbar.LENGTH_LONG).show()
        } catch (e: Exception) {
            Snackbar.make(binding.root, "Speichern fehlgeschlagen: ${e.message}", Snackbar.LENGTH_LONG).show()
        }
    }

    override fun onDestroyView() {
        stopPulseAnimation()
        super.onDestroyView()
        _binding = null
    }
}
