package com.assimilate.alltrans.curview

import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Matrix
import android.graphics.PixelFormat
import android.media.Image
import android.media.ImageReader
import android.os.Build
import android.os.Handler
import android.os.Looper
import android.util.Log
import android.view.Gravity
import android.view.MotionEvent
import android.view.View
import android.view.ViewConfiguration
import android.view.WindowManager
import android.widget.ImageView
import com.assimilate.alltrans.R
import com.assimilate.alltrans.common.TextGraphic
import com.assimilate.alltrans.common.TextRecognitionProcessor
import com.assimilate.alltrans.common.VisionImageProcessor
import com.google.mlkit.vision.text.Text
import com.google.mlkit.vision.text.chinese.ChineseTextRecognizerOptions
import java.io.IOException

class FloatingView(
    private val context: Context
) : TextRecognitionProcessor.TextRecognitionCallback {

    private var isAttachedToWindow = false
    private var imageProcessor: VisionImageProcessor? = null
    private var graphicOverlay: GraphicOverlay? = null
    private var imageReader: ImageReader? = null

    private var onMovePointListener: OnMovePointListener? = null
    private var onClickListener: OnClickListener? = null

    private val handler = Handler(Looper.getMainLooper())
    private val fadeRunnable = Runnable { fadeAndStickToEdge() }

    private val originalImageResId = R.drawable.ic_sus_little_ball
    private val edgeImageResId = R.drawable.ic_sus_little_ball_tie
    private val moveImageResId = R.drawable.ic_sus_little_search
    private var imageView: ImageView = ImageView(context).apply {
        setImageResource(originalImageResId)
    }

    private var lastX = 0
    private var lastY = 0
    private var hasCapturedScreenshot = false

    init {
        setupTouchListener()
        handler.postDelayed(fadeRunnable, 2333)

        // 初始化语言识别
        imageProcessor = TextRecognitionProcessor(
            context,
            ChineseTextRecognizerOptions.Builder().build(), this
        )

        graphicOverlay = GraphicOverlay(context, null)
    }

    interface OnMovePointListener {
        fun onMovePoint()
    }

    interface OnClickListener {
        fun onClick()
    }

    fun setOnMovePointListener(listener: OnMovePointListener) {
        this.onMovePointListener = listener
    }

    fun setOnClickListener(listener: OnClickListener) {
        this.onClickListener = listener
    }

    private val windowManager: WindowManager =
        context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
    private val screenWidth: Int = context.resources.displayMetrics.widthPixels
    private val originalImageWidth: Int =
        BitmapFactory.decodeResource(context.resources, R.drawable.ic_sus_little_ball).width

    private val fullScreenParams = WindowManager.LayoutParams(
        WindowManager.LayoutParams.MATCH_PARENT,
        WindowManager.LayoutParams.MATCH_PARENT,
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
        } else {
            WindowManager.LayoutParams.TYPE_PHONE
        },
        WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or
                WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN or
                WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS or
                WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR,
        PixelFormat.TRANSLUCENT
    )

    private val params: WindowManager.LayoutParams = WindowManager.LayoutParams(
        WindowManager.LayoutParams.WRAP_CONTENT,
        WindowManager.LayoutParams.WRAP_CONTENT,
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
        } else {
            WindowManager.LayoutParams.TYPE_PHONE
        },
        WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
        PixelFormat.TRANSLUCENT
    ).apply {
        gravity = Gravity.TOP or Gravity.START
        x = screenWidth - originalImageWidth
        y = 500
    }

    private fun setupTouchListener() {
        imageView.setOnTouchListener(object : View.OnTouchListener {
            private var initialX = 0
            private var initialY = 0
            private var initialTouchX = 0f
            private var initialTouchY = 0f
            private var isClick = true
            private var downTime: Long = 0
            private val touchSlop = ViewConfiguration.get(context).scaledTouchSlop
            private val maxClickDuration = 500 // 最大点击时间（毫秒）


            override fun onTouch(v: View?, event: MotionEvent): Boolean {
                when (event.action) {
                    MotionEvent.ACTION_DOWN -> {
                        isClick = true
                        downTime = System.currentTimeMillis()
                        initialX = params.x
                        initialY = params.y
                        initialTouchX = event.rawX
                        initialTouchY = event.rawY
                        handler.removeCallbacks(fadeRunnable)
                        imageView.alpha = 1.0f
                        imageView.setImageResource(originalImageResId)

                        return true
                    }

                    MotionEvent.ACTION_UP -> {
                        val upTime = System.currentTimeMillis()
                        val duration = upTime - downTime

                        handler.postDelayed(fadeRunnable, 3000)
                        imageView.setImageResource(originalImageResId)
                        stickToEdge()

                        imageView.performClick()
                        if (isClick && duration < maxClickDuration) {
                            onClickListener?.onClick()
                        } else {
                            hasCapturedScreenshot = false
                        }

                        if (graphicOverlay?.isAttachedToWindow == true) {
                            try {
                                windowManager.removeView(graphicOverlay)
                            } catch (e: IllegalArgumentException) {
                                Log.e("FloatingView", "View not attached to window manager", e)
                            }
                        } else {
                            Log.e(
                                "FloatingView",
                                "Attempted to remove a view that is not attached to the window manager"
                            )
                        }

                        windowManager.updateViewLayout(imageView, params)
                        return true
                    }

                    MotionEvent.ACTION_MOVE -> {
                        val dx = event.rawX - initialTouchX
                        val dy = event.rawY - initialTouchY

                        if (Math.abs(dx) > touchSlop || Math.abs(dy) > touchSlop) {
                            isClick = false
                        }

                        if (!isClick) {
                            // 将图片的位置设置为手指触摸点的上方
                            params.x = initialX + dx.toInt()
                            params.y =
                                initialY + dy.toInt() - imageView.height / 2  // 调整y坐标，使图片位于手指的上方
                            onMovePointListener?.onMovePoint()

                            imageView.setImageResource(moveImageResId)

                            lastX = params.x + imageView.width / 2
                            lastY = params.y + imageView.height / 2

                            try {
                                updateGraphicOverlay(lastX, lastY)
                                windowManager.updateViewLayout(imageView, params)
                            } catch (e: IllegalArgumentException) {
                                Log.e("FloatingView", "View not attached to window manager", e)
                            }
                        }
                        return true
                    }
                }

                return false
            }
        })
    }

    private fun updateGraphicOverlay(x: Int, y: Int) {
        graphicOverlay?.let {
            synchronized(it.lock) {
                val graphics = it.graphics
                for (graphic in graphics) {
                    if (graphic.contains(x.toFloat(), y.toFloat())) {
                        if (graphic is TextGraphic) {
                            graphic.showTextBlockAt(x.toFloat(), y.toFloat())
                        }
                        Log.d("GraphicOverlay", "Graphic on move!")
                        break
                    }
                }
            }
        }
    }

    private fun captureAndProcessScreenshot(reader: ImageReader?) {
        reader?.let { it ->
            val image = it.acquireLatestImage()
            image?.let {
                val bitmap = imageToBitmap(it)
                image.close()
                tryReloadAndDetectInImage(bitmap)
            }
        }
    }

    private fun stickToEdge() {
        val screenWidth = context.resources.displayMetrics.widthPixels
        val midPoint = screenWidth / 2
        params.x = if (params.x < midPoint) {
            0
        } else {
            screenWidth - originalImageWidth
        }
        if (isAttachedToWindow) {
            try {
                windowManager.updateViewLayout(imageView, params)
            } catch (e: IllegalArgumentException) {
                Log.e("FloatingView", "View not attached to window manager", e)
            }
        }
    }

    private fun fadeAndStickToEdge() {
        imageView.animate().alpha(0.5f).setDuration(500).withEndAction {
            val screenWidth = context.resources.displayMetrics.widthPixels
            val originalImageWidth =
                BitmapFactory.decodeResource(context.resources, originalImageResId).width
            val edgeImageWidth =
                BitmapFactory.decodeResource(context.resources, edgeImageResId).width

            val isLeftEdge = params.x + originalImageWidth / 2 < screenWidth / 2
            params.x = if (isLeftEdge) {
                0
            } else {
                screenWidth - edgeImageWidth
            }
            if (isAttachedToWindow) {
                try {
                    windowManager.updateViewLayout(imageView, params)
                } catch (e: IllegalArgumentException) {
                    Log.e("FloatingView", "View not attached to window manager", e)
                }
            }
            updateImageForEdge(imageView, isLeftEdge)
        }.start()
    }

    private fun updateImageForEdge(imageView: ImageView, isLeftEdge: Boolean) {
        val bitmap = BitmapFactory.decodeResource(context.resources, edgeImageResId)
        if (isLeftEdge) {
            imageView.setImageBitmap(flipBitmapHorizontally(bitmap))
            imageView.setPadding(0, 30, 50, 30)
        } else {
            imageView.setImageBitmap(bitmap)
            imageView.setPadding(50, 30, 0, 30)
        }
        destroyGraphicOverlay()
    }

    private fun destroyGraphicOverlay() {
        try {
            if (isAttachedToWindow && graphicOverlay?.parent != null) {
                windowManager.removeView(graphicOverlay)
            }
        } catch (e: IllegalArgumentException) {
            Log.e("FloatingView", "View not attached to window manager", e)
        }
    }

    private fun flipBitmapHorizontally(src: Bitmap): Bitmap {
        val matrix = Matrix()
        matrix.setScale(-1f, 1f)
        return Bitmap.createBitmap(src, 0, 0, src.width, src.height, matrix, true)
    }

    fun attachToWindow() {
        if (!isAttachedToWindow) {
            windowManager.addView(imageView, params)
            isAttachedToWindow = true
        }
    }

    fun detachFromWindow() {
        if (isAttachedToWindow) {
            try {
                windowManager.removeView(imageView)
                isAttachedToWindow = false
            } catch (e: IllegalArgumentException) {
                Log.e("FloatingView", "View not attached to window manager", e)
            }
        }
    }

    private fun imageToBitmap(image: Image): Bitmap {
        val planes = image.planes
        val buffer = planes[0].buffer
        val pixelStride = planes[0].pixelStride
        val rowStride = planes[0].rowStride
        val rowPadding = rowStride - pixelStride * image.width

        val bitmap = Bitmap.createBitmap(
            image.width + rowPadding / pixelStride,
            image.height,
            Bitmap.Config.ARGB_8888
        )
        bitmap.copyPixelsFromBuffer(buffer)
        return Bitmap.createBitmap(bitmap, 0, 0, image.width, image.height)
    }

    private fun tryReloadAndDetectInImage(bitmap: Bitmap) {
        try {
            graphicOverlay?.clear()
            if (imageProcessor != null) {
                graphicOverlay?.setImageSourceInfo(
                    bitmap.width,
                    bitmap.height,
                    false
                )
                imageProcessor!!.processBitmap(bitmap, graphicOverlay)
            } else {
                Log.e(
                    "FloatingView",
                    "Null imageProcessor, please check adb logs for imageProcessor creation error"
                )
            }
        } catch (e: IOException) {
            Log.e("FloatingView", "Error retrieving saved image", e)
        }
    }

    fun setImageReader(reader: ImageReader) {
        this.imageReader = reader
        if (!hasCapturedScreenshot) {
            hasCapturedScreenshot = true
            captureAndProcessScreenshot(imageReader)

            windowManager.addView(graphicOverlay, fullScreenParams)
        }
    }

    override fun onTextRecognized(text: Text, graphicOverlay: GraphicOverlay) {
        graphicOverlay.add(
            TextGraphic(
                graphicOverlay,
                text,
                false, true, "float"
            )
        )
    }

    override fun onTextFailure(e: Exception) {
    }
}
