using System.Net.Sockets;
using System.Text;

namespace ServiceLib.Handler
{
    public class PacHandler
    {
        private static string _configPath;
        private static int _httpPort;
        private static int _pacPort;
        private static TcpListener? _tcpListener;
        private static byte[] _writeContent;
        private static bool _isRunning;
        private static bool _needRestart = true;

        public static async Task Start(string configPath, int httpPort, int pacPort)
        {
            _needRestart = (configPath != _configPath || httpPort != _httpPort || pacPort != _pacPort || !_isRunning);

            _configPath = configPath;
            _httpPort = httpPort;
            _pacPort = pacPort;

            await InitText();

            if (_needRestart)
            {
                Stop();
                RunListener();
            }
        }

        private static async Task InitText()
        {
            var path = Path.Combine(_configPath, "pac.txt");
            if (!File.Exists(path))
            {
                var pac = Utils.GetEmbedText(Global.PacFileName);
                await File.AppendAllTextAsync(path, pac);
            }

            var pacText =
                (await File.ReadAllTextAsync(path)).Replace("__PROXY__", $"PROXY 127.0.0.1:{_httpPort};DIRECT;");

            var sb = new StringBuilder();
            sb.AppendLine("HTTP/1.0 200 OK");
            sb.AppendLine("Content-type:application/x-ns-proxy-autoconfig");
            sb.AppendLine("Connection:close");
            sb.AppendLine("Content-Length:" + Encoding.UTF8.GetByteCount(pacText));
            sb.AppendLine();
            sb.Append(pacText);
            _writeContent = Encoding.UTF8.GetBytes(sb.ToString());
        }

        private static void RunListener()
        {
            _tcpListener = TcpListener.Create(_pacPort);
            _isRunning = true;
            _tcpListener.Start();
            Task.Factory.StartNew(async () =>
            {
                while (_isRunning)
                {
                    try
                    {
                        if (!_tcpListener.Pending())
                        {
                            await Task.Delay(10);
                            continue;
                        }

                        var client = await _tcpListener.AcceptTcpClientAsync();
                        await Task.Run(() => { WriteContent(client); });
                    }
                    catch
                    {
                        // ignored
                    }
                }
            }, TaskCreationOptions.LongRunning);
        }

        private static void WriteContent(TcpClient client)
        {
            var stream = client.GetStream();
            stream.Write(_writeContent, 0, _writeContent.Length);
            stream.Flush();
        }

        public static void Stop()
        {
            if (_tcpListener == null) return;
            try
            {
                _isRunning = false;
                _tcpListener.Stop();
                _tcpListener = null;
            }
            catch
            {
                // ignored
            }
        }
    }
}