package de.data_it_solution.brotherprinthelper

import android.Manifest
import android.bluetooth.BluetoothAdapter
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.graphics.Color
import android.os.Build
import android.os.Bundle
import android.widget.ProgressBar
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import com.brother.sdk.lmprinter.*
import com.brother.sdk.lmprinter.setting.PrintImageSettings
import com.brother.sdk.lmprinter.setting.PTPrintSettings
import com.google.zxing.BarcodeFormat
import com.google.zxing.MultiFormatWriter
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File
import java.io.FileOutputStream

/**
 * BrotherPrintHelper MainActivity
 *
 * Empfängt Barcode-Daten per Intent und druckt sie auf Brother P-touch E560BT
 *
 * Intent-Aufruf von PWA:
 * brotherprint://print?barcode=1234567890
 *
 * @author Eduard Wisch <data@data-it-solution.de>
 */
class MainActivity : AppCompatActivity() {

    private var barcodeValue: String? = null
    private var productRef: String? = null
    private lateinit var statusText: TextView
    private lateinit var progressBar: ProgressBar

    companion object {
        private const val REQUEST_BLUETOOTH_PERMISSION = 1
    }

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

        statusText = findViewById(R.id.statusText)
        progressBar = findViewById(R.id.progressBar)

        // Intent-Daten auslesen
        handleIntent(intent)

        // Bluetooth-Permissions prüfen
        if (checkBluetoothPermissions()) {
            // Permissions vorhanden → Drucken starten
            startPrinting()
        } else {
            // Permissions anfragen
            requestBluetoothPermissions()
        }
    }

    override fun onNewIntent(intent: Intent?) {
        super.onNewIntent(intent)
        handleIntent(intent)
    }

    /**
     * Intent auswerten und Barcode-Daten extrahieren
     */
    private fun handleIntent(intent: Intent?) {
        intent?.data?.let { uri ->
            // brotherprint://print?barcode=1234567890&ref=PROD-123
            barcodeValue = uri.getQueryParameter("barcode")
            productRef = uri.getQueryParameter("ref")

            if (barcodeValue.isNullOrEmpty()) {
                showToast("Kein Barcode-Wert im Intent gefunden!")
                finish()
                return
            }

            showToast("Barcode empfangen: $barcodeValue")
        }

        // Fallback: Barcode aus Intent Extras
        if (barcodeValue == null) {
            barcodeValue = intent?.getStringExtra("barcode")
            productRef = intent?.getStringExtra("ref")
        }
    }

    /**
     * Bluetooth-Permissions prüfen
     */
    private fun checkBluetoothPermissions(): Boolean {
        return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            // Android 12+
            ContextCompat.checkSelfPermission(
                this,
                Manifest.permission.BLUETOOTH_CONNECT
            ) == PackageManager.PERMISSION_GRANTED &&
            ContextCompat.checkSelfPermission(
                this,
                Manifest.permission.BLUETOOTH_SCAN
            ) == PackageManager.PERMISSION_GRANTED
        } else {
            // Android < 12
            ContextCompat.checkSelfPermission(
                this,
                Manifest.permission.BLUETOOTH
            ) == PackageManager.PERMISSION_GRANTED &&
            ContextCompat.checkSelfPermission(
                this,
                Manifest.permission.BLUETOOTH_ADMIN
            ) == PackageManager.PERMISSION_GRANTED
        }
    }

    /**
     * Bluetooth-Permissions anfragen
     */
    private fun requestBluetoothPermissions() {
        val permissions = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            arrayOf(
                Manifest.permission.BLUETOOTH_CONNECT,
                Manifest.permission.BLUETOOTH_SCAN
            )
        } else {
            arrayOf(
                Manifest.permission.BLUETOOTH,
                Manifest.permission.BLUETOOTH_ADMIN
            )
        }

        ActivityCompat.requestPermissions(
            this,
            permissions,
            REQUEST_BLUETOOTH_PERMISSION
        )
    }

    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)

        if (requestCode == REQUEST_BLUETOOTH_PERMISSION) {
            if (grantResults.all { it == PackageManager.PERMISSION_GRANTED }) {
                // Permissions erteilt → Drucken starten
                startPrinting()
            } else {
                showToast("Bluetooth-Berechtigung erforderlich!")
                finish()
            }
        }
    }

    /**
     * Druckvorgang starten
     */
    private fun startPrinting() {
        if (barcodeValue == null) {
            showToast("Kein Barcode-Wert vorhanden!")
            finish()
            return
        }

        updateStatus("Erstelle Barcode...")

        // Druck in Background-Thread ausführen
        CoroutineScope(Dispatchers.IO).launch {
            try {
                // Barcode-Bitmap erstellen mit Produkt-Referenz
                val barcodeBitmap = generateBarcodeBitmap(barcodeValue!!, productRef)

                updateStatus("Verbinde mit Drucker...")

                // Mit Drucker verbinden und drucken
                val success = printBarcodeViaBluetooth(barcodeBitmap)

                withContext(Dispatchers.Main) {
                    if (success) {
                        showToast("Druck erfolgreich!")
                    } else {
                        showToast("Druckfehler!")
                    }
                    // Nach 1 Sekunde App beenden und zurück zur PWA
                    finish()
                }

            } catch (e: Exception) {
                withContext(Dispatchers.Main) {
                    showToast("Fehler: ${e.message}")
                    finish()
                }
            }
        }
    }

    /**
     * Barcode-Bitmap erstellen mit Produkt-Referenz und Barcode-Text
     */
    private fun generateBarcodeBitmap(content: String, ref: String?): Bitmap {
        val writer = MultiFormatWriter()
        // Barcode ohne Text generieren
        val bitMatrix = writer.encode(content, BarcodeFormat.CODE_128, 800, 300)

        val barcodeWidth = bitMatrix.width
        val barcodeHeight = bitMatrix.height

        // Platz für Referenz oben (80px) + Text unten (100px)
        val refHeight = if (!ref.isNullOrEmpty()) 80 else 0
        val textHeight = 100
        val totalHeight = refHeight + barcodeHeight + textHeight

        // Bitmap mit Platz für Ref + Barcode + Text
        val bitmap = Bitmap.createBitmap(barcodeWidth, totalHeight, Bitmap.Config.RGB_565)
        val canvas = android.graphics.Canvas(bitmap)

        // Weißer Hintergrund
        canvas.drawColor(Color.WHITE)

        // Produkt-Referenz FETT oben zeichnen
        if (!ref.isNullOrEmpty()) {
            val refPaint = android.graphics.Paint().apply {
                color = Color.BLACK
                textSize = 56f
                textAlign = android.graphics.Paint.Align.CENTER
                typeface = android.graphics.Typeface.create(android.graphics.Typeface.MONOSPACE, android.graphics.Typeface.BOLD)
            }
            canvas.drawText(ref, (barcodeWidth / 2).toFloat(), 60f, refPaint)
        }

        // Barcode zeichnen (versetzt um refHeight)
        for (x in 0 until barcodeWidth) {
            for (y in 0 until barcodeHeight) {
                if (bitMatrix[x, y]) {
                    canvas.drawPoint(x.toFloat(), (y + refHeight).toFloat(), android.graphics.Paint().apply { color = Color.BLACK })
                }
            }
        }

        // Barcode-Wert unter Barcode zeichnen
        val textPaint = android.graphics.Paint().apply {
            color = Color.BLACK
            textSize = 48f
            textAlign = android.graphics.Paint.Align.CENTER
            typeface = android.graphics.Typeface.MONOSPACE
        }
        canvas.drawText(content, (barcodeWidth / 2).toFloat(), (refHeight + barcodeHeight + 65).toFloat(), textPaint)

        return bitmap
    }

    /**
     * Barcode über Bluetooth drucken
     */
    private fun printBarcodeViaBluetooth(bitmap: Bitmap): Boolean {
        try {
            // Bluetooth Channel öffnen (P-touch E560BT MAC-Adresse wird automatisch gefunden)
            val bluetoothAdapter = BluetoothAdapter.getDefaultAdapter()
            if (bluetoothAdapter == null) {
                updateStatus("Kein Bluetooth-Adapter gefunden!")
                return false
            }

            updateStatus("Suche Brother Drucker...")

            // Suche nach gepaartem Brother Drucker
            val pairedDevices = bluetoothAdapter.bondedDevices
            var brotherDevice: android.bluetooth.BluetoothDevice? = null

            for (device in pairedDevices) {
                updateStatus("Gefunden: ${device.name}")
                if (device.name != null && device.name.contains("PT-E", ignoreCase = true)) {
                    brotherDevice = device
                    updateStatus("Brother Drucker gefunden: ${device.name} (${device.address})")
                    break
                }
            }

            if (brotherDevice == null) {
                updateStatus("FEHLER: Kein Brother Drucker gepaart! Bitte PT-E560BT in Bluetooth-Settings paaren.")
                Thread.sleep(5000) // 5 Sekunden warten damit User Meldung lesen kann
                return false
            }

            // Bluetooth Channel mit MAC-Adresse erstellen
            val channel = Channel.newBluetoothChannel(brotherDevice.address, bluetoothAdapter)

            updateStatus("Verbinde mit ${brotherDevice.name}...")

            val result: PrinterDriverGenerateResult = PrinterDriverGenerator.openChannel(channel)
            if (result.error.code != OpenChannelError.ErrorCode.NoError) {
                updateStatus("Fehler beim Öffnen: ${result.error.code}")
                return false
            }

            val printerDriver = result.driver

            updateStatus("Konfiguriere Drucker...")

            // Drucker-Einstellungen für P-touch E560BT (24mm TZe-Band)
            val printSettings = PTPrintSettings(PrinterModel.PT_E560BT)
            printSettings.workPath = filesDir.absolutePath

            // Label-Größe auf 24mm setzen (muss mit eingelegtem Band übereinstimmen!)
            printSettings.labelSize = PTPrintSettings.LabelSize.Width24mm

            // Barcode längs auf Band drucken (90° Rotation)
            printSettings.setImageRotation(PrintImageSettings.Rotation.Rotate90)

            // Schnitt-Einstellungen: Halbschnitt am Anfang, Vollschnitt am Ende
            printSettings.isAutoCut = true  // Vollschnitt am Ende
            printSettings.isHalfCut = true  // Halbschnitt-Modus aktivieren
            printSettings.isCutPause = false

            // Spezial-Tape für TZe-Bänder DEAKTIVIEREN
            printSettings.isSpecialTapePrint = false

            // Chain-Print deaktivieren für einzelne Labels
            printSettings.isChainPrint = false

            updateStatus("Drucke Barcode...")

            // Bitmap in temporäre Datei speichern
            val tempFile = File.createTempFile("barcode", ".png", cacheDir)
            FileOutputStream(tempFile).use { out ->
                bitmap.compress(Bitmap.CompressFormat.PNG, 100, out)
            }

            // Drucken
            val printError: PrintError = printerDriver.printImage(tempFile.path, printSettings)

            // Verbindung schließen
            printerDriver.closeChannel()

            // Temporäre Datei löschen
            tempFile.delete()

            if (printError.code != PrintError.ErrorCode.NoError) {
                // Benutzerfreundliche Fehlermeldung je nach ErrorCode
                val errorMsg = when (printError.code.toString()) {
                    "SetLabelSizeError" -> "FEHLER: Falsches Label-Format!\nBitte 24mm TZe-Band einlegen."
                    "NoCoverError" -> "FEHLER: Drucker-Abdeckung offen!"
                    "NoMediaError" -> "FEHLER: Kein Band eingelegt!"
                    "CutterError" -> "FEHLER: Problem mit Schneide-Mechanismus!"
                    "BatteryError" -> "FEHLER: Batterie schwach oder fehlt!"
                    else -> "Druckfehler: ${printError.code}"
                }
                updateStatus(errorMsg)
                Thread.sleep(5000) // 5 Sekunden warten
                return false
            }

            return true

        } catch (e: Exception) {
            updateStatus("Exception: ${e.message}")
            return false
        }
    }

    /**
     * Status-Text aktualisieren
     */
    private fun updateStatus(message: String) {
        runOnUiThread {
            statusText.text = message
        }
    }

    /**
     * Toast-Nachricht anzeigen
     */
    private fun showToast(message: String) {
        runOnUiThread {
            Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
        }
    }
}
