namespace ServiceLib.Handler.SysProxy
{
    public static class SysProxyHandler
    {
        private static readonly string _tag = "SysProxyHandler";

        public static async Task<bool> UpdateSysProxy(Config config, bool forceDisable)
        {
            var type = config.SystemProxyItem.SysProxyType;

            if (forceDisable && type != ESysProxyType.Unchanged)
            {
                type = ESysProxyType.ForcedClear;
            }

            try
            {
                var port = AppHandler.Instance.GetLocalPort(EInboundProtocol.socks);
                var exceptions = config.SystemProxyItem.SystemProxyExceptions.Replace(" ", "");
                if (port <= 0)
                {
                    return false;
                }
                switch (type)
                {
                    case ESysProxyType.ForcedChange when Utils.IsWindows():
                        {
                            GetWindowsProxyString(config, port, out var strProxy, out var strExceptions);
                            ProxySettingWindows.SetProxy(strProxy, strExceptions, 2);
                            break;
                        }
                    case ESysProxyType.ForcedChange when Utils.IsLinux():
                        await ProxySettingLinux.SetProxy(Global.Loopback, port, exceptions);
                        break;

                    case ESysProxyType.ForcedChange when Utils.IsOSX():
                        await ProxySettingOSX.SetProxy(Global.Loopback, port, exceptions);
                        break;

                    case ESysProxyType.ForcedClear when Utils.IsWindows():
                        ProxySettingWindows.UnsetProxy();
                        break;

                    case ESysProxyType.ForcedClear when Utils.IsLinux():
                        await ProxySettingLinux.UnsetProxy();
                        break;

                    case ESysProxyType.ForcedClear when Utils.IsOSX():
                        await ProxySettingOSX.UnsetProxy();
                        break;

                    case ESysProxyType.Pac when Utils.IsWindows():
                        await SetWindowsProxyPac(port);
                        break;
                }

                if (type != ESysProxyType.Pac && Utils.IsWindows())
                {
                    PacHandler.Stop();
                }
            }
            catch (Exception ex)
            {
                Logging.SaveLog(_tag, ex);
            }
            return true;
        }

        private static void GetWindowsProxyString(Config config, int port, out string strProxy, out string strExceptions)
        {
            strExceptions = config.SystemProxyItem.SystemProxyExceptions.Replace(" ", "");
            if (config.SystemProxyItem.NotProxyLocalAddress)
            {
                strExceptions = $"<local>;{strExceptions}";
            }

            strProxy = string.Empty;
            if (Utils.IsNullOrEmpty(config.SystemProxyItem.SystemProxyAdvancedProtocol))
            {
                strProxy = $"{Global.Loopback}:{port}";
            }
            else
            {
                strProxy = config.SystemProxyItem.SystemProxyAdvancedProtocol
                    .Replace("{ip}", Global.Loopback)
                    .Replace("{http_port}", port.ToString())
                    .Replace("{socks_port}", port.ToString());
            }
        }

        private static async Task SetWindowsProxyPac(int port)
        {
            var portPac = AppHandler.Instance.GetLocalPort(EInboundProtocol.pac);
            await PacHandler.Start(Utils.GetConfigPath(), port, portPac);
            var strProxy = $"{Global.HttpProtocol}{Global.Loopback}:{portPac}/pac?t={DateTime.Now.Ticks}";
            ProxySettingWindows.SetProxy(strProxy, "", 4);
        }
    }
}