package com.jrz.nfcapp.model

import android.nfc.NdefMessage

data class TagDump(
    val uid: String,
    val tagType: String,
    val techList: List<String>,
    val ndefMessage: NdefMessage?,
    val ndefCapacity: Int,
    val ndefMaxSize: Int,
    val isNdefWritable: Boolean,
    val rawPages: List<ByteArray>,
    val rawBytes: ByteArray,
    val debugLog: String = ""
) {
    fun formattedUid(): String = uid.uppercase()

    fun shortTechList(): String = techList
        .map { it.substringAfterLast('.') }
        .joinToString(", ")

    fun ndefContentSummary(): String {
        val msg = ndefMessage ?: return "Kein NDEF"
        return buildString {
            msg.records.forEachIndexed { i, record ->
                append("Record $i: TNF=${record.tnf} ")
                val type = String(record.type)
                append("Type=$type ")
                val payload = record.payload
                when {
                    type == "T" -> {
                        // NDEF Text record
                        val langLen = payload[0].toInt() and 0x3F
                        append("→ \"${String(payload, langLen + 1, payload.size - langLen - 1)}\"\n")
                    }
                    type == "U" -> {
                        // NDEF URI record
                        val prefix = URI_PREFIXES.getOrElse(payload[0].toInt() and 0xFF) { "" }
                        append("→ $prefix${String(payload, 1, payload.size - 1)}\n")
                    }
                    else -> {
                        append("→ ${payload.toHex()}\n")
                    }
                }
            }
        }.trimEnd()
    }

    fun rawPagesFormatted(): String = buildString {
        rawPages.forEachIndexed { i, page ->
            append("Blk %03d: ".format(i))
            append(page.toHex())
            append("  ")
            page.forEach { b ->
                val c = (b.toInt() and 0xFF).toChar()
                append(if (c.code in 32..126) c else '.')
            }
            append('\n')
        }
    }.trimEnd()

    fun toCsvDump(): String = buildString {
        appendLine("# NFC Tag Dump")
        appendLine("UID,$uid")
        appendLine("Type,$tagType")
        appendLine("Technologies,${techList.joinToString("|")}")
        appendLine("NDEF_Capacity,$ndefCapacity")
        appendLine("NDEF_MaxSize,$ndefMaxSize")
        appendLine("NDEF_Writable,$isNdefWritable")
        appendLine()
        appendLine("# Raw Pages")
        rawPages.forEachIndexed { i, page ->
            appendLine("Page_$i,${page.toHex()}")
        }
        if (ndefMessage != null) {
            appendLine()
            appendLine("# NDEF Records")
            ndefMessage.records.forEachIndexed { i, rec ->
                appendLine("Record_${i}_TNF,${rec.tnf}")
                appendLine("Record_${i}_Type,${rec.type.toHex()}")
                appendLine("Record_${i}_Payload,${rec.payload.toHex()}")
            }
        }
    }

    companion object {
        val URI_PREFIXES = mapOf(
            0x00 to "", 0x01 to "http://www.", 0x02 to "https://www.",
            0x03 to "http://", 0x04 to "https://", 0x05 to "tel:",
            0x06 to "mailto:", 0x07 to "ftp://anonymous:anonymous@",
            0x08 to "ftp://ftp.", 0x09 to "ftps://", 0x0A to "sftp://",
            0x0B to "smb://", 0x0C to "nfs://", 0x0D to "ftp://",
            0x0E to "dav://", 0x0F to "news:", 0x10 to "telnet://",
            0x11 to "imap:", 0x12 to "rtsp://", 0x13 to "urn:",
            0x14 to "pop:", 0x15 to "sip:", 0x16 to "sips:",
            0x17 to "tftp:", 0x18 to "btspp://", 0x19 to "btl2cap://",
            0x1A to "btgoep://", 0x1B to "tcpobex://", 0x1C to "irdaobex://",
            0x1D to "file://", 0x1E to "urn:epc:id:", 0x1F to "urn:epc:tag:",
            0x20 to "urn:epc:pat:", 0x21 to "urn:epc:raw:", 0x22 to "urn:epc:",
            0x23 to "urn:nfc:"
        )
    }
}

fun ByteArray.toHex(): String = joinToString(" ") { "%02X".format(it.toInt() and 0xFF) }
fun String.hexToBytes(): ByteArray {
    val s = replace(" ", "").replace(":", "")
    return ByteArray(s.length / 2) { i -> s.substring(i * 2, i * 2 + 2).toInt(16).toByte() }
}
