using AxibugEmuOnline.Client.ClientCore;
using AxibugEmuOnline.Client.Event;
using AxibugProtobuf;
using ICSharpCode.SharpZipLib.Zip;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;

namespace AxibugEmuOnline.Client
{
    public class RomFile
    {
        private HttpAPI.Resp_RomInfo webData;
        private bool hasLocalFile;
        private AxiHttpProxy.SendDownLoadProxy downloadRequest;
        /// <summary> 依赖的Rom文件 </summary>
        private List<RomFile> dependencies = new List<RomFile>();

        /// <summary> 指示该Rom是否是多文件Rom </summary>
        public bool MultiFileRom
        {
            get
            {
                switch (Platform)
                {
                    case RomPlatformType.Nes: return false;
                    case RomPlatformType.Cps1: return true;
                    default: throw new NotImplementedException($"未实现的平台{Platform}");
                }
            }
        }

        /// <summary> 指示该Rom文件的存放路径 </summary>
        public string LocalFilePath => $"{App.PersistentDataPath(Platform)}/RemoteRoms/{FileName}";

        /// <summary> 指示该Rom文件是否已下载完毕 </summary>
        public bool RomReady
        {
            get
            {
                if (!hasLocalFile) return false;

                foreach (var depRom in dependencies)
                {
                    if (!depRom.RomReady) return false;
                }

                return true;
            }
        }
        /// <summary> 指示是否正在下载Rom文件 </summary>
        public bool IsDownloading
        {
            get
            {
                var selfDownloading = downloadRequest != null && !downloadRequest.downloadHandler.isDone;
                if (selfDownloading) return true;

                foreach (var depRom in dependencies)
                {
                    if (depRom.IsDownloading) return true;
                }

                return false;
            }
        }

        public float Progress
        {
            get
            {
                if (!IsDownloading) return 0;

                float total = 0f;

                total += downloadRequest != null ? downloadRequest.downloadHandler.DownLoadPr : 0;
                foreach (var depRom in dependencies)
                {
                    total += depRom.Progress;
                }

                return total;
            }
        }

        public RomPlatformType Platform => webData != null ? (RomPlatformType)webData.ptype : RomPlatformType.Invalid;
        /// <summary> 指示该Rom信息是否已填充 </summary>
        public bool InfoReady
        {
            get
            {
                if (webData == null) return false;

                foreach (var depRom in dependencies)
                {
                    if (!depRom.InfoReady) return false;
                }

                return true;
            }
        }
        /// <summary> 唯一标识 </summary>
        public int ID => webData != null ? webData.id : -1;
        /// <summary> 别名 </summary>
        public string Alias => webData.romName;
        /// <summary> 描述 </summary>
        public string Descript => webData.desc;
        /// <summary> 游戏类型 </summary>
        public string GameTypeDes => webData.gType;
        /// <summary> 小图URL </summary>
        public string ImageURL => webData.imgUrl;

        /// <summary> 文件名 </summary>
        public string FileName { get; private set; }
        /// <summary> 在查询结果中的索引 </summary>
        public int Index { get; private set; }
        /// <summary> 在查询结果中的所在页 </summary>
        public int Page { get; private set; }
        public string Hash => webData != null ? webData.hash : string.Empty;
        /// <summary> 标记是否收藏 </summary>
        public bool Star
        {
            get { return webData != null ? webData.isStar > 0 : false; }
            set
            {
                if (webData == null) return;
                webData.isStar = value ? 1 : 0;
            }
        }

        public event Action<RomFile> OnDownloadOver;
        public event Action OnInfoFilled;

        public RomFile(int index, int insidePage)
        {
            Index = index;
            Page = insidePage;
        }

        public void BeginDownload()
        {
            if (RomReady) return;
            if (IsDownloading) return;

            //检查依赖Rom的下载情况            

            App.StartCoroutine(DownloadRemoteRom((bytes) =>
            {
                HandleRomFilePostProcess(bytes);
            }));
        }

        private void HandleRomFilePostProcess(byte[] bytes)
        {
            if (bytes == null) return;

            if (MultiFileRom)
            {
                Dictionary<string, byte[]> unzipFiles = new Dictionary<string, byte[]>();
                //多rom文件的平台,下载下来的数据直接解压放入文件夹内
                var zip = new ZipInputStream(new MemoryStream(bytes));
                while (true)
                {
                    var currentEntry = zip.GetNextEntry();
                    if (currentEntry == null) break;

                    if (currentEntry.IsDirectory) continue;

                    var buffer = new byte[1024];
                    MemoryStream output = new MemoryStream();
                    while (true)
                    {
                        var size = zip.Read(buffer, 0, buffer.Length);
                        if (size == 0) break;
                        else output.Write(buffer, 0, size);
                    }
                    output.Flush();
                    unzipFiles[$"{LocalFilePath}/{currentEntry.Name}"] = output.ToArray();
                }

                foreach (var item in unzipFiles)
                {
                    var path = item.Key;
                    var data = item.Value;
                    File.WriteAllBytes(path, data);
                }
            }
            else
            {
                var directPath = Path.GetDirectoryName(LocalFilePath);
                Directory.CreateDirectory(directPath);

                File.WriteAllBytes(LocalFilePath, bytes);
                hasLocalFile = true;

                Eventer.Instance.PostEvent(EEvent.OnRomFileDownloaded, ID);
            }
            OnDownloadOver?.Invoke(this);
        }

        public byte[] GetRomFileData()
        {
            Debug.Assert(!MultiFileRom, "仅供单文件Rom使用的接口");

            if (webData == null) throw new Exception("Not Valid Rom");
            if (!RomReady) throw new Exception("Rom File Not Downloaded");

            var bytes = File.ReadAllBytes(LocalFilePath);
            if (Path.GetExtension(LocalFilePath).ToLower() == ".zip")
            {
                var zip = new ZipInputStream(new MemoryStream(bytes));
                while (true)
                {
                    var currentEntry = zip.GetNextEntry();
                    if (currentEntry == null) break;

                    if (!currentEntry.Name.ToLower().EndsWith(".nes")) continue;

                    var buffer = new byte[1024];
                    MemoryStream output = new MemoryStream();
                    while (true)
                    {
                        var size = zip.Read(buffer, 0, buffer.Length);
                        if (size == 0) break;
                        else output.Write(buffer, 0, size);
                    }
                    output.Flush();
                    return output.ToArray();
                }
            }
            else
            {
                return bytes;
            }

            throw new Exception("Not Valid Rom Data");
        }

        private IEnumerator DownloadRemoteRom(Action<byte[]> callback)
        {
            downloadRequest = AxiHttpProxy.GetDownLoad($"{App.httpAPI.WebHost}/{webData.url}");

            while (!downloadRequest.downloadHandler.isDone)
            {
                yield return null;
                Debug.Log($"下载进度:{downloadRequest.downloadHandler.DownLoadPr} ->{downloadRequest.downloadHandler.loadedLenght}/{downloadRequest.downloadHandler.NeedloadedLenght}");
            }
            AxiHttpProxy.ShowAxiHttpDebugInfo(downloadRequest.downloadHandler);

            var request = downloadRequest;
            downloadRequest = null;
            if (!request.downloadHandler.bHadErr)
                callback(request.downloadHandler.data);
            else
                callback(null);
        }

        public void SetWebData(HttpAPI.Resp_RomInfo resp_RomInfo)
        {
            webData = resp_RomInfo;
            FileName = MultiFileRom ? Path.GetFileNameWithoutExtension(webData.url) : Path.GetFileName(webData.url);
            FileName = System.Net.WebUtility.UrlDecode(FileName);

            if (MultiFileRom)
                hasLocalFile = Directory.Exists(LocalFilePath);
            else
                hasLocalFile = File.Exists(LocalFilePath);

            //收集依赖Rom
            if (webData.parentRomIdsList != null)
            {
                foreach (var romID in webData.parentRomIdsList)
                {
                    var romFile = new RomFile(Index, Page);
                    dependencies.Add(romFile);
                    App.StartCoroutine(App.httpAPI.GetRomInfo(romID, (romInfo) =>
                    {
                        romFile.SetWebData(romInfo);
                    }));
                }
            }

            App.StartCoroutine(WaitInfoReady());
        }

        private IEnumerator WaitInfoReady()
        {
            while (!InfoReady) yield return null;

            OnInfoFilled?.Invoke();
        }
    }
}