using Newtonsoft.Json;
using Octopus.Simulator.Networks;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using Unity.VisualScripting.Antlr3.Runtime;
using UnityEngine;
using UnityEngine.Networking;
using Octopus.Simulator;

namespace Octopus.Simulator.Networks
{
    //API를 통해 서버와 통신하기 위한 함수들이 내장되어 있습니다.
    //Post, Get. Put을 사용하며, Post의 경우엔 Class를 입력으로 받아 Json형식으로 변환하여 업로드합니다.
    //비동기로 실행하기 위해 Coroutine으로 제작되었으며, callback의 bool값을 통해 서버로부터
    //정상적으로 API가 입력, 결과가 출력되었는지를 확인할 수 있습니다.
    public class WebManager : MonoBehaviour
    {
        public static WebManager webManager;
        public APIEndPointsConfig apiConfig;
        public SimulationInfo info;

        [SerializeField]
        string WebPath = "";
        [SerializeField]
        string ApiPath = "";
        string host = "";
        string token = "";
        int port;
        string http;

        void Awake()
        {
            webManager = this;
            SetWebConfig();
            SetApiConfig(); 
            Request_Get("/simulation/histories/1", (flag, value) =>
            {
                if (flag)
                {
                    Debug.Log(value);
                    info = JsonConvert.DeserializeObject<SimulationInfo>(value);
                }
            });
        }

        private void SetWebConfig()
        {
            string path = Application.streamingAssetsPath + WebPath;
            string json;
            using (StreamReader reader = new StreamReader(path))
            {
                json = reader.ReadToEnd();
            }
            WebConfigList ConfigList = JsonConvert.DeserializeObject<WebConfigList>(json);
            var config = ConfigList.configs[0];
            host = config.host;
            port = config.port;
            token = config.accessToken;
            http = $"{host}:{port}";
        }

        private void SetApiConfig()
        {
            string path = Application.streamingAssetsPath + ApiPath;
            string json;
            using (StreamReader reader = new StreamReader(path))
            {
                json = reader.ReadToEnd();
            }
            apiConfig = JsonConvert.DeserializeObject<APIEndPointsConfig>(json);
        }

        //Post동작을 실행하는 함수입니다
        public void Request_Post(object inputclass, string type, System.Action<bool, string> ResultCallback)
        {
            //입력된 클래스를 json데이터로 변환합니다.
            string json = JsonConvert.SerializeObject(inputclass);
            StartCoroutine(Web_Post(http + type, json, (result, text) =>
            {
                ResultCallback(result, text);
            }));
        }

        //Get동작을 실행하는 함수입니다.
        public void Request_Get(string type, System.Action<bool, string> ResultCallback)
        {
            StartCoroutine(Web_Get(http + type, (result, text) =>
            {
                ResultCallback(result, text);
            }));
        }

        //Put동작을 실행하는 함수입니다.
        public void Request_Put(string type, System.Action<bool, string> ResultCallback)
        {
            StartCoroutine(Web_Put(http + type, (result, text) =>
            {
                ResultCallback(result, text);
            }));
        }

        IEnumerator Web_Post(string URL, string json, System.Action<bool, string> callback)
        {
            using (UnityWebRequest request = UnityWebRequest.PostWwwForm(URL, json))
            {
                byte[] jsonToSend = new System.Text.UTF8Encoding().GetBytes(json);

                request.uploadHandler.Dispose();
                request.uploadHandler = new UploadHandlerRaw(jsonToSend);
                request.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
                request.SetRequestHeader("Authorization", "Bearer " + token);

                yield return request.SendWebRequest();

                //result가 에러로 왔다면
                if ((request.result == UnityWebRequest.Result.ConnectionError) || (request.result == UnityWebRequest.Result.ProtocolError))
                {
                    Debug.Log(request.error);
                    //callback을 false로 하고 텍스트를 리턴합니다.
                    callback(false, request.downloadHandler.text);
                }
                else
                {
                    //result가 에러가 아니라면, callback을 true로 하고 텍스트를 리턴합니다.
                    Debug.Log(request.downloadHandler.text);
                    callback(true, request.downloadHandler.text);
                }
            }
        }

        IEnumerator Web_Get(string URL, System.Action<bool, string> callback)
        {
            using (UnityWebRequest request = UnityWebRequest.Get(URL))
            {
                request.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
                request.SetRequestHeader("Authorization", "Bearer " + token);


                yield return request.SendWebRequest();

                //result가 에러로 왔다면
                if ((request.result == UnityWebRequest.Result.ConnectionError) || (request.result == UnityWebRequest.Result.ProtocolError))
                {
                    Debug.Log(request.error);
                    //callback을 false로 하고 텍스트를 리턴합니다.
                    callback(false, request.downloadHandler.text);
                }
                else
                {
                    //result가 에러가 아니라면, callback을 true로 하고 텍스트를 리턴합니다.
                    Debug.Log(request.downloadHandler.text);
                    callback(true, request.downloadHandler.text);
                }
            }
        }

        IEnumerator Web_Put(string URL, System.Action<bool, string> callback)
        {
            byte[] data = { };
            using (UnityWebRequest request = UnityWebRequest.Put(URL, data))
            {
                request.downloadHandler = (DownloadHandler)new DownloadHandlerBuffer();
                request.SetRequestHeader("Authorization", "Bearer " + token);


                yield return request.SendWebRequest();

                //result가 에러로 왔다면
                if ((request.result == UnityWebRequest.Result.ConnectionError) || (request.result == UnityWebRequest.Result.ProtocolError))
                {
                    Debug.Log(request.error);
                    //callback을 false로 하고 텍스트를 리턴합니다.
                    callback(false, request.downloadHandler.text);
                }
                else
                {
                    //result가 에러가 아니라면, callback을 true로 하고 텍스트를 리턴합니다.
                    Debug.Log(request.downloadHandler.text);
                    callback(true, request.downloadHandler.text);
                }
            }
        }
    }
}