using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using UnityEngine;
using UnityEngine.Events;

namespace AssetUpdate
{
    public abstract class AssetDownloadAction : IAssetAsyncAction
    {
        //public UnityWebRequest currentRequest { get; private set; }
        protected Dictionary<string, string> _assetPathInfo;
        private BinaryFormatter _formatter;
        public AssetUpdateManager.AssetUpdateError error;
        public List<AssetDependencyItem> downloadList { get; private set; }
        public int current { get; private set; }
        public string uriHeader { get; private set; }
        public AssetUpdateDownloader downloader { get; private set; }
        public long totalSize { get; private set; }
        public long completeSize { get; private set; }

        public bool UpdateTimeout()
        {
            return current >= downloadList.Count ||
                   error != AssetUpdateManager.AssetUpdateError.Success;
        }

        public void Dispose()
        {
            if (downloader != null)
                downloader.Dispose();
        }

        public void Start(string uri, List<AssetDependencyItem> list)
        {
            uriHeader = uri;
            downloadList = list;
            totalSize = downloadList.Aggregate<AssetDependencyItem, long>(0, (current1, t) => current1 + t.fileSize);
            var filePath = AssetConst.persistentDataPath.Open(AssetConst.pathFile + AssetConst.bytesExtension);
            _formatter = new BinaryFormatter();
            if (File.Exists(filePath))
                try
                {
                    using (var fs = File.OpenRead(filePath))
                    {
                        _assetPathInfo = _formatter.Deserialize(fs) as Dictionary<string, string>;
                    }
                }
                catch (Exception e)
                {
                    Debug.LogError(e);
                }

            if (_assetPathInfo == null)
                _assetPathInfo = new Dictionary<string, string>();
            if (downloadList.Count > 0)
            {
                current = -1;
                CreateConfirmUi(OnDownloadConfirm);
            }
        }

        public long GetCurrentBytes()
        {
            return completeSize + (downloader == null ? 0 : downloader.finishedSize);
        }

        // public float GetCurrentProgress()
        // {
        //     return downloader == null ? 1f : downloader.progress;
        // }

        protected abstract void CreateConfirmUi(UnityAction<bool> callback);

        // 项目相关功能
        protected abstract void CreateDownloadUi();

        // 项目相关功能
        protected abstract void RemoveDownloadUi();

        private void OnDownloadConfirm(bool isConfirm)
        {
            if (isConfirm)
            {
                CreateDownloadUi();
                StartNextItem();
            }
            else
            {
                error = AssetUpdateManager.AssetUpdateError.UserCancel;
            }
        }

        private void StartNextItem()
        {
            current++;
            if (current < downloadList.Count)
            {
                var data = downloadList[current];
                var uri = uriHeader.Open(data.version.ToString()).Open(data.name + AssetConst.bundleVariant);
                var filePath = AssetConst.GetPersistBundle(data.name + AssetConst.bundleVariant);
                downloader = new AssetUpdateDownloader(uri, filePath) {onComplete = OnWebRequestComplete};
                downloader.Start();
            }
            else
            {
                ShowComplete();
                RemoveDownloadUi();
            }
        }

        protected abstract void ShowComplete();

        private void OnWebRequestComplete(AssetUpdateDownloader loader)
        {
            error = downloader.error;
            var downloadSize = downloader.finishedSize;
            // 移除当前记录,防止获得进度时会报参数错误
            downloader = null;
            if (error == AssetUpdateManager.AssetUpdateError.Success)
            {
                var data = downloadList[current];
                var filePath = AssetConst.GetPersistBundle(data.name + AssetConst.bundleVariant);
                if (!File.Exists(filePath))
                {
                    error = AssetUpdateManager.AssetUpdateError.FileCreateError;
                }
                else
                {
                    // Hash校验
                    if (AssetUtils.GetFileMd5(filePath) != data.md5)
                    {
                        Debug.LogError(string.Format("Hash check on {0} didn't match! Restart the download!", data.name));
                        // 网络没有问题,回滚文件再次下载
                        current--;
                        StartNextItem();
//                        error = AssetUpdateManager.AssetUpdateError.FileCreateError;
                    }
                    else
                    {
                        completeSize += downloadSize;
                        // 保存下载数据
                        _assetPathInfo[data.name] = data.md5;
                        filePath = AssetConst.persistentDataPath.Open(AssetConst.pathFile + AssetConst.bytesExtension);
                        using (var fs = File.Create(filePath))
                        {
                            _formatter.Serialize(fs, _assetPathInfo);
                        }
                        StartNextItem();
                    }
                }
            }
            else
            {
                Debug.LogError(string.Format("Failed to download file {0}!", downloadList[current].name));
            }
        }
    }
}