/*
 * Hermes Node Android
 * Copyright (C) 2026 Stefy Lanza <stefy@nexlab.net>
 * SPDX-License-Identifier: GPL-3.0-or-later
 */
package net.nexlab.hermesnodeandroid

import android.Manifest
import android.app.Activity
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.SurfaceTexture
import android.hardware.camera2.CameraAccessException
import android.hardware.camera2.CameraCaptureSession
import android.hardware.camera2.CameraCharacteristics
import android.hardware.camera2.CameraDevice
import android.hardware.camera2.CameraManager
import android.hardware.camera2.CaptureRequest
import android.media.MediaRecorder
import android.os.Bundle
import android.os.Handler
import android.os.HandlerThread
import android.util.Size
import android.view.Gravity
import android.view.Surface
import android.view.TextureView
import android.widget.FrameLayout
import android.widget.TextView
import androidx.core.content.ContextCompat
import org.json.JSONObject
import java.io.File

class VideoCaptureActivity : Activity() {
    private lateinit var textureView: TextureView
    private lateinit var overlayText: TextView
    private lateinit var cameraManager: CameraManager
    private var cameraDevice: CameraDevice? = null
    private var captureSession: CameraCaptureSession? = null
    private var mediaRecorder: MediaRecorder? = null
    private var handlerThread: HandlerThread? = null
    private var handler: Handler? = null
    private var outputFile: File? = null
    private var requestId: String = ""
    private var nodeName: String = "android"
    private var durationMs: Long = 3000L
    private var width: Int = 1280
    private var height: Int = 720
    private var selectedCameraId: String? = null
    private var completionPosted = false

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        textureView = TextureView(this)
        overlayText = TextView(this).apply {
            text = "Hermes video capture in progress"
            textSize = 18f
            setPadding(32, 48, 32, 48)
            setBackgroundColor(0xAA000000.toInt())
            setTextColor(0xFFFFFFFF.toInt())
        }
        val root = FrameLayout(this).apply {
            addView(textureView, FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT))
            addView(overlayText, FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT).apply {
                gravity = Gravity.TOP
            })
        }
        setContentView(root)

        val payload = VideoCaptureSessionStore.loadPending(this)
        if (payload == null) {
            finishWithFailure("No pending video capture request")
            return
        }
        requestId = payload.optString("request_id")
        nodeName = payload.optString("node_name", "android")
        durationMs = payload.optLong("duration_ms", 3000L).coerceIn(1000L, 15000L)
        width = payload.optInt("width", 1280)
        height = payload.optInt("height", 720)
        selectedCameraId = payload.optString("camera_id", payload.optString("id", "")).ifBlank { null }
        overlayText.text = "Hermes video capture in progress\nNode: $nodeName\nDuration: ${durationMs / 1000.0}s"

        if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
            finishWithFailure("Camera permission not granted")
            return
        }

        cameraManager = getSystemService(CAMERA_SERVICE) as CameraManager
        startBackgroundThread()
        textureView.surfaceTextureListener = object : TextureView.SurfaceTextureListener {
            override fun onSurfaceTextureAvailable(surface: SurfaceTexture, width: Int, height: Int) {
                startCaptureFlow()
            }
            override fun onSurfaceTextureSizeChanged(surface: SurfaceTexture, width: Int, height: Int) = Unit
            override fun onSurfaceTextureDestroyed(surface: SurfaceTexture): Boolean = true
            override fun onSurfaceTextureUpdated(surface: SurfaceTexture) = Unit
        }
        if (textureView.isAvailable) startCaptureFlow()
    }

    override fun onDestroy() {
        cleanup()
        super.onDestroy()
    }

    private fun startCaptureFlow() {
        if (completionPosted) return
        val cameraId = chooseCameraId() ?: run {
            finishWithFailure("No suitable camera available")
            return
        }
        selectedCameraId = cameraId
        outputFile = File.createTempFile("hermes-video-", ".mp4", cacheDir)
        val previewTexture = textureView.surfaceTexture ?: run {
            finishWithFailure("Preview surface unavailable")
            return
        }
        previewTexture.setDefaultBufferSize(width, height)
        val previewSurface = Surface(previewTexture)
        val recorder = buildRecorder(outputFile!!)
        mediaRecorder = recorder
        val recorderSurface = recorder.surface
        try {
            cameraManager.openCamera(cameraId, object : CameraDevice.StateCallback() {
                override fun onOpened(device: CameraDevice) {
                    cameraDevice = device
                    try {
                        device.createCaptureSession(listOf(previewSurface, recorderSurface), object : CameraCaptureSession.StateCallback() {
                            override fun onConfigured(session: CameraCaptureSession) {
                                captureSession = session
                                try {
                                    val request = device.createCaptureRequest(CameraDevice.TEMPLATE_RECORD).apply {
                                        addTarget(previewSurface)
                                        addTarget(recorderSurface)
                                        set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO)
                                    }.build()
                                    session.setRepeatingRequest(request, null, handler)
                                    recorder.start()
                                    textureView.postDelayed({ finishSuccess() }, durationMs)
                                } catch (e: Exception) {
                                    finishWithFailure("Failed to start capture: ${e.message}")
                                }
                            }

                            override fun onConfigureFailed(session: CameraCaptureSession) {
                                finishWithFailure("Camera session configuration failed")
                            }
                        }, handler)
                    } catch (e: Exception) {
                        finishWithFailure("Failed to create camera session: ${e.message}")
                    }
                }

                override fun onDisconnected(device: CameraDevice) {
                    finishWithFailure("Camera disconnected")
                }

                override fun onError(device: CameraDevice, error: Int) {
                    finishWithFailure("Camera error: $error")
                }
            }, handler)
        } catch (e: SecurityException) {
            finishWithFailure("Camera permission denied: ${e.message}")
        } catch (e: CameraAccessException) {
            finishWithFailure("Camera access failed: ${e.message}")
        }
    }

    private fun buildRecorder(file: File): MediaRecorder {
        return MediaRecorder().apply {
            setVideoSource(MediaRecorder.VideoSource.SURFACE)
            setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
            setOutputFile(file.absolutePath)
            setVideoEncoder(MediaRecorder.VideoEncoder.H264)
            setVideoEncodingBitRate(4_000_000)
            setVideoFrameRate(24)
            setVideoSize(width, height)
            prepare()
        }
    }

    private fun chooseCameraId(): String? {
        if (!selectedCameraId.isNullOrBlank()) return selectedCameraId
        return cameraManager.cameraIdList.firstOrNull { id ->
            val chars = cameraManager.getCameraCharacteristics(id)
            chars.get(CameraCharacteristics.LENS_FACING) == CameraCharacteristics.LENS_FACING_BACK
        } ?: cameraManager.cameraIdList.firstOrNull()
    }

    private fun finishSuccess() {
        if (completionPosted) return
        completionPosted = true
        val file = outputFile
        val payload = JSONObject()
            .put("request_id", requestId)
            .put("success", true)
            .put("format", "mp4")
            .put("path", file?.absolutePath ?: "")
            .put("bytes", file?.length() ?: 0L)
            .put("duration_ms", durationMs)
            .put("width", width)
            .put("height", height)
            .put("camera_id", selectedCameraId ?: "")
            .put("message", "Video capture completed with visible foreground activity")
        VideoCaptureSessionStore.saveResult(this, payload)
        VideoCaptureSessionStore.clearPending(this)
        cleanup()
        startService(Intent(this, HermesNodeService::class.java).setAction(HermesNodeService.ACTION_VIDEO_CAPTURE_COMPLETE))
        finish()
    }

    private fun finishWithFailure(message: String) {
        if (completionPosted) return
        completionPosted = true
        val payload = JSONObject()
            .put("request_id", requestId)
            .put("success", false)
            .put("error", message)
        VideoCaptureSessionStore.saveResult(this, payload)
        VideoCaptureSessionStore.clearPending(this)
        cleanup()
        startService(Intent(this, HermesNodeService::class.java).setAction(HermesNodeService.ACTION_VIDEO_CAPTURE_COMPLETE))
        finish()
    }

    private fun cleanup() {
        runCatching { captureSession?.stopRepeating() }
        runCatching { captureSession?.close() }
        captureSession = null
        runCatching { cameraDevice?.close() }
        cameraDevice = null
        runCatching { mediaRecorder?.stop() }
        runCatching { mediaRecorder?.reset() }
        runCatching { mediaRecorder?.release() }
        mediaRecorder = null
        handlerThread?.quitSafely()
        handlerThread = null
        handler = null
    }

    private fun startBackgroundThread() {
        handlerThread = HandlerThread("HermesVideoCapture").apply { start() }
        handler = Handler(handlerThread!!.looper)
    }
}
