using System;
using System.Text;
using Newtonsoft.Json;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Networking;
using System.Collections.Generic;
using Cysharp.Threading.Tasks;

public struct Response<T>
{
    public long responseCode { get; set; }
    public string responseText { get; set; }
    public T responseData { get; set; }
}

public class NetworkService
{
#if !UNITY_EDITOR
    private string _apiUrl = "https://yandexquest.graff.tech/";
#else
    private string _apiUrl = "http://localhost:5000/";
#endif

    public async UniTask<Response<TValue>> GetAsync<TValue>(string requestString)
    {
        Response<TValue> responseStruct = new Response<TValue>();

        using var getRequest = UnityWebRequest.Get(_apiUrl + requestString);
        getRequest.SetRequestHeader("Content-type", "application/json");
        UnityWebRequest operation = new UnityWebRequest();

        try
        {
            operation = await getRequest.SendWebRequest();
        }
        catch { }

        responseStruct.responseCode = getRequest.responseCode;
        if(getRequest.responseCode != 200)
        {
            responseStruct.responseText = getRequest.downloadHandler.text;
            return responseStruct;
        }

        try
        {
            TValue result = JsonConvert.DeserializeObject<TValue>(operation.downloadHandler.text);
            responseStruct.responseData = result;

            return responseStruct;
        }
        catch(Exception ex)
        {
            responseStruct.responseCode = -1;
            responseStruct.responseText = ex.Message;

            return responseStruct;
        }
    }

    public async UniTask<Response<TValue>> GetAsync<TValue>(string requestString, params string[] query)
    {
        Response<TValue> responseStruct = new Response<TValue>();

        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.Append(requestString);
        stringBuilder.Append("?");

        for (int i = 0; i < query.Length; i++)
        {
            stringBuilder.Append(query[i]);
            if (i != query.Length - 1)
                stringBuilder.Append("&");
        }

        using var getRequest = UnityWebRequest.Get(_apiUrl + stringBuilder.ToString());

        getRequest.SetRequestHeader("Content-type", "application/json");
        UnityWebRequest operation = new UnityWebRequest();

        try
        {
            operation = await getRequest.SendWebRequest();
        }
        catch { }

        responseStruct.responseCode = getRequest.responseCode;
        if(getRequest.responseCode != 200)
        {
            responseStruct.responseText = getRequest.downloadHandler.text;
            return responseStruct;
        }

        try
        {
            TValue result = JsonConvert.DeserializeObject<TValue>(operation.downloadHandler.text);
            responseStruct.responseData = result;
            return responseStruct;
        }
        catch(Exception ex)
        {
            responseStruct.responseCode = -1;
            responseStruct.responseText = ex.Message;
            return responseStruct;
        }
    }

    public async UniTask<Response<TValue>> GetAsync<TValue>(string requestString, Dictionary<string, string> headers = null, params string[] query)
    {
        Response<TValue> responseStruct = new Response<TValue>();

        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.Append(requestString);
        stringBuilder.Append("?");

        for (int i = 0; i < query.Length; i++)
        {
            stringBuilder.Append(query[i]);
            if (i != query.Length - 1)
                stringBuilder.Append("&");
        }

        using var getRequest = UnityWebRequest.Get(_apiUrl + stringBuilder.ToString());
        if(headers != null)
            foreach(var header in headers)
                getRequest.SetRequestHeader(header.Key, header.Value);

        getRequest.SetRequestHeader("Content-type", "application/json");
        UnityWebRequest operation = new UnityWebRequest();

        try
        {
            operation = await getRequest.SendWebRequest();
        }
        catch { }

        responseStruct.responseCode = getRequest.responseCode;
        if(getRequest.responseCode != 200)
        {
            responseStruct.responseText = getRequest.downloadHandler.text;
            return responseStruct;
        }

        try
        {
            TValue result = JsonConvert.DeserializeObject<TValue>(operation.downloadHandler.text);
            responseStruct.responseData = result;

            return responseStruct;
        }
        catch(Exception ex)
        {
            responseStruct.responseCode = -1;
            responseStruct.responseText = ex.Message;

            return default;
        }
    }

    public async UniTask PostAsync<TValue> (string requestString, TValue data, Dictionary<string, string> headers = null)
    {   
        string sendingData = JsonConvert.SerializeObject(data);
        using var postRequest = UnityWebRequest.Post(_apiUrl + requestString, sendingData);
        byte[] dataBytes = new UTF8Encoding().GetBytes(sendingData);
        postRequest.uploadHandler = new UploadHandlerRaw(dataBytes);
        postRequest.downloadHandler = new DownloadHandlerBuffer();

        if(headers != null)
        {
            foreach(var header in headers)
                postRequest.SetRequestHeader(header.Key, header.Value);
        }

        postRequest.SetRequestHeader("Content-Type", "application/json");
        UnityWebRequest operation = new UnityWebRequest();

        try
        {
            operation = await postRequest.SendWebRequest();
        }
        catch { }
    }

    public async UniTask<Response<TResponseValue>> PostAsync<TSendingValue, TResponseValue> (string requestString, TSendingValue data)
    {
        Response<TResponseValue> responseStruct = new Response<TResponseValue>();

        string sendingData = JsonConvert.SerializeObject(data);
        using var postRequest = UnityWebRequest.Post(_apiUrl + requestString, sendingData);
        byte[] dataBytes = new UTF8Encoding().GetBytes(sendingData);
        postRequest.uploadHandler = new UploadHandlerRaw(dataBytes);
        postRequest.downloadHandler = new DownloadHandlerBuffer();
        postRequest.SetRequestHeader("Content-Type", "application/json");

        UnityWebRequest operation = new UnityWebRequest();

        try
        {
            operation = await postRequest.SendWebRequest();
        }
        catch { }

        responseStruct.responseCode = postRequest.responseCode;
        if(postRequest.responseCode != 200)
        {
            responseStruct.responseText = postRequest.downloadHandler.text;
            return responseStruct;
        }

        try
        {
            TResponseValue result = JsonConvert.DeserializeObject<TResponseValue>(operation.downloadHandler.text);
            responseStruct.responseData = result;

            return responseStruct;
        }
        catch(Exception ex)
        {
            responseStruct.responseCode = -1;
            responseStruct.responseText = ex.Message;

            return responseStruct;
        }
    }

    public async UniTask PutAsync<TValue>(string requestString, TValue data)
    {
        string sendingData = JsonConvert.SerializeObject(data);

        using var putRequest = UnityWebRequest.Put(_apiUrl + requestString, sendingData);
        byte[] dataBytes = new UTF8Encoding().GetBytes(sendingData);
        putRequest.uploadHandler = new UploadHandlerRaw(dataBytes);
        putRequest.downloadHandler = new DownloadHandlerBuffer();
        putRequest.SetRequestHeader("Content-Type", "application/json");

        UnityWebRequest operation = new UnityWebRequest();

        try
        {
            operation = await putRequest.SendWebRequest();
        }
        catch { }
    }
}