package com.gensee.multi_instance

import androidx.test.ext.junit.runners.AndroidJUnit4
import com.gensee.media.VODPlayer
import org.junit.Test
import org.junit.runner.RunWith
import java.util.concurrent.CountDownLatch
import java.util.concurrent.atomic.AtomicInteger

/**
 * 真实业务场景测试：多个 VODPlayer 同时播放
 *
 * 场景描述：
 * 1. ViewPager2 预加载机制导致多个页面同时创建
 * 2. 每个 Fragment 有独立的 VODPlayer 实例
 * 3. 多个 Player 同时调用 initAudioPlayer()
 * 4. 可能触发与 Android 音频系统相关的竞态条件
 *
 * 用户提供的参数：
 * - 参数2: vodId=83179783, domain=product.gensee.com, serviceType=TRAINING
 * - 参数3: vodId=68965323, domain=emoney.gensee.com, serviceType=WEBCAST
 */
@RunWith(AndroidJUnit4::class)
class MultiPlayerScenarioTest {

    /**
     * 使用反射调用 initAudioPlayer
     * 需要向上遍历父类链，直到找到 AbsPlayer
     */
    private fun initAudioPlayer(player: Any) {
        var currentClass = player.javaClass
        
        // 向上查找，直到找到 AbsPlayer 类
        while (currentClass != null && currentClass.simpleName != "AbsPlayer") {
            currentClass = currentClass.superclass
        }
        
        if (currentClass == null) {
            throw RuntimeException("AbsPlayer class not found in hierarchy")
        }
        
        val method = currentClass.getDeclaredMethod("initAudioPlayer")
        method.isAccessible = true
        method.invoke(player)
    }

    /**
     * 使用反射调用 audioRelease
     * 需要向上遍历父类链，直到找到 AbsPlayer
     */
    private fun audioRelease(player: Any) {
        var currentClass = player.javaClass
        
        // 向上查找，直到找到 AbsPlayer 类
        while (currentClass != null && currentClass.simpleName != "AbsPlayer") {
            currentClass = currentClass.superclass
        }
        
        if (currentClass == null) {
            throw RuntimeException("AbsPlayer class not found in hierarchy")
        }
        
        val method = currentClass.getDeclaredMethod("audioRelease")
        method.isAccessible = true
        method.invoke(player)
    }

    /**
     * 测试场景：两个独立的 VODPlayer 同时初始化
     *
     * 模拟 ViewPager2 预加载两个页面时的场景
     */
    @Test
    fun testTwoPlayersSimultaneousInit() {
        android.util.Log.i("MultiPlayerTest", "========== Two Players Simultaneous Init ==========")

        val player1 = VODPlayer()
        val player2 = VODPlayer()
        val latch = CountDownLatch(2)

        val crashInfo = mutableListOf<String>()

        // Player 1 线程
        val thread1 = Thread {
            try {
                android.util.Log.i("MultiPlayerTest", "Player 1: initAudioPlayer() START")
                initAudioPlayer(player1)
                android.util.Log.i("MultiPlayerTest", "Player 1: initAudioPlayer() SUCCESS")
            } catch (e: Exception) {
                val error = "Player 1 FAILED: ${e.message}"
                android.util.Log.e("MultiPlayerTest", error, e)
                crashInfo.add(error)
            } finally {
                latch.countDown()
            }
        }

        // Player 2 线程
        val thread2 = Thread {
            try {
                android.util.Log.i("MultiPlayerTest", "Player 2: initAudioPlayer() START")
                initAudioPlayer(player2)
                android.util.Log.i("MultiPlayerTest", "Player 2: initAudioPlayer() SUCCESS")
            } catch (e: Exception) {
                val error = "Player 2 FAILED: ${e.message}"
                android.util.Log.e("MultiPlayerTest", error, e)
                crashInfo.add(error)
            } finally {
                latch.countDown()
            }
        }

        // ⚠️ 关键：同时启动两个线程
        thread1.start()
        thread2.start()

        // 等待两个线程都完成（最多 5 秒）
        latch.await(5, java.util.concurrent.TimeUnit.SECONDS)

        // 检查结果
        if (crashInfo.isNotEmpty()) {
            android.util.Log.e("MultiPlayerTest", "🎯🎯🎯 CRASH DETECTED! 🎯🎯🎯")
            crashInfo.forEach { android.util.Log.e("MultiPlayerTest", it) }
            throw AssertionError("Multi-player init failed: ${crashInfo.joinToString()}")
        } else {
            android.util.Log.i("MultiPlayerTest", "✅ Both players initialized successfully")
        }

        // 清理
        try {
            Thread.sleep(500)
            android.util.Log.i("MultiPlayerTest", "Cleaning up...")
            audioRelease(player1)
            audioRelease(player2)
        } catch (e: Exception) {
            android.util.Log.e("MultiPlayerTest", "Cleanup failed", e)
        }

        android.util.Log.i("MultiPlayerTest", "========== Test Completed ==========")
    }

    /**
     * 测试场景：三个 Player 同时初始化（压力测试）
     *
     * 模拟预加载更多页面的场景
     */
    @Test
    fun testThreePlayersSimultaneousInit() {
        android.util.Log.i("MultiPlayerTest", "========== Three Players Simultaneous Init ==========")

        val player1 = VODPlayer()
        val player2 = VODPlayer()
        val player3 = VODPlayer()
        val latch = CountDownLatch(3)

        val crashInfo = mutableListOf<String>()

        // 创建并启动三个线程
        listOf(
            Pair(player1, "Player 1"),
            Pair(player2, "Player 2"),
            Pair(player3, "Player 3")
        ).forEach { (player, name) ->
            Thread {
                try {
                    android.util.Log.i("MultiPlayerTest", "$name: initAudioPlayer() START")
                    initAudioPlayer(player)
                    android.util.Log.i("MultiPlayerTest", "$name: initAudioPlayer() SUCCESS")
                } catch (e: Exception) {
                    val error = "$name FAILED: ${e.message}"
                    android.util.Log.e("MultiPlayerTest", error, e)
                    synchronized(crashInfo) { crashInfo.add(error) }
                } finally {
                    latch.countDown()
                }
            }.start()
        }

        // 等待所有线程完成
        latch.await(5, java.util.concurrent.TimeUnit.SECONDS)

        if (crashInfo.isNotEmpty()) {
            android.util.Log.e("MultiPlayerTest", "🎯 CRASH DETECTED!")
            crashInfo.forEach { android.util.Log.e("MultiPlayerTest", it) }
            throw AssertionError("Multi-player init failed: ${crashInfo.joinToString()}")
        } else {
            android.util.Log.i("MultiPlayerTest", "✅ All three players initialized successfully")
        }

        // 清理
        try {
            Thread.sleep(500)
            audioRelease(player1)
            audioRelease(player2)
            audioRelease(player3)
        } catch (e: Exception) {
            android.util.Log.e("MultiPlayerTest", "Cleanup failed", e)
        }
    }

    /**
     * 测试场景：快速连续创建并初始化多个 Player
     *
     * 模拟用户快速滑动 ViewPager2 的场景
     */
    @Test
    fun testRapidPlayerCreation() {
        android.util.Log.i("MultiPlayerTest", "========== Rapid Player Creation Test ==========")

        val playerCount = 5
        val players = mutableListOf<VODPlayer>()
        val crashCount = AtomicInteger(0)

        repeat(playerCount) { index ->
            try {
                android.util.Log.i("MultiPlayerTest", "Creating Player $index")
                val player = VODPlayer()
                players.add(player)

                // 立即初始化
                android.util.Log.i("MultiPlayerTest", "Init Player $index")
                initAudioPlayer(player)

                android.util.Log.i("MultiPlayerTest", "Player $index initialized successfully")

                // 短暂延迟（模拟用户滑动间隔）
                Thread.sleep(20)

            } catch (e: Exception) {
                crashCount.incrementAndGet()
                android.util.Log.e("MultiPlayerTest", "Player $index FAILED", e)
            }
        }

        android.util.Log.i("MultiPlayerTest", "Created $playerCount players, ${crashCount.get()} failed")

        if (crashCount.get() > 0) {
            android.util.Log.e("MultiPlayerTest", "🎯 Some players failed to initialize!")
        }

        // 清理
        try {
            Thread.sleep(500)
            players.forEach { player ->
                try {
                    audioRelease(player)
                } catch (e: Exception) {
                    android.util.Log.e("MultiPlayerTest", "Cleanup failed for player", e)
                }
            }
        } catch (e: Exception) {
            android.util.Log.e("MultiPlayerTest", "Cleanup failed", e)
        }
    }

    /**
     * 测试场景：两个 Player 并发初始化和释放
     *
     * 模拟页面快速切换：创建页面 → 立即销毁 → 创建新页面
     */
    @Test
    fun testConcurrentInitAndRelease() {
        android.util.Log.i("MultiPlayerTest", "========== Concurrent Init and Release ==========")

        val latch = CountDownLatch(4)
        val crashInfo = mutableListOf<String>()

        // 线程1：创建并初始化 Player 1
        val initThread1 = Thread {
            try {
                val player1 = VODPlayer()
                android.util.Log.i("MultiPlayerTest", "Init Thread 1: Starting")
                initAudioPlayer(player1)
                android.util.Log.i("MultiPlayerTest", "Init Thread 1: Success")
                Thread.sleep(200) // 保持存活
                audioRelease(player1)
                android.util.Log.i("MultiPlayerTest", "Init Thread 1: Released")
            } catch (e: Exception) {
                val error = "Init Thread 1 FAILED: ${e.message}"
                android.util.Log.e("MultiPlayerTest", error, e)
                crashInfo.add(error)
            } finally {
                latch.countDown()
            }
        }

        // 线程2：创建并初始化 Player 2（与线程1并发）
        val initThread2 = Thread {
            try {
                val player2 = VODPlayer()
                android.util.Log.i("MultiPlayerTest", "Init Thread 2: Starting")
                initAudioPlayer(player2)
                android.util.Log.i("MultiPlayerTest", "Init Thread 2: Success")
                Thread.sleep(200)
                audioRelease(player2)
                android.util.Log.i("MultiPlayerTest", "Init Thread 2: Released")
            } catch (e: Exception) {
                val error = "Init Thread 2 FAILED: ${e.message}"
                android.util.Log.e("MultiPlayerTest", error, e)
                crashInfo.add(error)
            } finally {
                latch.countDown()
            }
        }

        // 线程3：快速创建并释放 Player 3
        val rapidThread = Thread {
            try {
                repeat(2) { i ->
                    val player = VODPlayer()
                    android.util.Log.i("MultiPlayerTest", "Rapid Thread: Creating player $i")
                    initAudioPlayer(player)
                    Thread.sleep(10) // 很短的时间
                    audioRelease(player)
                    android.util.Log.i("MultiPlayerTest", "Rapid Thread: Released player $i")
                }
            } catch (e: Exception) {
                val error = "Rapid Thread FAILED: ${e.message}"
                android.util.Log.e("MultiPlayerTest", error, e)
                crashInfo.add(error)
            } finally {
                latch.countDown()
            }
        }

        // 线程4：另一个并发初始化
        val initThread4 = Thread {
            try {
                val player4 = VODPlayer()
                android.util.Log.i("MultiPlayerTest", "Init Thread 4: Starting")
                initAudioPlayer(player4)
                android.util.Log.i("MultiPlayerTest", "Init Thread 4: Success")
                Thread.sleep(200)
                audioRelease(player4)
                android.util.Log.i("MultiPlayerTest", "Init Thread 4: Released")
            } catch (e: Exception) {
                val error = "Init Thread 4 FAILED: ${e.message}"
                android.util.Log.e("MultiPlayerTest", error, e)
                crashInfo.add(error)
            } finally {
                latch.countDown()
            }
        }

        // 同时启动所有线程
        initThread1.start()
        initThread2.start()
        rapidThread.start()
        initThread4.start()

        latch.await(10, java.util.concurrent.TimeUnit.SECONDS)

        if (crashInfo.isNotEmpty()) {
            android.util.Log.e("MultiPlayerTest", "🎯 CRASH DETECTED!")
            crashInfo.forEach { android.util.Log.e("MultiPlayerTest", it) }
            throw AssertionError("Concurrent test failed: ${crashInfo.joinToString()}")
        } else {
            android.util.Log.i("MultiPlayerTest", "✅ All concurrent operations completed successfully")
        }

        android.util.Log.i("MultiPlayerTest", "========== Test Completed ==========")
    }
}
