using LitJson;
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;
using XRTool.Util;

public class LangChaoMinIo : MonoSingleton<LangChaoMinIo>
{
    IMinioClient minio;
    string path;
    string bucket;
    string host;

    string tmpSecretId;
    string tmpSecretKey;
    string minioToken;

    int projectId;
    Thread thread;
    private void Start()
    {
        thread = new Thread(DoSomeWork);
        thread.Start();
    }

    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);
        }
    }

    void initMinIo(Action<bool> callBack)
    {
        JsonData data = new JsonData();
        data["inspectionId"] = projectId;
        GameStart.Instance.StartCoroutine(HttpTool.Instance.SendHttp(HttpActionLang.storage_inspectionCredential, data.ToJson(), async (string str) =>
        {
            try
            {

                JsonData d = JsonMapper.ToObject(str);
                minioToken = d["data"]["credentials"]["token"].ToString();
                tmpSecretId = d["data"]["credentials"]["tmpSecretId"].ToString();
                tmpSecretKey = d["data"]["credentials"]["tmpSecretKey"].ToString();
                host = d["data"]["host"].ToString();
                bucket = d["data"]["bucket"].ToString();
                path = d["data"]["path"].ToString();
                Debug.Log(str);
                bool isHttps = host.Contains("https");
                var endpoint = host.Split("//")[1];
                var accessKey = tmpSecretId;//"tr6Nh5D8bnlGaLJE6vb5";
                var secretKey = tmpSecretKey;// "aVOYdXLnX4MCiKbit8aomZNWvAx8YSpzhiwzFhrI";
                Debug.Log("endpoint===>" + endpoint + "    isHttps==>" + isHttps);
                minio = new MinioClient()
                                    .WithEndpoint(endpoint)
                                    .WithCredentials(accessKey, secretKey)
                                    .WithSessionToken(minioToken)
                                    .WithSSL(isHttps)
                                    .Build();
                TimerMgr.Instance.CreateTimer(() =>
                {

                    minio = null;
                }, 1200);
                callBack?.Invoke(true);
            }
            catch
            {
                callBack?.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 = 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()
    {
        Debug.LogError(bucket);
        Debug.LogError(path + "/" + nowgfd.objectName);
        try
        {

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

            // Get input stream to have content of 'my-objectname' from 'my-bucketname'
            GetObjectArgs getObjectArgs = new GetObjectArgs()
                                              .WithBucket(bucket)
                                              .WithObject(path + "/" + nowgfd.objectName)
                                              .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 = bucket;
            var objectName = 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((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;
    }

}