package com.example.p3

import android.content.Context
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.drawable.BitmapDrawable
import android.util.Log
import androidx.annotation.DrawableRes
import androidx.core.content.ContextCompat
import androidx.core.graphics.createBitmap
import com.example.core.domain.Printer
import com.example.core.model.PrintEntity
import com.pos.sdk.printer.POIPrinterManager
import com.pos.sdk.printer.POIPrinterManager.IPrinterListener
import com.pos.sdk.printer.models.BitmapPrintLine
import com.pos.sdk.printer.models.PrintLine
import com.pos.sdk.printer.models.TextPrintLine
import dagger.hilt.android.qualifiers.ApplicationContext
import java.io.File
import javax.inject.Inject


class P3Printer @Inject constructor(
    @param:ApplicationContext private val context: Context,
) : Printer {
    companion object {
        private const val TAG = "Printer"

        // Printer state constants (should ideally come from the SDK if available)
        private const val PRINTER_STATE_ERROR = 4
        private const val DEFAULT_PRINT_GRAY = 2000
        private const val DEFAULT_LINE_SPACE = 5
    }

    /**
     * Prints a sample receipt for demonstration.
     */
    fun printSampleReceipt(context: Context) {
        // Use applicationContext to avoid potential memory leaks

        val printerManager = initialP3Printer()

        printerManager?.apply {
            setPrintGray(DEFAULT_PRINT_GRAY)
            setLineSpace(DEFAULT_LINE_SPACE)

            // Header
            addPrintLine(TextPrintLine("This is an example of a receipt", PrintLine.CENTER))

            // Reusable logo bitmap
            val logoBitmap = drawableToBitmap(context, android.R.drawable.btn_plus)
            val logoLine = logoBitmap?.let { BitmapPrintLine(it, PrintLine.CENTER) }

            logoLine?.let { addPrintLine(it) }

            // Address
            val addressFont = getFontPath("font")
            if (addressFont.isNotEmpty()) {
                setPrintFont(addressFont)
            } else {
                setPrintFont("/system/fonts/ComingSoon.ttf")
            }
            addPrintLine(
                TextPrintLine(
                    "Floor ** , Building **, No.*** LONG DONG Avenue, Pudong New District, Shanghai, China",
                    PrintLine.LEFT,
                    20
                )
            )

            // Transaction Details
            val detailFont = getFontPath("font")
            if (detailFont.isNotEmpty()) {
                setPrintFont(detailFont)
            } else {
                setPrintFont("/system/fonts/DroidSansMono.ttf")
            }
//            addPrintLine(createPrintRow("24 June 2025", "     Assistant 6", "815002", size = 18))
//            addPrintLine(createPrintRow("Item", "Quantity", "Price", size = 24, isBold = true))
//            addPrintLine(createPrintRow("Tomato", "1", "$2.08", size = 24))
//            addPrintLine(createPrintRow("Orange", "1", "$1.06", size = 24))
//
            // Footer
            addPrintLine(TextPrintLine("Total  $3.14", PrintLine.RIGHT))
            addPrintLine(TextPrintLine(""))
            logoLine?.let { addPrintLine(it) }
            addPrintLine(TextPrintLine(""))

            addPrintLine(
                TextPrintLine(
                    "Did you know you could have earned Rewards points on this purchase?",
                    PrintLine.CENTER
                )
            )
            addPrintLine(
                TextPrintLine(
                    "Simply sign up today for a Membership Card!",
                    PrintLine.CENTER
                )
            )

            logoLine?.let { addPrintLine(it) }
            addPrintLine(TextPrintLine(" ", 0, 100))

            val listener = object : IPrinterListener {
                override fun onStart() {
                    Log.d(TAG, "Print started")
                }

                override fun onFinish() {
                    Log.d(TAG, "Print finished")
                    close()
                }

                override fun onError(code: Int, msg: String?) {
                    Log.e(TAG, "Print error - code: $code, message: $msg")
                    close()
                }
            }

            beginPrint(listener)
        }
    }

    private fun initialP3Printer(): POIPrinterManager? {
        val printerManager = POIPrinterManager(context.applicationContext)
        printerManager.open()

        val state = printerManager.printerState
        Log.d(TAG, "Printer state = $state")

        if (state == PRINTER_STATE_ERROR) {
            Log.e(TAG, "Printer is in an error state ($state). Aborting print.")
            printerManager.close()
            return null
        }

        return printerManager
    }


    /**
     * Creates a row with left, center, and right aligned text.
     */
    private fun createPrintRow(
        label: String,
        value: String,
        size: Int,
        isBold: Boolean = false
    ): List<TextPrintLine> {
        return if (value.hasPersianLetters()) {

            listOf(
                TextPrintLine(label, PrintLine.LEFT, size, true),
                TextPrintLine(value, PrintLine.RIGHT, size, isBold)
            )
        } else {

            listOf(
                TextPrintLine(label, PrintLine.LEFT, size, true),
                TextPrintLine(value, PrintLine.LEFT, size, isBold)
            )
        }
    }

    private fun getFontPath(resourceName: String): String {
        return try {
            // Find resource ID by name (e.g., "font") in the "font" resource folder
            val resId = context.resources.getIdentifier(resourceName, "font", context.packageName)
            if (resId == 0) {
                Log.e(TAG, "Font resource not found: $resourceName")
                return ""
            }

            val fileName = "$resourceName.ttf"
            val fontFile = File(context.filesDir, fileName)
            if (!fontFile.exists()) {
                context.resources.openRawResource(resId).use { input ->
                    fontFile.outputStream().use { output ->
                        input.copyTo(output)
                    }
                }
            }
            fontFile.absolutePath
        } catch (e: Exception) {
            Log.e(TAG, "Error loading font from resources: $resourceName", e)
            ""
        }
    }

    override fun print(
        printEntities: List<PrintEntity>,
        @DrawableRes icon: Int
    ) {
        val printerManager = initialP3Printer()

        printerManager?.apply {
            setPrintGray(DEFAULT_PRINT_GRAY)
            setLineSpace(DEFAULT_LINE_SPACE)

            // Reusable logo bitmap
            val logoBitmap = drawableToBitmap(context, icon, 200)
            if (logoBitmap != null) {
                val logoLine = BitmapPrintLine(logoBitmap, PrintLine.CENTER)
                addPrintLine(logoLine)
                addPrintLine(TextPrintLine(" ", 0, 10))
            }

            val customFontPath = getFontPath("font")
            if (customFontPath.isNotEmpty()) {
                setPrintFont(customFontPath)
            } else {
                setPrintFont("/system/fonts/DroidSansMono.ttf") // Fallback
            }

            val divider = drawableToBitmap(context, com.example.core.R.drawable.horizontal_line_svgrepo_com__1_)

            printEntities.forEachIndexed { index, printEntity ->

                // Header
                printEntity.title?.let {title->
                    addPrintLine(
                        TextPrintLine(
                            title,
                            if (title.hasPersianLetters()) PrintLine.LEFT else PrintLine.RIGHT
                        )
                    )
                }

                printEntity.items?.let {items->
                    items.forEach { itemEntity ->
                        addPrintLine(
                            createPrintRow(
                                label = itemEntity.label,
                                value = itemEntity.value,
                                size = 16,
                            )
                        )
                    }
                }
                if (divider != null && printEntities.lastIndex > index) {
                    val dividerLine = BitmapPrintLine(divider, PrintLine.CENTER)
                    addPrintLine(dividerLine)

                }
            }


            addPrintLine(TextPrintLine(" ", 0, 60))

            val listener = object : IPrinterListener {
                override fun onStart() {
                    Log.d(TAG, "Print started")
                }

                override fun onFinish() {
                    Log.d(TAG, "Print finished")
                    close()
                }

                override fun onError(code: Int, msg: String?) {
                    Log.e(TAG, "Print error - code: $code, message: $msg")
                    close()
                }
            }

            beginPrint(listener)
        }
    }


//    private fun fixForPrinter(input: String): String {
//        val LRM = '\u200E' // کنترل جهت
//
//        return input
//            .toPersianDigits() // همونی که قبل دادم
//            .replace(Regex("(\\d+)")) { matchResult ->
//                "$LRM${matchResult.value}$LRM"
//            }
//    }

    private fun String.hasPersianLetters(): Boolean {
        return Regex("[\\u0621-\\u0628\\u062A-\\u063A\\u0641-\\u0642\\u0644-\\u0648\\u067E\\u0686\\u0698\\u06A9\\u06AF\\u06CC\\u0647]").containsMatchIn(
            this
        )
    }

    private fun drawableToBitmap(context: Context, @DrawableRes drawableId: Int): Bitmap? {
        val drawable = ContextCompat.getDrawable(context, drawableId) ?: return null

        if (drawable is BitmapDrawable) {
            return drawable.bitmap
        }

        val bitmap = createBitmap(
            drawable.intrinsicWidth.coerceAtLeast(1),
            drawable.intrinsicHeight.coerceAtLeast(1)
        )
        val canvas = Canvas(bitmap)
        drawable.setBounds(0, 0, canvas.width, canvas.height)
        drawable.draw(canvas)

        return bitmap
    }

    private fun drawableToBitmap(
        context: Context,
        @DrawableRes drawableId: Int,
        maxWidth: Int = 300
    ): Bitmap? {
        val drawable = ContextCompat.getDrawable(context, drawableId) ?: return null

        val original = if (drawable is BitmapDrawable) {
            drawable.bitmap
        } else {
            val bitmap = createBitmap(
                drawable.intrinsicWidth.coerceAtLeast(1),
                drawable.intrinsicHeight.coerceAtLeast(1)
            )
            val canvas = Canvas(bitmap)
            drawable.setBounds(0, 0, canvas.width, canvas.height)
            drawable.draw(canvas)
            bitmap
        }

        // 👇 scale با حفظ نسبت
        val ratio = maxWidth.toFloat() / original.width
        val width = maxWidth
        val height = (original.height * ratio).toInt()

        return Bitmap.createScaledBitmap(original, width, height, true)
    }
}
