using System;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using Best.HTTP;
using IchniOnline.Online.Network.Models;
using UnityEngine;
namespace IchniOnline.Online.Network
{
///
/// BestHTTP-based API client singleton for IchniOnline backend communication.
/// Pure HTTP layer — no business logic.
///
public class IchniOnlineApiClient
{
private static IchniOnlineApiClient _instance;
public static IchniOnlineApiClient Instance => _instance ??= new IchniOnlineApiClient();
public string BaseUrl { get; set; } = "http://localhost:53734";
public string JwtToken { get; set; }
private IchniOnlineApiClient() { }
public async Task> GetAsync(string endpoint)
{
string url = BuildUrl(endpoint);
var request = new HTTPRequest(new Uri(url), HTTPMethods.Get);
AddAuthHeader(request);
try
{
var resp = await request.GetHTTPResponseAsync();
return ProcessResponse(resp);
}
catch (Exception ex)
{
return ApiResult.Fail(ResponseCode.InternalServerError, "Network error", ex.Message);
}
}
public async Task> PostAsync(string endpoint, object body)
{
string url = BuildUrl(endpoint);
var request = new HTTPRequest(new Uri(url), HTTPMethods.Post);
request.SetHeader("Content-Type", "application/json");
AddAuthHeader(request);
if (body != null)
{
string jsonBody = JsonUtility.ToJson(body);
request.UploadSettings.UploadStream = new MemoryStream(Encoding.UTF8.GetBytes(jsonBody));
}
try
{
var resp = await request.GetHTTPResponseAsync();
return ProcessResponse(resp);
}
catch (Exception ex)
{
return ApiResult.Fail(ResponseCode.InternalServerError, "Network error", ex.Message);
}
}
private string BuildUrl(string endpoint)
{
if (string.IsNullOrEmpty(BaseUrl))
throw new InvalidOperationException("BaseUrl is not configured.");
string baseUrl = BaseUrl.TrimEnd('/');
string path = endpoint.StartsWith("/") ? endpoint : $"/{endpoint}";
return baseUrl + path;
}
private void AddAuthHeader(HTTPRequest request)
{
if (!string.IsNullOrEmpty(JwtToken))
{
request.SetHeader("Authorization", $"Bearer {JwtToken}");
}
}
private ApiResult ProcessResponse(HTTPResponse resp)
{
string json = resp.DataAsText;
if (resp.StatusCode >= 200 && resp.StatusCode < 300)
{
if (string.IsNullOrEmpty(json))
{
return ApiResult.Fail(ResponseCode.InternalServerError, "Empty response body");
}
var response = JsonUtility.FromJson(json, typeof(GlobalResponse)) as GlobalResponse;
if (response == null)
{
return ApiResult.Fail(ResponseCode.InternalServerError, "Failed to parse response JSON");
}
if (response.Code == ResponseCode.Ok)
{
return ApiResult.Ok(response.Data);
}
return ApiResult.Fail(response.Code, response.Message);
}
// Non-2xx: try to parse server error body
if (!string.IsNullOrEmpty(json))
{
var errorResponse = JsonUtility.FromJson(json, typeof(GlobalResponseBase)) as GlobalResponseBase;
if (errorResponse != null)
{
return ApiResult.Fail(errorResponse.Code, errorResponse.Message);
}
}
return ApiResult.Fail(ResponseCode.InternalServerError, $"HTTP error {resp.StatusCode}");
}
}
}