using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using FairyGUI;
using SGModule.Common.Base;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.Video;

namespace RedHotRoast
{
    public class LiveVideoManager : SingletonMonoBehaviour<LiveVideoManager>
    {
        public static string videoBaseUrl = "";

        // 封面缓存
        // private readonly Dictionary<string, Texture2D> coverCache = new();

        // 封面提取队列（避免同时开多个VideoPlayer）
        private readonly Queue<CoverTask> coverQueue = new();

        // 已下载视频缓存
        private readonly HashSet<string> downloadedVideos = new();

        // 当前正在下载的视频，用于去重
        private readonly HashSet<string> downloadingSet = new();

        // ==== 队列 ====

        // 普通视频队列和优先队列
        private readonly Queue<VideoTask> normalQueue = new();
        private readonly Queue<VideoTask> priorityQueue = new();
        private bool isExtracting;

        private Coroutine normalCoroutine;
        private Coroutine priorityCoroutine;

        private string videoLocalDir => Path.Combine(TextureHelper.getResPath(), "LiveVideos");
        private string coverLocalDir => Path.Combine(TextureHelper.getResPath(), "LiveVideoCovers");

        protected override void Awake()
        {
            base.Awake();
            InitDirs();
            InitCache();
        }

        private void InitDirs()
        {
            if (!Directory.Exists(videoLocalDir))
                Directory.CreateDirectory(videoLocalDir);

            if (!Directory.Exists(coverLocalDir))
                Directory.CreateDirectory(coverLocalDir);
        }

        private void InitCache()
        {
            var files = Directory.GetFiles(videoLocalDir, "*.mp4");
            foreach (var file in files)
            {
                var fileName = Path.GetFileNameWithoutExtension(file);
                downloadedVideos.Add(fileName);
            }
        }

        #region 缓存清理

        public void ClearAllCache()
        {
            // foreach (var tex in coverCache.Values)
            //     if (tex != null)
            //         Destroy(tex);
            // coverCache.Clear();

            if (Directory.Exists(coverLocalDir))
            {
                Directory.Delete(coverLocalDir, true);
                Directory.CreateDirectory(coverLocalDir);
            }

            if (Directory.Exists(videoLocalDir))
            {
                Directory.Delete(videoLocalDir, true);
                Directory.CreateDirectory(videoLocalDir);
                downloadedVideos.Clear();
            }
        }

        #endregion

        #region 统一加载视频封面

        public IEnumerator LoadCover(string fileName, Action<Texture2D> callback)
        {
            Texture2D tex = null;

            var persistentPath = Path.Combine(TextureHelper.getResPath(), "LiveVideoCovers", fileName + ".png");
            if (File.Exists(persistentPath))
            {
                tex = LoadTextureFromFile(persistentPath);
                if (tex != null)
                {
                    callback?.Invoke(tex);
                    yield break;
                }
            }

            var saPath = Path.Combine(Application.streamingAssetsPath, "LiveVideoCovers", fileName + ".jpg");

#if UNITY_ANDROID && !UNITY_EDITOR
            using (UnityWebRequest www = UnityWebRequestTexture.GetTexture(saPath))
            {
                yield return www.SendWebRequest();
                if (www.result == UnityWebRequest.Result.Success)
                    tex = DownloadHandlerTexture.GetContent(www);
                else
                    Debug.LogWarning($"LoadCover StreamingAssets失败: {www.error}, file: {fileName}");
            }
#else
            if (File.Exists(saPath))
                try
                {
                    var data = File.ReadAllBytes(saPath);
                    tex = new Texture2D(2, 2);
                    tex.LoadImage(data);
                }
                catch (Exception e)
                {
                    Debug.LogWarning($"LoadCover StreamingAssets读取失败: {fileName}, error: {e}");
                }
#endif
            callback?.Invoke(tex);
        }

        #endregion


        public static IEnumerator LoadVideoToPlayer(VideoPlayer player, string fileName, GLoader loader,
            Action<VideoPlayer> onComplete, bool play = true)
        {
            string localPath = null;
            var isDone = false;
            Instance.GetVideoLocalPath(fileName, path =>
            {
                localPath = path;
                isDone = true;
            });
            Debug.Log("LoadVideoToPlayer ------1------" + isDone);

            while (!isDone)
                yield return null;

            if (string.IsNullOrEmpty(localPath))
            {
                onComplete?.Invoke(null);
                yield break;
            }

            if (player.IsDestroyed())
            {
                onComplete?.Invoke(null);
                yield break;
            }

            player.source = VideoSource.Url;
            Debug.Log("LoadVideoToPlayer diaoyongyici: " + fileName);
            player.url = Application.platform == RuntimePlatform.Android && !Application.isEditor
                ? localPath
                : "file://" + localPath;

            player.isLooping = true;
            player.playOnAwake = false;

            var rtWidth = (int)loader.width;
            var rtHeight = (int)loader.height;

            var rt = new RenderTexture(rtWidth, rtHeight, 0);
            rt.Create();

            player.targetTexture = rt;


            if (!loader.isDisposed)
            {
                Debug.Log("LoadVideoToPlayer loader is isDisposed: ");
                loader.texture = new NTexture(rt);
                loader.visible = false;
            }

            player.Prepare();

            var timeout = 3f;
            var timer = 0f;
            while (!player.IsDestroyed() && !player.isPrepared && timer < timeout)
            {
                yield return null;
                timer += Time.deltaTime;
            }

            if (player.IsDestroyed())
            {
                onComplete?.Invoke(null);
                yield break;
            }

            if (!player.isPrepared)
            {
                if (rt != null && !rt.Equals(null)) rt.Release();
                onComplete?.Invoke(null);
                yield break;
            }

            if (play)
                player.Play();
            else
                player.Pause();

            if (!loader.isDisposed)
                loader.visible = true;

            onComplete?.Invoke(player);
        }

        #region 视频下载队列（支持普通 + 优先 + 硬取消 + 去重）

        public void GetVideoLocalPath(string fileName, Action<string> callback, bool priority = true, int maxRetry = 3,
            bool hardCancel = false)
        {
            var localPath = Path.Combine(videoLocalDir, fileName + ".mp4");

            // 已下载直接回调
            if (downloadedVideos.Contains(fileName) && File.Exists(localPath))
            {
                callback?.Invoke(localPath);
                return;
            }

            // 去重：如果正在下载中，也直接等待回调
            if (downloadingSet.Contains(fileName))
            {
                StartCoroutine(WaitForDownload(fileName, callback));
                return;
            }

            var task = new VideoTask
            {
                FileName = fileName,
                LocalPath = localPath,
                Callback = callback,
                MaxRetry = maxRetry
            };

            if (priority)
            {
                if (hardCancel)
                {
                    // 硬取消：停止当前优先队列协程，清空队列
                    if (priorityCoroutine != null)
                    {
                        StopCoroutine(priorityCoroutine);
                        priorityCoroutine = null;
                    }

                    priorityQueue.Clear();
                }

                priorityQueue.Enqueue(task);
                if (priorityCoroutine == null)
                    priorityCoroutine = StartCoroutine(ProcessPriorityQueue());
            }
            else
            {
                normalQueue.Enqueue(task);
                if (normalCoroutine == null)
                    normalCoroutine = StartCoroutine(ProcessNormalQueue());
            }
        }

        // 等待正在下载的视频完成再回调
        private IEnumerator WaitForDownload(string fileName, Action<string> callback)
        {
            while (downloadingSet.Contains(fileName))
                yield return null;

            var localPath = Path.Combine(videoLocalDir, fileName + ".mp4");
            callback?.Invoke(File.Exists(localPath) ? localPath : null);
        }

        // 优先队列协程（单任务）
        private IEnumerator ProcessPriorityQueue()
        {
            while (priorityQueue.Count > 0)
            {
                var task = priorityQueue.Dequeue();
                yield return DownloadVideoCoroutine(task);
            }

            priorityCoroutine = null;
        }

        // 普通队列协程（单任务）
        private IEnumerator ProcessNormalQueue()
        {
            while (normalQueue.Count > 0)
            {
                var task = normalQueue.Dequeue();
                yield return DownloadVideoCoroutine(task);
            }

            normalCoroutine = null;
        }

        // 核心下载协程
        private IEnumerator DownloadVideoCoroutine(VideoTask task)
        {
            // 再次检查本地是否已有，避免重复下载
            if (downloadedVideos.Contains(task.FileName) && File.Exists(task.LocalPath))
            {
                task.Callback?.Invoke(task.LocalPath);
                yield break;
            }

            downloadingSet.Add(task.FileName);

            var tmpPath = task.LocalPath + ".downloading";
            var url = videoBaseUrl + "LiveAlbums/" + task.FileName + ".mp4";

            if (File.Exists(tmpPath)) File.Delete(tmpPath);

            var attempt = 0;
            var success = false;

            while (attempt < task.MaxRetry)
            {
                attempt++;
                using (var www = UnityWebRequest.Get(url))
                {
                    www.downloadHandler = new DownloadHandlerFile(tmpPath, true);
                    yield return www.SendWebRequest();

                    if (www.result == UnityWebRequest.Result.Success)
                    {
                        if (File.Exists(task.LocalPath)) File.Delete(task.LocalPath);

                        Debug.Log($"[DownloadVideo] 下载成功，开始解密视频 {task.FileName}");
                        Rescrypt.DecryptFile(tmpPath, task.LocalPath);
                        Debug.Log($"[DownloadVideo] 解密完成，保存路径：{task.LocalPath}");

                        downloadedVideos.Add(task.FileName);
                        success = true;
                        break;
                    }

                    Debug.LogWarning($"视频下载失败（第 {attempt} 次）: {task.FileName}, {www.error}");
                    if (attempt < task.MaxRetry)
                        yield return new WaitForSeconds(1f);
                }
            }

            if (!success)
            {
                Debug.LogError($"视频下载失败，超过最大重试次数：{task.FileName}");
                if (File.Exists(tmpPath)) File.Delete(tmpPath);
            }

            downloadingSet.Remove(task.FileName);
            task.Callback?.Invoke(success ? task.LocalPath : null);

            LiveVideoMemoryManager.RequestCleanup();
        }

        #endregion

        #region 视频封面

        // 你的封面逻辑保持不变
        public void GetVideoCover(GLoader loader, string fileName, Action<Texture2D> onComplete)
        {
            // if (coverCache.TryGetValue(fileName, out var cached))
            // {
            //     onComplete?.Invoke(cached);
            //     return;
            // }

            // var coverPath = Path.Combine(coverLocalDir, fileName + ".png");
            // if (File.Exists(coverPath))
            // {
            //     var tex = LoadTextureFromFile(coverPath);
            //     coverCache[fileName] = tex;
            //     onComplete?.Invoke(tex);
            //     return;
            // }

            StartCoroutine(LoadCover(fileName, onComplete));

            coverQueue.Enqueue(new CoverTask { FileName = fileName, Callback = onComplete });

            if (!isExtracting)
                ProcessCoverQueue(loader);
        }

        private void ProcessCoverQueue(GLoader loader)
        {
            isExtracting = true;

            while (coverQueue.Count > 0)
            {
                var task = coverQueue.Dequeue();
                ProcessGetCoverCoroutine(loader, task.FileName, task.Callback);
            }

            isExtracting = false;
        }

        private void ProcessGetCoverCoroutine(GLoader loader, string fileName, Action<Texture2D> callback)
        {
            TextureHelper.SetImgLoader(loader, fileName,
                (a) => {
                    // coverCache[fileName] = a.nativeTexture as Texture2D;
                    // callback?.Invoke(coverCache[fileName]);
                    callback?.Invoke(a.nativeTexture as Texture2D);
                }, "LiveAlbums/", FolderNames.VideoCoversName);
        }

        private IEnumerator ExtractCoverFromVideo(string fileName, string videoPath, Action<Texture2D> callback)
        {
            var go = new GameObject("LiveVideoCoverExtractor_" + fileName);
            var vp = go.AddComponent<VideoPlayer>();
            vp.audioOutputMode = VideoAudioOutputMode.None;
            vp.source = VideoSource.Url;
            vp.url = Application.platform == RuntimePlatform.Android && !Application.isEditor
                ? videoPath
                : "file://" + videoPath;

            vp.isLooping = false;
            vp.playOnAwake = false;

            var rt = new RenderTexture(389, 583, 0);
            vp.targetTexture = rt;
            vp.Prepare();

            var timeout = 5f;
            var timer = 0f;
            while (!vp.isPrepared && timer < timeout)
            {
                timer += Time.deltaTime;
                yield return null;
            }

            if (!vp.isPrepared)
            {
                Debug.LogWarning($"LiveVideoManager: Video '{fileName}' prepare timeout.");
                Destroy(go);
                callback?.Invoke(null);
                yield break;
            }

            vp.Pause();
            yield return new WaitForEndOfFrame();

            var tex = CaptureFrame(vp);
            SaveCover(fileName, tex);
            // coverCache[fileName] = tex;

            callback?.Invoke(tex);
            Destroy(go);
        }

        private Texture2D CaptureFrame(VideoPlayer vp)
        {
            var rt = vp.targetTexture;
            RenderTexture.active = rt;

            var tex = new Texture2D(rt.width, rt.height, TextureFormat.RGB24, false);
            tex.ReadPixels(new Rect(0, 0, rt.width, rt.height), 0, 0);
            tex.Apply();

            RenderTexture.active = null;
            vp.Stop();
            vp.targetTexture = null;
            return tex;
        }

        private void SaveCover(string fileName, Texture2D tex)
        {
            try
            {
                var pngData = tex.EncodeToPNG();
                var path = Path.Combine(coverLocalDir, fileName + ".png");
                File.WriteAllBytes(path, pngData);
            }
            catch (Exception e)
            {
                Debug.LogWarning($"Save cover PNG failed for '{fileName}': {e}");
            }
        }

        private Texture2D LoadTextureFromFile(string filePath)
        {
            try
            {
                var data = File.ReadAllBytes(filePath);
                var tex = new Texture2D(2, 2);
                tex.LoadImage(data);
                return tex;
            }
            catch
            {
                return null;
            }
        }

        public bool ExistVideo(string fileName)
        {
            var path = Path.Combine(videoLocalDir, fileName + ".mp4");
            return File.Exists(path);
        }

        #endregion
    }

    internal class VideoTask
    {
        public Action<string> Callback;
        public string FileName;
        public string LocalPath;
        public int MaxRetry;
    }

    internal class CoverTask
    {
        public Action<Texture2D> Callback;
        public string FileName;
    }

    internal static class LiveVideoMemoryManager
    {
        private const int CLEANUP_INTERVAL = 30;
        private const int CLEANUP_THRESHOLD = 10;
        private static readonly float lastCleanupTime = 0f;
        private static int downloadCount;

        public static void RequestCleanup()
        {
            downloadCount++;
            if (downloadCount >= CLEANUP_THRESHOLD ||
                Time.realtimeSinceStartup - lastCleanupTime > CLEANUP_INTERVAL)
                LiveVideoManager.Instance.StartCoroutine(CleanupCoroutine());
        }

        private static IEnumerator CleanupCoroutine()
        {
            yield return null;
            // Debug.Log("[LiveVideoMemoryManager] 清理内存...");
            // yield return Resources.UnloadUnusedAssets();
            // GC.Collect();
            //
            // lastCleanupTime = Time.realtimeSinceStartup;
            // downloadCount = 0;
        }
    }
}