﻿using System;
using System.Collections;
using System.IO;
using Toast.SmartDownloader;
using UnityEngine;
using UnityEngine.UI;
using Debug = UnityEngine.Debug;

namespace Toast.SmartDownloader.Example
{
    public partial class SmartDlExample : MonoBehaviour
    {
        [Header("Input Fields")]
        public InputField AppkeyInputField;
        public InputField ServiceNameField;
        public InputField DstPathField;

        [Space]

        [Header("Config Sliders")]
        public Slider RetryCountSlider;
        public Slider ConnectTimeoutSlider;
        public Slider ReadTimeoutSlider;

        [Space]

        [Header("Etc.")]
        public Button ExtraButton;
        public Text ResultText;
        public ProgressBar PercentageBar;
        public RectTransform ExitPanel;

        private Coroutine _progressCoroutine;
        private ResultCode _recentResultCode = ResultCode.UNKNOWN;

        #region Define partial methods
        partial void OnBeforeAwake();
        partial void OnCompleteDownload(DownloadResult result, DownloadProfiler profiler);
        partial void OnSetupDownloadConfig(DownloadConfig config);
        #endregion

        void Awake()
        {
            OnBeforeAwake();

            AppkeyInputField.text = SmartDlExampleConfiguration.AppKey;
            ServiceNameField.text = SmartDlExampleConfiguration.ServiceName;
            DstPathField.text = SmartDlExampleConfiguration.DownloadPath;

            RetryCountSlider.value = SmartDlExampleConfiguration.RetryCount;
            ConnectTimeoutSlider.value = SmartDlExampleConfiguration.ConnectionTimeoutSeconds;
            ReadTimeoutSlider.value = SmartDlExampleConfiguration.ReadTimeoutSeconds;

            AppkeyInputField.onEndEdit.AddListener(SmartDlExampleConfiguration.SaveAppKey);
            ServiceNameField.onEndEdit.AddListener(SmartDlExampleConfiguration.SaveServiceName);
            DstPathField.onEndEdit.AddListener(SmartDlExampleConfiguration.SaveDownloadPath);

            RetryCountSlider.onValueChanged.AddListener(retryCount => SmartDlExampleConfiguration.SaveRetryCount((int)retryCount));
            ConnectTimeoutSlider.onValueChanged.AddListener(connectionTimeoutSeconds => SmartDlExampleConfiguration.SaveConnectionTimeoutSeconds((int)connectionTimeoutSeconds));
            ReadTimeoutSlider.onValueChanged.AddListener(readTimeoutSeconds => SmartDlExampleConfiguration.SaveReadTimeoutSeconds((int)readTimeoutSeconds));

#if UNITY_2018_1_OR_NEWER
            Application.wantsToQuit += WantsToQuit;
#endif
        }

        void OnDestroy()
        {
#if UNITY_2018_1_OR_NEWER
            Application.wantsToQuit -= WantsToQuit;
#endif
        }

        void Start()
        {
            SmartDlLogger.CurrentLevel = SmartDlLogger.LogLevel.Trace;
            SmartDlLogger.OnLog += (type, log) =>
            {
                switch (type)
                {
                    case SmartDlLogger.LogLevel.Trace:
                    case SmartDlLogger.LogLevel.Developer:
                    case SmartDlLogger.LogLevel.Debug:
                    case SmartDlLogger.LogLevel.Info:
                        Debug.Log(log);
                        break;
                    case SmartDlLogger.LogLevel.Warn:
                        Debug.LogWarning(log);
                        break;
                    case SmartDlLogger.LogLevel.Error:
                        Debug.LogError(log);
                        break;
                    default:
                        Debug.Log(log);
                        break;
                }
            };
        }

        public void OnClickStartDownload()
        {
            if (string.IsNullOrEmpty(AppkeyInputField.text))
            {
                PrintResult("You MUST input appkey field");
                return;
            }

            if (string.IsNullOrEmpty(ServiceNameField.text))
            {
                PrintResult("You MUST input service name");
                return;
            }

            PrintResult("Start download");
            StopUpdateProgressCoroutine();

            #region Set DownloadConfig
            var downloadConfig = DownloadConfig.Default;
            downloadConfig.RetryDownloadCountPerFile = (int)RetryCountSlider.value;
            downloadConfig.DownloadConnectTimeout = TimeSpan.FromSeconds(ConnectTimeoutSlider.value);
            downloadConfig.DownloadReadTimeout = TimeSpan.FromSeconds(ReadTimeoutSlider.value);
            OnSetupDownloadConfig(downloadConfig);
            #endregion

            var profiler = new DownloadProfiler();
            profiler.Start();

            _recentResultCode = ResultCode.UNKNOWN;
            SmartDl.SetUserId("SmartDlExample");
            SmartDl.StartDownload(SmartDlExampleConfiguration.AppKey,
                SmartDlExampleConfiguration.ServiceName,
                SmartDlExampleConfiguration.DownloadPath,
                downloadConfig,
                result =>
            {
                profiler.End();
                _recentResultCode = result.Code;

                OnCompleteDownload(result, profiler);
                if (result.IsSuccessful)
                {
                    PrintResult(string.Format("Success elapsed time : {0:F2} ms / {1:F2} s",
                        profiler.ElapsedMilliseconds,
                        profiler.ElapsedSeconds));
                }
                else
                {
                    PrintResult(string.Format("Fail to download [{0}]", result));
                    StopUpdateProgressCoroutine();
                }
            });
            _progressCoroutine = StartCoroutine(UpdateProgress());
        }

        public void OnClickStopDownload()
        {
            PrintResult("Stop download");
            StopUpdateProgressCoroutine();
            SmartDl.StopDownload();
        }

        public void OnClickDeleteFiles()
        {
            PrintResult(FileUtil.DeleteFilesInDownloadPath() ? "Success to delete directory" : "Fail to delete directory");
        }

        private void StopUpdateProgressCoroutine()
        {
            if (_progressCoroutine != null)
            {
                StopCoroutine(_progressCoroutine);
            }
        }

        private IEnumerator UpdateProgress()
        {
            while (true)
            {
                var progress = SmartDl.Progress;

                PercentageBar.Percentage = progress.Percentage;
                PercentageBar.CompletedFileCount = progress.CompletedFileCount;
                PercentageBar.TotalFileCount = progress.TotalFileNumber;
                PercentageBar.CompletedFileSizeKB = progress.TotalReceivedBytes / 1024.0;
                PercentageBar.TotalFileSizeKB = progress.TotalFileBytes / 1024.0;

                if (progress.FileMap != null)
                {
                    var threadCount = progress.FileMap.Count;
                    ThreadProgressContainer.Instance.ThreadCount = threadCount;
                    for (int i = 0; i < threadCount; i++)
                    {
                        var file = progress.FileMap[i];
                        ThreadProgressContainer.Instance[i].ThreadNumber = i.ToString();
                        ThreadProgressContainer.Instance[i].FileName = file.FileName;
                        ThreadProgressContainer.Instance[i].ProgressBar.Percentage = (file.DownloadedBytes / (float)file.TotalBytes) * 100.0f;
                    }
                }

                if (progress.IsCompleted == true)
                {
                    yield break;
                }

                yield return null;
            }
        }
    }
}