using static Community.CsharpSqlite.Sqlite3;

namespace Hawkeye.VisionBuilder.Workflow.DataTransfer;

public class CSharpDataTransferHTTP
{
    private readonly PythonModelAPI _api;
    private readonly HttpClient _client;
    private readonly CancellationTokenSource _pingCts = new();
    private readonly Thread _pingThread;
    private readonly object _lock = new();

    public CSharpDataTransferHTTP()
    {
        var handler = new SocketsHttpHandler
        {
            PooledConnectionIdleTimeout = TimeSpan.FromSeconds(10),
            MaxConnectionsPerServer = 100
        };
        _client = new HttpClient(handler)
        {
            DefaultRequestHeaders =
            {
                ExpectContinue = false
            }
        };
        _api = new PythonModelAPI("http://localhost:8000", _client);
        _pingThread = new Thread(PingLoop) { IsBackground = true };
        _pingThread.Start();
    }

    private void PingLoop()
    {
        while (!_pingCts.Token.IsCancellationRequested)
        {
            try
            {
                _client.GetAsync("http://localhost:8000/").Wait();
            }
            catch
            {
                // Ignore errors, optionally log
            }
            Thread.Sleep(3000); // Ping every 3 seconds
        }
    }

    public void LoadModel(string path, string modelName)
    {
        lock (_lock)
        {
            _api.LoadModelAsync(new LoadModelIn()
            {
                Name = modelName,
                Path = Path.GetFileName(path)
            }).Wait();
        }
    }

    public void ActivateModel(string modelName)
    {
        lock (_lock)
        {
            _api.ActivateModelAsync(new ActivateModelIn() { Name = modelName }).Wait();
        }
    }

    public int[] GetAcceptSize()
    {
        var response = _api.GetAcceptSizeAsync().Result;
        return response.Accept_size.ToArray();
    }

    public int[] GetOutputSize()
    {
        var response = _api.GetOutputSizeAsync().Result;
        return response.Accept_size.ToArray();
    }

    public byte[] PredictRaw(byte[] byteArray)
    {
        var response = _api.PredictRawAsync(new FileParameter(new MemoryStream(byteArray))).Result;
        var stream = response.Stream;
        using var memoryStream = new MemoryStream();
        stream.CopyTo(memoryStream);
        memoryStream.Seek(0, SeekOrigin.Begin);
        var responseBytes = memoryStream.ToArray();
        return responseBytes;
    }

    public byte[] Predict(byte[] byteArray)
    {
        lock (_lock)
        {
            var response = _api.PredictAsync(new FileParameter(new MemoryStream(byteArray))).Result;
            var stream = response.Stream;
            using var memoryStream = new MemoryStream();
            stream.CopyTo(memoryStream);
            memoryStream.Seek(0, SeekOrigin.Begin);
            var responseBytes = memoryStream.ToArray();
            return responseBytes;
        }
    }
}