package com.jrz.nfcapp.ui.clone

import android.nfc.Tag
import java.io.IOException
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import com.jrz.nfcapp.R
import com.jrz.nfcapp.databinding.FragmentCloneBinding
import com.jrz.nfcapp.model.TagDump
import com.jrz.nfcapp.util.NfcHelper

enum class CloneState { IDLE, READING_SOURCE, WRITING_TARGET }

class CloneFragment : Fragment() {

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

    var state: CloneState = CloneState.IDLE
        private set

    private var sourceDump: TagDump? = null

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

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

        binding.btnReadSource.setOnClickListener {
            state = CloneState.READING_SOURCE
            binding.tvSourceStatus.text = getString(R.string.clone_waiting_source)
            binding.btnReadSource.isEnabled = false
        }

        binding.btnWriteTarget.setOnClickListener {
            if (sourceDump == null) return@setOnClickListener
            state = CloneState.WRITING_TARGET
            binding.tvTargetStatus.text = getString(R.string.clone_waiting_target)
            binding.btnWriteTarget.isEnabled = false
        }
    }

    fun onTagScanned(tag: Tag) {
        when (state) {
            CloneState.READING_SOURCE -> readSource(tag)
            CloneState.WRITING_TARGET -> writeTarget(tag)
            CloneState.IDLE -> {}
        }
    }

    private fun readSource(tag: Tag) {
        Thread {
            try {
                val dump = NfcHelper.readTag(tag)
                sourceDump = dump
                requireActivity().runOnUiThread { onSourceRead(dump) }
            } catch (e: Exception) {
                requireActivity().runOnUiThread {
                    state = CloneState.IDLE
                    binding.tvSourceStatus.text = getString(R.string.error_read, e.message)
                    binding.btnReadSource.isEnabled = true
                }
            }
        }.start()
    }

    private fun onSourceRead(dump: TagDump) {
        state = CloneState.IDLE
        binding.btnReadSource.isEnabled = true
        binding.tvSourceStatus.text = getString(R.string.clone_source_ready, dump.rawBytes.size)
        binding.layoutSourceDetails.visibility = View.VISIBLE
        binding.tvSourceUid.text = "UID: ${dump.formattedUid()}"
        binding.tvSourceType.text = "Typ: ${dump.tagType}"
        val sizeInfo = buildString {
            if (dump.ndefMessage != null) append("NDEF: ${dump.ndefMessage.byteArrayLength} Bytes  ")
            if (dump.rawPages.isNotEmpty()) append("Pages: ${dump.rawPages.size} (${dump.rawBytes.size} Bytes)")
            if (dump.ndefMessage == null && dump.rawPages.isEmpty()) append("Keine lesbaren Daten")
        }
        binding.tvSourceSize.text = sizeInfo
        binding.btnWriteTarget.isEnabled = dump.ndefMessage != null || dump.rawPages.isNotEmpty()
        binding.tvTargetStatus.text = if (binding.btnWriteTarget.isEnabled)
            "Bereit zum Schreiben" else "Keine schreibbaren Daten"
    }

    private fun writeTarget(tag: Tag) {
        val dump = sourceDump ?: return
        Thread {
            try {
                when (NfcHelper.detectWriteMethod(tag)) {
                    NfcHelper.WriteMethod.NFC_V -> {
                        if (dump.rawPages.isEmpty()) throw IOException("Keine Quelldaten zum Schreiben")
                        NfcHelper.writeNfcV(tag, dump.rawPages)
                    }
                    NfcHelper.WriteMethod.ULTRALIGHT -> {
                        if (dump.rawPages.isEmpty()) throw IOException("Keine Quelldaten zum Schreiben")
                        NfcHelper.writeUltralight(tag, dump.rawPages)
                    }
                    NfcHelper.WriteMethod.NDEF,
                    NfcHelper.WriteMethod.NDEF_FORMATABLE -> {
                        val msg = dump.ndefMessage ?: throw IOException("Keine NDEF-Daten in Quelle")
                        NfcHelper.writeNdef(tag, msg)
                    }
                    NfcHelper.WriteMethod.MIFARE_CLASSIC ->
                        throw IOException("MIFARE Classic Schreiben benötigt Schlüssel")
                    NfcHelper.WriteMethod.UNSUPPORTED ->
                        throw IOException("Ziel-Tag unterstützt kein Schreiben")
                }
                requireActivity().runOnUiThread { onWriteSuccess() }
            } catch (e: Exception) {
                requireActivity().runOnUiThread { onWriteError(e.message ?: "Fehler") }
            }
        }.start()
    }

    private fun onWriteSuccess() {
        state = CloneState.IDLE
        binding.tvTargetStatus.text = getString(R.string.clone_success)
        binding.btnWriteTarget.isEnabled = true
    }

    private fun onWriteError(error: String) {
        state = CloneState.IDLE
        binding.tvTargetStatus.text = getString(R.string.error_write, error)
        binding.btnWriteTarget.isEnabled = true
    }

    // Extension for display
    private fun TagDump.formattedUid() = uid.uppercase()

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