package com.example.studentfaceregistry

import android.Manifest
import android.content.pm.PackageManager
import android.graphics.Typeface
import android.os.Bundle
import android.os.SystemClock
import android.util.Size
import android.util.Log
import android.view.Gravity
import android.view.View
import android.widget.Button
import android.widget.FrameLayout
import android.widget.LinearLayout
import android.widget.TextView
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.camera.core.CameraSelector
import androidx.camera.core.ImageAnalysis
import androidx.camera.core.ImageProxy
import androidx.camera.core.Preview
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.camera.view.PreviewView
import androidx.core.content.ContextCompat
import androidx.lifecycle.lifecycleScope
import com.example.studentfaceregistry.data.Student
import com.example.studentfaceregistry.data.StudentRepository
import com.example.studentfaceregistry.face.FaceMatcher
import com.example.studentfaceregistry.face.FaceProcessor
import com.example.studentfaceregistry.face.MatchType
import com.google.mlkit.vision.common.InputImage
import com.example.studentfaceregistry.ui.DetectionUi
import com.example.studentfaceregistry.ui.OverlayView
import com.example.studentfaceregistry.upload.UploadServer
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.util.concurrent.Executors

class MainActivity : AppCompatActivity() {
    private lateinit var countText: TextView
    private lateinit var previewView: PreviewView
    private lateinit var overlayView: OverlayView
    private lateinit var recognitionStatusText: TextView
    private lateinit var uploadStatusText: TextView
    private lateinit var uploadUrlText: TextView
    private lateinit var pauseRecognitionButton: Button
    private lateinit var homePanel: View
    private lateinit var recognitionPanel: View
    private lateinit var uploadPanel: View

    private var currentMode = AppMode.HOME
    private var processor: FaceProcessor? = null
    private var uploadServer: UploadServer? = null
    private var analysisUseCase: ImageAnalysis? = null
    private var cameraProvider: ProcessCameraProvider? = null

    private val repository by lazy { StudentRepository(this) }
    private val matcher = FaceMatcher(euclideanThreshold = 1.0f, cosineThreshold = 0.6f)
    private val cameraExecutor = Executors.newSingleThreadExecutor()
    private var students: List<Student> = emptyList()
    private var recognitionEnabled = true
    private var analyzing = false
    private var lastAnalysisAt = 0L

    private val permissionLauncher = registerForActivityResult(
        ActivityResultContracts.RequestMultiplePermissions()
    ) { grants ->
        if (grants[Manifest.permission.CAMERA] == true) {
            if (currentMode == AppMode.RECOGNITION) {
                startRecognitionSession()
            }
        } else if (currentMode == AppMode.RECOGNITION) {
            recognitionStatusText.text = "需要相机权限才能识别学生身份。"
            toast("需要相机权限才能识别学生身份。")
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(createContentView())

        lifecycleScope.launch {
            repository.students.collectLatest { list ->
                students = list
                countText.text = "已入库 ${list.size} 名学生"
            }
        }

        switchMode(AppMode.HOME)
    }

    override fun onDestroy() {
        super.onDestroy()
        stopRecognitionSession()
        stopUploadSession()
        cameraExecutor.shutdown()
    }

    private fun createContentView(): View {
        val root = LinearLayout(this).apply {
            orientation = LinearLayout.VERTICAL
            setBackgroundColor(0xFFF8FAFC.toInt())
        }

        val header = LinearLayout(this).apply {
            orientation = LinearLayout.VERTICAL
            setPadding(32, 28, 32, 20)
        }
        header.addView(TextView(this).apply {
            text = "学生人脸识别"
            textSize = 24f
            setTextColor(0xFF0F172A.toInt())
        })
        countText = TextView(this).apply {
            text = "已入库 0 名学生"
            textSize = 15f
            setTextColor(0xFF475569.toInt())
        }
        header.addView(countText)

        val content = FrameLayout(this).apply {
            layoutParams = LinearLayout.LayoutParams(
                LinearLayout.LayoutParams.MATCH_PARENT,
                0,
                1f
            )
        }

        homePanel = createHomePanel()
        recognitionPanel = createRecognitionPanel()
        uploadPanel = createUploadPanel()
        homePanel.visibility = View.VISIBLE
        recognitionPanel.visibility = View.GONE
        uploadPanel.visibility = View.GONE

        content.addView(homePanel, FrameLayout.LayoutParams(-1, -1))
        content.addView(recognitionPanel, FrameLayout.LayoutParams(-1, -1))
        content.addView(uploadPanel, FrameLayout.LayoutParams(-1, -1))

        root.addView(header)
        root.addView(content)
        return root
    }

    private fun createHomePanel(): View {
        return LinearLayout(this).apply {
            orientation = LinearLayout.VERTICAL
            gravity = Gravity.CENTER
            setPadding(40, 40, 40, 40)

            addView(TextView(this@MainActivity).apply {
                text = "请选择要进入的功能"
                textSize = 26f
                typeface = Typeface.DEFAULT_BOLD
                setTextColor(0xFF0F172A.toInt())
                gravity = Gravity.CENTER
            })

            addView(TextView(this@MainActivity).apply {
                text = "识别和注册上传分开运行，减少同时占用相机、模型和本地服务带来的卡顿。"
                textSize = 16f
                setTextColor(0xFF475569.toInt())
                gravity = Gravity.CENTER
                setPadding(0, 20, 0, 36)
            })

            addView(Button(this@MainActivity).apply {
                text = "进入识别"
                textSize = 20f
                setPadding(36, 24, 36, 24)
                setOnClickListener { switchMode(AppMode.RECOGNITION) }
            })

            addView(Button(this@MainActivity).apply {
                text = "进入注册上传"
                textSize = 20f
                setPadding(36, 24, 36, 24)
                setOnClickListener { switchMode(AppMode.UPLOAD) }
            })
        }
    }

    private fun createRecognitionPanel(): View {
        return LinearLayout(this).apply {
            orientation = LinearLayout.VERTICAL
            setPadding(24, 16, 24, 24)

            recognitionStatusText = TextView(this@MainActivity).apply {
                text = "准备进入识别模式"
                textSize = 22f
                typeface = Typeface.DEFAULT_BOLD
                setTextColor(0xFF0F172A.toInt())
                setPadding(8, 8, 8, 20)
            }
            addView(recognitionStatusText)

            val cameraFrame = FrameLayout(this@MainActivity).apply {
                layoutParams = LinearLayout.LayoutParams(
                    LinearLayout.LayoutParams.MATCH_PARENT,
                    0,
                    1f
                )
            }
            previewView = PreviewView(this@MainActivity).apply {
                scaleType = PreviewView.ScaleType.FILL_CENTER
            }
            overlayView = OverlayView(this@MainActivity)
            cameraFrame.addView(previewView, FrameLayout.LayoutParams(-1, -1))
            cameraFrame.addView(overlayView, FrameLayout.LayoutParams(-1, -1))
            addView(cameraFrame)

            addView(LinearLayout(this@MainActivity).apply {
                gravity = Gravity.CENTER
                orientation = LinearLayout.HORIZONTAL
                setPadding(12, 20, 12, 8)

                addView(Button(this@MainActivity).apply {
                    text = "返回首页"
                    setOnClickListener { switchMode(AppMode.HOME) }
                })

                pauseRecognitionButton = Button(this@MainActivity).apply {
                    text = "暂停识别"
                    setOnClickListener {
                        recognitionEnabled = !recognitionEnabled
                        text = if (recognitionEnabled) "暂停识别" else "继续识别"
                        recognitionStatusText.text = if (recognitionEnabled) "正在识别" else "识别已暂停"
                        if (!recognitionEnabled) {
                            overlayView.update(emptyList(), 1, 1)
                        }
                        updateAnalyzerState()
                    }
                }
                addView(pauseRecognitionButton)
            })
        }
    }

    private fun createUploadPanel(): View {
        return LinearLayout(this).apply {
            orientation = LinearLayout.VERTICAL
            gravity = Gravity.CENTER_HORIZONTAL
            setPadding(40, 48, 40, 48)

            uploadStatusText = TextView(this@MainActivity).apply {
                text = "准备进入注册上传模式"
                textSize = 24f
                typeface = Typeface.DEFAULT_BOLD
                setTextColor(0xFF0F172A.toInt())
                gravity = Gravity.CENTER
            }
            addView(uploadStatusText)

            addView(TextView(this@MainActivity).apply {
                text = "在同一 Wi-Fi 下，用电脑浏览器打开下面的地址，就可以上传学生图片或视频。"
                textSize = 16f
                setTextColor(0xFF475569.toInt())
                gravity = Gravity.CENTER
                setPadding(0, 16, 0, 20)
            })

            uploadUrlText = TextView(this@MainActivity).apply {
                text = "-"
                textSize = 20f
                typeface = Typeface.MONOSPACE
                setTextColor(0xFF0F172A.toInt())
                gravity = Gravity.CENTER
                setPadding(24, 20, 24, 20)
                setTextIsSelectable(true)
                setBackgroundColor(0xFFE2E8F0.toInt())
            }
            addView(uploadUrlText)

            addView(LinearLayout(this@MainActivity).apply {
                gravity = Gravity.CENTER
                orientation = LinearLayout.HORIZONTAL
                setPadding(12, 28, 12, 8)

                addView(Button(this@MainActivity).apply {
                    text = "刷新地址"
                    setOnClickListener { startUploadSession() }
                })

                addView(Button(this@MainActivity).apply {
                    text = "返回首页"
                    setOnClickListener { switchMode(AppMode.HOME) }
                })
            })
        }
    }

    private fun switchMode(mode: AppMode) {
        if (currentMode == mode) return

        val previousMode = currentMode
        currentMode = mode
        homePanel.visibility = if (mode == AppMode.HOME) View.VISIBLE else View.GONE
        recognitionPanel.visibility = if (mode == AppMode.RECOGNITION) View.VISIBLE else View.GONE
        uploadPanel.visibility = if (mode == AppMode.UPLOAD) View.VISIBLE else View.GONE

        when (previousMode) {
            AppMode.RECOGNITION -> stopRecognitionSession()
            AppMode.UPLOAD -> stopUploadSession()
            AppMode.HOME -> Unit
        }

        when (mode) {
            AppMode.HOME -> Unit
            AppMode.RECOGNITION -> enterRecognitionMode()
            AppMode.UPLOAD -> enterUploadMode()
        }
    }

    private fun enterRecognitionMode() {
        recognitionEnabled = true
        analyzing = false
        lastAnalysisAt = 0L
        pauseRecognitionButton.text = "暂停识别"
        recognitionStatusText.text = "正在准备识别服务..."
        overlayView.update(emptyList(), 1, 1)

        if (hasCameraPermission()) {
            startRecognitionSession()
        } else {
            permissionLauncher.launch(arrayOf(Manifest.permission.CAMERA))
        }
    }

    private fun startRecognitionSession() {
        if (currentMode != AppMode.RECOGNITION) return

        val faceProcessor = ensureProcessor() ?: return
        val providerFuture = ProcessCameraProvider.getInstance(this)
        providerFuture.addListener({
            val provider = providerFuture.get()
            cameraProvider = provider
            if (currentMode != AppMode.RECOGNITION) {
                provider.unbindAll()
                return@addListener
            }

            val preview = Preview.Builder().build().also {
                it.setSurfaceProvider(previewView.surfaceProvider)
            }
            val analysis = ImageAnalysis.Builder()
                .setTargetResolution(ANALYSIS_SIZE)
                .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
                .build()

            provider.unbindAll()
            provider.bindToLifecycle(this, CameraSelector.DEFAULT_BACK_CAMERA, preview, analysis)
            analysisUseCase = analysis
            recognitionStatusText.text = if (faceProcessor === processor) "正在识别" else "识别服务已启动"
            updateAnalyzerState()
        }, ContextCompat.getMainExecutor(this))
    }

    private fun stopRecognitionSession() {
        recognitionEnabled = false
        analyzing = false
        analysisUseCase?.clearAnalyzer()
        analysisUseCase = null
        cameraProvider?.unbindAll()
        cameraProvider = null
        overlayView.update(emptyList(), 1, 1)
        processor?.close()
        processor = null
    }

    private fun updateAnalyzerState() {
        val analysis = analysisUseCase ?: return
        if (currentMode == AppMode.RECOGNITION && recognitionEnabled && processor != null) {
            analysis.setAnalyzer(cameraExecutor) { image -> analyze(image) }
        } else {
            analysis.clearAnalyzer()
        }
    }

    private fun analyze(image: ImageProxy) {
        val faceProcessor = processor
        val now = SystemClock.elapsedRealtime()
        if (
            currentMode != AppMode.RECOGNITION ||
            !recognitionEnabled ||
            analyzing ||
            faceProcessor == null ||
            now - lastAnalysisAt < ANALYSIS_INTERVAL_MS
        ) {
            image.close()
            return
        }

        analyzing = true
        lastAnalysisAt = now
        lifecycleScope.launch(Dispatchers.Default) {
            try {
                val mediaImage = image.image ?: return@launch
                val inputImage = InputImage.fromMediaImage(mediaImage, image.imageInfo.rotationDegrees)
                val faces = faceProcessor.detectFaces(inputImage)

                if (faces.isEmpty()) {
                    withContext(Dispatchers.Main) {
                        if (currentMode == AppMode.RECOGNITION) {
                            overlayView.update(emptyList(), 1, 1)
                            updateRecognitionStatus(emptyList())
                        }
                    }
                    return@launch
                }

                val bitmap = ImageUtils.imageProxyToBitmap(image)
                val detections = faces.map { face ->
                    val embedding = faceProcessor.embedFace(bitmap, face)
                    val result = matcher.findNearest(embedding, students)
                    DetectionUi(
                        bounds = face.boundingBox,
                        result = result,
                        confidence = result.confidence
                    )
                }

                withContext(Dispatchers.Main) {
                    if (currentMode == AppMode.RECOGNITION) {
                        overlayView.update(detections, bitmap.width, bitmap.height)
                        updateRecognitionStatus(detections)
                    }
                }
            } catch (e: Exception) {
                Log.e("MainActivity", "Recognition failed", e)
                withContext(Dispatchers.Main) {
                    if (currentMode == AppMode.RECOGNITION) {
                        recognitionStatusText.text = "识别失败：${e.message ?: e.javaClass.simpleName}"
                    }
                }
            } finally {
                analyzing = false
                image.close()
            }
        }
    }

    private fun updateRecognitionStatus(detections: List<DetectionUi>) {
        if (detections.isEmpty()) {
            recognitionStatusText.text = "未检测到人脸"
            return
        }

        val matched = detections.filter { it.result.isMatched }
        val unsure = detections.filter { it.result.matchType == MatchType.UNSURE }
        val total = detections.size

        if (matched.isNotEmpty()) {
            if (matched.size == 1 && total == 1) {
                val student = matched[0].result.student!!
                val confidence = (matched[0].confidence!! * 100).toInt()
                recognitionStatusText.text = "识别到：${student.name}（${student.studentNo}）置信度${confidence}%"
            } else {
                val names = matched.joinToString(", ") {
                    val student = it.result.student!!
                    val confidence = (it.confidence!! * 100).toInt()
                    "${student.name}(${confidence}%)"
                }
                recognitionStatusText.text = "识别到 ${matched.size}/$total 人：$names"
            }
        } else if (unsure.isNotEmpty()) {
            recognitionStatusText.text = "疑似检测到 ${unsure.size} 人（不确定）"
        } else {
            recognitionStatusText.text = "检测到 $total 张未入库人脸"
        }
    }

    private fun enterUploadMode() {
        uploadStatusText.text = "正在准备注册上传服务..."
        startUploadSession()
    }

    private fun startUploadSession() {
        if (currentMode != AppMode.UPLOAD) return

        val server = uploadServer ?: UploadServer(this, repository).also {
            uploadServer = it
        }
        runCatching {
            server.start()
            uploadStatusText.text = "请在电脑浏览器打开以下地址"
            uploadUrlText.text = server.accessUrl()
        }.onFailure {
            val message = it.message ?: "unknown error"
            uploadStatusText.text = "上传服务启动失败：$message"
            uploadUrlText.text = "-"
        }
    }

    private fun stopUploadSession() {
        uploadServer?.close()
        uploadServer = null
        uploadStatusText.text = "注册上传服务已停止"
        uploadUrlText.text = "-"
    }

    private fun ensureProcessor(): FaceProcessor? {
        val current = processor
        if (current != null) return current

        val created = runCatching { FaceProcessor(this) }
            .onFailure {
                val message = it.message ?: "unknown error"
                recognitionStatusText.text = "模型初始化失败：$message"
                toast("模型初始化失败：$message")
            }
            .getOrNull()
        processor = created
        return created
    }

    private fun hasCameraPermission(): Boolean {
        return ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED
    }

    private fun toast(message: String) {
        Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
    }

    companion object {
        private const val ANALYSIS_INTERVAL_MS = 250L
        private val ANALYSIS_SIZE = Size(640, 480)
    }
}

private enum class AppMode {
    HOME,
    RECOGNITION,
    UPLOAD
}
