using Minio;
using Minio.DataModel.Args;
using Minio.Exceptions;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Networking;

public class MinIoXR 
{
    IMinioClient minio;
    MinIOConfig minioconfig;

    int projectId;
    Thread thread;
    private void Start()
    {
        thread = new Thread(DoSomeWork);
        thread.Start();
    }
    int miao = 0;
    bool isminioUpdate;
    bool isUpdate;
    void DoSomeWork()
    {
        while (true)
        {
            if (minio == null)
            {
            }
            else
            {
                if (Nowfd != null && !isUpdate)
                {
                    isUpdate = true;
                    Run().Wait();
                }
                if ( gfdQueue.Count > 0 && !isDownLoad)
                {
                    isDownLoad = true;
                    nowgfd = gfdQueue.Dequeue();
                    RunFile().Wait();
                }
            }
            Thread.Sleep(1000);
            miao++;
            if(miao>2400)
            {
                miao = 0;
                minio = null;
            }
        }
    }

    public class MinIOConfig
    {
        public string token;
        public string tmpSecretId;
        public string tmpSecretKey;
        public string host;
        public string bucket;
        public string path;
    }

    void initMinIo(MinIOConfig d,Action<bool> isSuccess)
    {
        minioconfig = d;
        try
        {
            bool isHttps = d.host.Contains("https");
            var endpoint = d.host.Split("//")[1];
            var accessKey = d.tmpSecretId;//"tr6Nh5D8bnlGaLJE6vb5";
            var secretKey = d.tmpSecretKey;// "aVOYdXLnX4MCiKbit8aomZNWvAx8YSpzhiwzFhrI";
            minio = new MinioClient()
                                .WithEndpoint(endpoint)
                                .WithCredentials(accessKey, secretKey)
                                .WithSessionToken(d.token)
                                .WithSSL(isHttps)
                                .Build();
            isSuccess.Invoke(true);
        }
        catch
        {

            isSuccess.Invoke(false);
        }
    }

    Queue<FileData> fdQueue = new Queue<FileData>();
    void putFile(string filePath, string fileName, Action<string> callBack)
    {
        FileData fd = new FileData();
        fd.filePath = filePath;
        fd.fileName = fileName;
        fd.callBack = callBack;
        fdQueue.Enqueue(fd);
    }
    string DicName = "XunJian";
    public void saveFile(byte[] bytes, int projectId, string Index, int imgIndex, Action<string> callBack)
    {
        this.projectId = projectId;
        if (!Directory.Exists(Application.persistentDataPath + "/" + DicName))
            Directory.CreateDirectory(Application.persistentDataPath + "/" + DicName);

        string fileName = DicName + "_" + projectId + "_" + Index + "_" + imgIndex + ".png";
        string filePathname = Application.persistentDataPath + "/" + DicName + "/" + fileName;
      //  if (File.Exists(filePathname))
      //      File.Delete(filePathname);
        File.WriteAllBytes(filePathname, bytes);

       // PlayerPrefs.SetString(fileName, filePathname);
        putFile(filePathname, fileName, callBack);

    }
    /// <summary>
    /// 运行模式下Texture转换成Texture2D
    /// </summary>
    /// <param name="texture"></param>
    /// <returns></returns>
    private Texture2D TextureToTexture2D(Texture texture)
    {
        Texture2D texture2D = new Texture2D(texture.width, texture.height, TextureFormat.RGBA32, false);
        RenderTexture currentRT = RenderTexture.active;
        RenderTexture renderTexture = RenderTexture.GetTemporary(texture.width, texture.height, 32);
        Graphics.Blit(texture, renderTexture);

        RenderTexture.active = renderTexture;
        texture2D.ReadPixels(new Rect(0, 0, renderTexture.width, renderTexture.height), 0, 0);
        texture2D.Apply();

        RenderTexture.active = currentRT;
        RenderTexture.ReleaseTemporary(renderTexture);

        return texture2D;
    }

    /// <summary>
    /// 获取文件
    /// </summary>
    /// <param name="projectId">巡检ID</param>
    /// <param name="Index">步骤ID</param>
    /// <param name="imgIndex">步骤ID内图片ID</param>
    /// <param name="callBack"></param>
    public void getFile(int projectId, string Index, int imgIndex, Action<Texture2D> callBack)//, string path
    {
        this.projectId = projectId;



       
        string fileName = DicName + "_" + projectId + "_" + Index + "_" + imgIndex + ".png";
        string filePathname = PlayerPrefs.GetString(fileName);
        if (filePathname != "")
        {
           // StartCoroutine(_GetTexture(filePathname, callBack));
        }
        else
        {
            GetFileData gfd = new GetFileData();
            gfd.bucket = minioconfig.bucket;
            gfd.objectName = DicName + "_" + projectId + "_" + Index + "_" + imgIndex + ".png";
            gfd.callBack = callBack;
            gfdQueue.Enqueue(gfd);
        }
    }
    GetFileData nowgfd;
    Queue<byte[]> backQueue = new Queue<byte[]>();
    Queue<GetFileData> gfdQueue = new Queue<GetFileData>();
    // File uploader task.
    private async Task RunFile()
    {
        try
        {

            StatObjectArgs statObjectArgs = new StatObjectArgs()
                                              .WithBucket(minioconfig.bucket)
                                              .WithObject(minioconfig.path + "/" + nowgfd.objectName);
            await minio.StatObjectAsync(statObjectArgs);

            // Get input stream to have content of 'my-objectname' from 'my-bucketname'
            GetObjectArgs getObjectArgs = new GetObjectArgs()
                                              .WithBucket(minioconfig.bucket)
                                              .WithObject(minioconfig.path + "/" + nowgfd.objectName)
                                             // .WithHeaders(metaData)
                                              .WithCallbackStream(async (stream) =>
                                              {
                                                  backQueue.Enqueue(StreamToBytes(stream));

                                              });
            await minio.GetObjectAsync(getObjectArgs);

        }
        catch
        {
            backQueue.Enqueue(null);

        }
    }
     static byte[] StreamToBytes(Stream stream)
    {
        byte[] bytes = new byte[stream.Length];
        stream.Read(bytes, 0, bytes.Length);
        stream.Seek(0, SeekOrigin.Begin);
        return bytes;
    }
    /// <summary>
    /// 请求图片
    /// </summary>
    /// <param name="url">图片地址,like 'http://www.my-server.com/image.png '</param>
    /// <param name="action">请求发起后处理回调结果的委托,处理请求结果的图片</param>
    /// <returns></returns>
    IEnumerator _GetTexture(string url, Action<Texture2D> actionResult)
    {
#if UNITY_ANDROID
        //Debug.LogError("请求图片:"+url);
        WWW w = new WWW("file://" + url);
        yield return w;
        if (w.isDone)
            actionResult?.Invoke(w.texture);
#else

        UnityWebRequest uwr = new UnityWebRequest(url);
        DownloadHandlerTexture downloadTexture = new DownloadHandlerTexture(true);
        uwr.downloadHandler = downloadTexture;
        yield return uwr.SendWebRequest();
        Texture2D t = null;
        if (!(uwr.isNetworkError || uwr.isHttpError))
        {
            t = downloadTexture.texture;
        }
        else
        {
            Debug.Log("下载失败,请检查网络,或者下载地址是否正确: " + uwr.error);
        }

        if (actionResult != null)
        {
            actionResult(t);
        }
#endif
    }
    // File uploader task.
    private async Task Run()
    {
        try
        {

            var getListBucketsTask = await minio.ListBucketsAsync().ConfigureAwait(false);
            var bucketName = minioconfig.bucket;
            var objectName = minioconfig.path + "/" + Nowfd.fileName;
            var filePath = Nowfd.filePath;
            var contentType = "application/octet-stream";

            // Make a bucket on the server, if not already present.

            // Upload a file to bucket.
            var putObjectArgs = new PutObjectArgs()
                .WithBucket(bucketName)
                .WithObject(objectName)
                .WithFileName(filePath)
                .WithContentType(contentType);
            await minio.PutObjectAsync(putObjectArgs).ConfigureAwait(false);
            Debug.Log("33333333333333333");

            PlayerPrefs.SetString(Nowfd.fileName, Nowfd.filePath);
            isUpdate = false;
            Nowfd.callBack?.Invoke(Nowfd.fileName);
            Nowfd = null;
        }
        catch
        {

            Nowfd.callBack?.Invoke(null);
            isUpdate = false;
            Nowfd = null;
        }
    }
    bool isDownLoad;
    FileData Nowfd;
    private void Update()
    {
        if (fdQueue.Count > 0 && Nowfd == null)
        {
            Nowfd = fdQueue.Dequeue();
        }
        if (minio == null)
        {
            if (projectId != 0 && !isminioUpdate)
            {
                isminioUpdate = true;
                initMinIo(minioconfig,(bool b) =>
                {
                    isminioUpdate = false;
                });
            }
        }
        if(backQueue.Count>0)
        {
            byte[] bytes = backQueue.Dequeue();
         
                if(bytes!=null)
                {

                    Debug.Log("444444444444");
                    Texture2D t2d = new Texture2D(10, 10);
                    t2d.LoadImage(bytes);
                    t2d.Apply();
                    nowgfd.callBack?.Invoke(t2d);
                }else

                {
                    Debug.Log("55555555555555");
                    nowgfd.callBack?.Invoke(null);

                }

          
            isDownLoad = false;
            nowgfd = null;
        }
    }

    public class FileData
    {
        public string filePath;
        public string fileName;
        public Action<string> callBack;
    }

    public class GetFileData
    {
        public string bucket;
        public string objectName;
        public Action<Texture2D> callBack;
    }

}