/**
 * 自然写互动课堂智慧黑板端应用软件 V1.0
 *
 * ScreenRecorder.kt - 课堂录制模块
 *
 * 功能说明：
 * - 课堂屏幕录制（MediaCodec H.264编码）
 * - 音频同步录制（AAC编码）
 * - MediaMuxer封装MP4文件
 * - 录制进度跟踪与时间限制
 * - 录像文件管理（存储/上传/清理）
 * - 课堂回放支持
 */

package com.writech.board.recording

import android.content.Context
import android.media.*
import android.os.Environment
import android.util.Log
import android.view.Surface
import java.io.File
import java.nio.ByteBuffer
import java.text.SimpleDateFormat
import java.util.*
import java.util.concurrent.atomic.AtomicBoolean
import kotlin.concurrent.thread

/**
 * 录制状态
 */
enum class RecordingState {
    IDLE,        /* 空闲 */
    PREPARING,   /* 准备中 */
    RECORDING,   /* 录制中 */
    PAUSED,      /* 暂停 */
    STOPPING,    /* 停止中 */
    ERROR        /* 错误 */
}

/**
 * 录制配置参数
 */
data class RecordingConfig(
    val videoWidth: Int = 1920,         /* 视频宽度 */
    val videoHeight: Int = 1080,        /* 视频高度 */
    val videoBitrate: Int = 6_000_000,  /* 视频码率 6Mbps */
    val videoFps: Int = 30,             /* 帧率 30fps */
    val audioEnabled: Boolean = true,    /* 是否录制音频 */
    val audioBitrate: Int = 128_000,    /* 音频码率 128kbps */
    val audioSampleRate: Int = 44100,   /* 音频采样率 */
    val maxDurationSec: Int = 5400,     /* 最大录制时长 90分钟 */
    val outputDir: String = ""          /* 输出目录 */
)

/**
 * 录制结果信息
 */
data class RecordingResult(
    val filePath: String,               /* 录像文件路径 */
    val durationMs: Long,               /* 录制时长（毫秒） */
    val fileSize: Long,                 /* 文件大小（字节） */
    val videoWidth: Int,                /* 视频宽度 */
    val videoHeight: Int,               /* 视频高度 */
    val timestamp: Long = System.currentTimeMillis()
)

/**
 * 录制事件回调
 */
interface RecordingListener {
    fun onRecordingStateChanged(state: RecordingState)
    fun onRecordingProgress(durationMs: Long)
    fun onRecordingCompleted(result: RecordingResult)
    fun onRecordingError(error: String)
}

/**
 * 课堂屏幕录制器
 *
 * 使用Android MediaCodec + MediaMuxer实现高效屏幕录制：
 * - 视频编码: H.264 (AVC), 1080p@30fps
 * - 音频编码: AAC-LC, 44.1kHz
 * - 容器格式: MP4 (MPEG-4 Part 14)
 */
class ScreenRecorder(private val context: Context) {

    companion object {
        private const val TAG = "ScreenRecorder"
        private const val VIDEO_MIME = MediaFormat.MIMETYPE_VIDEO_AVC
        private const val AUDIO_MIME = MediaFormat.MIMETYPE_AUDIO_AAC
        /** I帧间隔（秒） */
        private const val IFRAME_INTERVAL = 2
        /** 编码器超时（微秒） */
        private const val CODEC_TIMEOUT_US = 10000L
        /** 进度回调间隔（毫秒） */
        private const val PROGRESS_INTERVAL_MS = 1000L
    }

    /* ==================== 状态 ==================== */

    /** 录制状态 */
    var state: RecordingState = RecordingState.IDLE
        private set

    /** 录制配置 */
    private var config = RecordingConfig()

    /** 是否正在录制 */
    private val isRecording = AtomicBoolean(false)

    /** 录制开始时间 */
    private var startTimeNs: Long = 0

    /** 暂停累计时间 */
    private var pausedDurationNs: Long = 0

    /** 暂停起始时间 */
    private var pauseStartNs: Long = 0

    /* ==================== 编码器 ==================== */

    /** 视频编码器 */
    private var videoEncoder: MediaCodec? = null
    /** 音频编码器 */
    private var audioEncoder: MediaCodec? = null
    /** 混流器 */
    private var mediaMuxer: MediaMuxer? = null
    /** 视频输入Surface */
    private var inputSurface: Surface? = null

    /** 视频轨道索引 */
    private var videoTrackIndex: Int = -1
    /** 音频轨道索引 */
    private var audioTrackIndex: Int = -1
    /** Muxer是否已启动 */
    private var isMuxerStarted = false
    /** 已添加的轨道数 */
    private var tracksAdded = 0

    /** 输出文件路径 */
    private var outputFilePath: String = ""

    /* ==================== 监听器 ==================== */

    /** 事件监听器 */
    private var listener: RecordingListener? = null

    /**
     * 设置录制事件监听器
     */
    fun setListener(listener: RecordingListener) {
        this.listener = listener
    }

    /* ==================== 录制控制 ==================== */

    /**
     * 开始录制
     *
     * @param config 录制配置
     * @return 视频输入Surface（渲染内容将被录制）
     */
    fun startRecording(config: RecordingConfig = RecordingConfig()): Surface? {
        if (state != RecordingState.IDLE && state != RecordingState.ERROR) {
            Log.w(TAG, "无法启动录制, 当前状态=$state")
            return null
        }

        this.config = config
        changeState(RecordingState.PREPARING)

        try {
            /* 生成输出文件路径 */
            outputFilePath = generateOutputPath()
            Log.i(TAG, "录制输出: $outputFilePath")

            /* 配置视频编码器 */
            setupVideoEncoder()

            /* 配置音频编码器 */
            if (config.audioEnabled) {
                setupAudioEncoder()
            }

            /* 创建MediaMuxer */
            mediaMuxer = MediaMuxer(outputFilePath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4)

            /* 启动编码器 */
            videoEncoder?.start()
            audioEncoder?.start()

            /* 获取视频输入Surface */
            inputSurface = videoEncoder?.createInputSurface()

            isRecording.set(true)
            startTimeNs = System.nanoTime()
            pausedDurationNs = 0

            /* 启动编码线程 */
            startEncodingThreads()

            changeState(RecordingState.RECORDING)
            Log.i(TAG, "录制开始: ${config.videoWidth}x${config.videoHeight} " +
                    "@${config.videoFps}fps, 码率=${config.videoBitrate / 1_000_000}Mbps")

            return inputSurface

        } catch (e: Exception) {
            Log.e(TAG, "启动录制失败", e)
            changeState(RecordingState.ERROR)
            listener?.onRecordingError("启动录制失败: ${e.message}")
            releaseResources()
            return null
        }
    }

    /**
     * 暂停录制
     */
    fun pauseRecording() {
        if (state != RecordingState.RECORDING) return

        pauseStartNs = System.nanoTime()
        changeState(RecordingState.PAUSED)
        Log.i(TAG, "录制已暂停")
    }

    /**
     * 恢复录制
     */
    fun resumeRecording() {
        if (state != RecordingState.PAUSED) return

        pausedDurationNs += System.nanoTime() - pauseStartNs
        changeState(RecordingState.RECORDING)
        Log.i(TAG, "录制已恢复")
    }

    /**
     * 停止录制
     */
    fun stopRecording() {
        if (state != RecordingState.RECORDING && state != RecordingState.PAUSED) {
            Log.w(TAG, "非录制状态无法停止")
            return
        }

        changeState(RecordingState.STOPPING)
        isRecording.set(false)

        Log.i(TAG, "停止录制中...")

        /* 等待编码线程结束后再释放资源（在编码线程中处理） */
    }

    /* ==================== 编码器配置 ==================== */

    /**
     * 配置视频编码器（H.264）
     */
    private fun setupVideoEncoder() {
        val format = MediaFormat.createVideoFormat(VIDEO_MIME, config.videoWidth, config.videoHeight)
        format.setInteger(MediaFormat.KEY_COLOR_FORMAT,
            MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface)
        format.setInteger(MediaFormat.KEY_BIT_RATE, config.videoBitrate)
        format.setInteger(MediaFormat.KEY_FRAME_RATE, config.videoFps)
        format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, IFRAME_INTERVAL)

        /* 设置编码Profile为High，提升压缩效率 */
        format.setInteger(MediaFormat.KEY_PROFILE,
            MediaCodecInfo.CodecProfileLevel.AVCProfileHigh)
        format.setInteger(MediaFormat.KEY_LEVEL,
            MediaCodecInfo.CodecProfileLevel.AVCLevel41)

        videoEncoder = MediaCodec.createEncoderByType(VIDEO_MIME)
        videoEncoder?.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE)

        Log.d(TAG, "视频编码器配置: ${config.videoWidth}x${config.videoHeight}, " +
                "码率=${config.videoBitrate}, 帧率=${config.videoFps}")
    }

    /**
     * 配置音频编码器（AAC-LC）
     */
    private fun setupAudioEncoder() {
        val format = MediaFormat.createAudioFormat(AUDIO_MIME, 
            config.audioSampleRate, 1)
        format.setInteger(MediaFormat.KEY_BIT_RATE, config.audioBitrate)
        format.setInteger(MediaFormat.KEY_AAC_PROFILE,
            MediaCodecInfo.CodecProfileLevel.AACObjectLC)
        format.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 16384)

        audioEncoder = MediaCodec.createEncoderByType(AUDIO_MIME)
        audioEncoder?.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE)

        Log.d(TAG, "音频编码器配置: ${config.audioSampleRate}Hz, " +
                "码率=${config.audioBitrate}")
    }

    /* ==================== 编码线程 ==================== */

    /**
     * 启动编码线程
     */
    private fun startEncodingThreads() {
        /* 视频编码线程 */
        thread(name = "VideoEncoder") {
            drainEncoder(videoEncoder, true)
        }

        /* 音频编码线程 */
        if (config.audioEnabled) {
            thread(name = "AudioEncoder") {
                drainEncoder(audioEncoder, false)
            }
        }

        /* 进度回调线程 */
        thread(name = "RecordingProgress") {
            while (isRecording.get()) {
                if (state == RecordingState.RECORDING) {
                    val elapsed = (System.nanoTime() - startTimeNs - pausedDurationNs) / 1_000_000
                    listener?.onRecordingProgress(elapsed)

                    /* 检查最大时长限制 */
                    if (elapsed > config.maxDurationSec * 1000L) {
                        Log.i(TAG, "达到最大录制时长 ${config.maxDurationSec}秒, 自动停止")
                        stopRecording()
                    }
                }
                Thread.sleep(PROGRESS_INTERVAL_MS)
            }
        }
    }

    /**
     * 从编码器中取出编码后的数据并写入Muxer
     */
    private fun drainEncoder(encoder: MediaCodec?, isVideo: Boolean) {
        if (encoder == null) return

        val bufferInfo = MediaCodec.BufferInfo()
        val encoderName = if (isVideo) "视频" else "音频"

        try {
            while (isRecording.get() || true) {
                val outputIndex = encoder.dequeueOutputBuffer(bufferInfo, CODEC_TIMEOUT_US)

                when {
                    outputIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED -> {
                        /* 添加轨道到Muxer */
                        val format = encoder.outputFormat
                        synchronized(this) {
                            if (isVideo) {
                                videoTrackIndex = mediaMuxer?.addTrack(format) ?: -1
                                Log.d(TAG, "${encoderName}轨道添加: index=$videoTrackIndex")
                            } else {
                                audioTrackIndex = mediaMuxer?.addTrack(format) ?: -1
                                Log.d(TAG, "${encoderName}轨道添加: index=$audioTrackIndex")
                            }
                            tracksAdded++

                            /* 所有轨道就绪后启动Muxer */
                            val expectedTracks = if (config.audioEnabled) 2 else 1
                            if (tracksAdded >= expectedTracks && !isMuxerStarted) {
                                mediaMuxer?.start()
                                isMuxerStarted = true
                                Log.i(TAG, "MediaMuxer已启动")
                            }
                        }
                    }
                    outputIndex >= 0 -> {
                        val buffer = encoder.getOutputBuffer(outputIndex) ?: continue

                        if (bufferInfo.flags and MediaCodec.BUFFER_FLAG_CODEC_CONFIG != 0) {
                            bufferInfo.size = 0
                        }

                        if (bufferInfo.size > 0 && isMuxerStarted) {
                            val trackIndex = if (isVideo) videoTrackIndex else audioTrackIndex
                            synchronized(this) {
                                mediaMuxer?.writeSampleData(trackIndex, buffer, bufferInfo)
                            }
                        }

                        encoder.releaseOutputBuffer(outputIndex, false)

                        /* 检查结束标志 */
                        if (bufferInfo.flags and MediaCodec.BUFFER_FLAG_END_OF_STREAM != 0) {
                            Log.d(TAG, "${encoderName}编码结束")
                            break
                        }
                    }
                }

                if (!isRecording.get()) {
                    encoder.signalEndOfInputStream()
                }
            }
        } catch (e: Exception) {
            Log.e(TAG, "${encoderName}编码异常", e)
        } finally {
            if (isVideo) {
                /* 视频编码完成后释放资源 */
                onEncodingFinished()
            }
        }
    }

    /**
     * 编码完成后的清理工作
     */
    private fun onEncodingFinished() {
        val durationMs = (System.nanoTime() - startTimeNs - pausedDurationNs) / 1_000_000

        releaseResources()

        /* 获取文件大小 */
        val file = File(outputFilePath)
        val fileSize = if (file.exists()) file.length() else 0

        val result = RecordingResult(
            filePath = outputFilePath,
            durationMs = durationMs,
            fileSize = fileSize,
            videoWidth = config.videoWidth,
            videoHeight = config.videoHeight
        )

        changeState(RecordingState.IDLE)
        listener?.onRecordingCompleted(result)

        Log.i(TAG, "录制完成: 时长=${durationMs / 1000}秒, " +
                "文件大小=${fileSize / 1024}KB, 路径=$outputFilePath")
    }

    /* ==================== 资源管理 ==================== */

    /**
     * 释放所有资源
     */
    private fun releaseResources() {
        try {
            videoEncoder?.stop()
            videoEncoder?.release()
            videoEncoder = null
        } catch (e: Exception) { /* 忽略 */ }

        try {
            audioEncoder?.stop()
            audioEncoder?.release()
            audioEncoder = null
        } catch (e: Exception) { /* 忽略 */ }

        try {
            if (isMuxerStarted) {
                mediaMuxer?.stop()
            }
            mediaMuxer?.release()
            mediaMuxer = null
        } catch (e: Exception) { /* 忽略 */ }

        inputSurface?.release()
        inputSurface = null

        isMuxerStarted = false
        tracksAdded = 0
        videoTrackIndex = -1
        audioTrackIndex = -1

        Log.d(TAG, "录制资源已释放")
    }

    /**
     * 生成录像文件输出路径
     */
    private fun generateOutputPath(): String {
        val dir = if (config.outputDir.isNotEmpty()) {
            File(config.outputDir)
        } else {
            File(context.filesDir, "recordings")
        }
        if (!dir.exists()) dir.mkdirs()

        val dateFormat = SimpleDateFormat("yyyyMMdd_HHmmss", Locale.CHINA)
        val fileName = "class_${dateFormat.format(Date())}.mp4"
        return File(dir, fileName).absolutePath
    }

    /**
     * 状态变更
     */
    private fun changeState(newState: RecordingState) {
        state = newState
        listener?.onRecordingStateChanged(newState)
    }
}
