using System.Collections.ObjectModel;
using System.Net.Http.Headers;
using Avalonia.Media;
using Avalonia.Threading;
using CommunityToolkit.Mvvm.DependencyInjection;
using DynamicData;
using DynamicData.Binding;
using HetznerCloudApi;
using Material.Icons;
using Newtonsoft.Json.Linq;
using PSCHelpdesk.Plugins.HetznerServer.Models;
using PSCHelpdesk.Shared.Service;
using PSCHelpdesk.Shared.Setting;
using PSCHelpdesk.Shared.Tasks;
using ReactiveUI;
using Renci.SshNet;

namespace PSCHelpdesk.Plugins.HetznerServer.Service;

public class ServerService: IServerService
{
    public SourceCache<Server, long> SourceCache = new (x => x.ServerId);
    private SettingsManager _settingsManager;
    private readonly DispatcherTimer _reloadTimer = new DispatcherTimer();
    private string _searchText = string.Empty;
    private ITaskManager _taskManager;
    private readonly IToastManager? _toastManager;

    public ServerService()
    {
        _settingsManager = (SettingsManager)Ioc.Default.GetService<ISettingsManager>();
        _taskManager = Ioc.Default.GetService<ITaskManager>();
        _toastManager = (IToastManager)Ioc.Default.GetService<IToastManager>();
        this._reloadTimer.Tick += (sender, args) =>
        {
            this.reloadServerStatus();
        };
        _reloadTimer.Interval = TimeSpan.FromMinutes(60);
        _reloadTimer.Start();

        reloadServer();
    }
    
    private async Task reloadServer()
    {
        var settings = new Settings();
        _settingsManager.LoadPluginSettings("HetznerSettings", settings);
        if (settings.HetznerApiKey != "")
        {
            HetznerCloudClient hetznerCloudClient = new HetznerCloudClient(settings.HetznerApiKey);

            List<HetznerCloudApi.Object.Server.Server> list = await hetznerCloudClient.Server.Get();
            foreach (var server in list)
            {
                var uiDispatcher = Ioc.Default.GetService<IUserInterfaceDispatchService>();
                await uiDispatcher.InvokeAsync(() =>
                {
                    SourceCache.AddOrUpdate(new Server(server.Id, server.Name, server.ServerType.Name, server.Status,
                        server.PublicNet.Ipv4.Ip, server.PublicNet.Ipv6.Ip));
                });
                
            }
        }
        await Task.Run(async () => await this.reloadServerStatus());
    }

    private async Task reloadServerStatus()
    {
        var uiDispatcher = Ioc.Default.GetService<IUserInterfaceDispatchService>();

        await uiDispatcher.InvokeAsync(() =>
        {
            _reloadTimer.Stop();
        });
        
        var settings = new Settings();
        _settingsManager.LoadPluginSettings("HetznerSettings", settings);
        
        foreach (Server serv in SourceCache.Items)
        {
            doScan(serv);
        }
        
        await uiDispatcher.InvokeAsync(() =>
        {
            this._reloadTimer.Start();
        });
    }

    public void SaveSettings(Server selectedServer)
    {
        var settings = new Settings();
        _settingsManager.LoadPluginSettings("HetznerSettings", settings);
        if (settings.ServerSettings.Count(e => e.ServerId == selectedServer.ServerId) > 0)
        {
            settings.ServerSettings.First(e => e.ServerId == selectedServer.ServerId).FastBillId = selectedServer.FastBillId;
            settings.ServerSettings.First(e => e.ServerId == selectedServer.ServerId).PscApiKey = selectedServer.PscApiKey;
            settings.ServerSettings.First(e => e.ServerId == selectedServer.ServerId).FastBillNr = selectedServer.FastBillNr;
        }
        else
        {
            settings.ServerSettings.Add(new ServerSetting(selectedServer.ServerId, selectedServer.PscApiKey, selectedServer.FastBillId, selectedServer.FastBillNr));
        }
        _settingsManager.SavePluginSettings("HetznerSettings", settings);
    }

    public void DoAptUpgrade(Server serv)
    {
        var connectionInfo = new ConnectionInfo(serv.Ipv4,
            "root",
            new PrivateKeyAuthenticationMethod("root",
                new PrivateKeyFile(this._settingsManager.CoreSettings.PrivateSSHKeyPath)));
        using (var client = new SshClient(connectionInfo))
        {
            try
            {
                client.Connect();
                var command = client.RunCommand("apt upgrade -y && apt auto-remove -y");
                if (command.ExitStatus == 0)
                {
                    Console.WriteLine(serv.Name + " SUCCESS upgraded apt.");
                }
                else
                {
                    Console.WriteLine(serv.Name + " ERROR upgraded apt.");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    }
    
    public void DoReboot(Server serv)
    {
        var connectionInfo = new ConnectionInfo(serv.Ipv4,
            "root",
            new PrivateKeyAuthenticationMethod("root",
                new PrivateKeyFile(this._settingsManager.CoreSettings.PrivateSSHKeyPath)));
        using (var client = new SshClient(connectionInfo))
        {
            try
            {
                client.Connect();
                var command = client.RunCommand("reboot");
                if (command.ExitStatus == 0)
                {
                    Console.WriteLine(serv.Name + " SUCCESS Reboot");
                }
                else
                {
                    Console.WriteLine(serv.Name + " ERROR Reboot");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    }

    public void DoReScan(Server serv)
    {
        doScan(serv);
    }

    async private void doScan(Server serv)
    {
        var settings = new Settings();
        _settingsManager.LoadPluginSettings("HetznerSettings", settings);
        
        if (settings.ServerSettings.Count(e => e.ServerId == serv.ServerId) > 0)
        {
            serv.FastBillId = settings.ServerSettings.First(e => e.ServerId == serv.ServerId).FastBillId;
            serv.FastBillNr = settings.ServerSettings.First(e => e.ServerId == serv.ServerId).FastBillNr;
            serv.PscApiKey = settings.ServerSettings.First(e => e.ServerId == serv.ServerId).PscApiKey;
        }
        
        var connectionInfo = new ConnectionInfo(serv.Ipv4,
            "root",
            new PrivateKeyAuthenticationMethod("root", new PrivateKeyFile(this._settingsManager.CoreSettings.PrivateSSHKeyPath)));
        using (var client = new SshClient(connectionInfo))
        {
            try
            {
                client.Connect();
                var command = client.RunCommand("borgmatic info --json");
                if (command.ExitStatus == 0)
                {
                    serv.HasBackup = true;
                    JArray borgMatic = JArray.Parse(command.Result);
                    serv.BackupLastModified = DateTime.Parse(borgMatic[0]["repository"]["last_modified"].ToString());
                }
                command = client.RunCommand("whereis needrestart");
                if (command.ExitStatus == 0)
                {
                    if (command.Result.Length > 20)
                    {
                        serv.HasNeedRestart = true;
                    }
                }
                command = client.RunCommand("docker inspect psc_mongodb_1");
                if (command.ExitStatus == 0)
                {
                    JArray mongoDB = JArray.Parse(command.Result);
                    var mongoDBEnvArray = mongoDB[0]["Config"]["Env"];

                    foreach (String entry in mongoDBEnvArray)
                    {
                        var mongodDBexploded = entry.Split("=");
                        if (mongodDBexploded[0] == "MONGO_VERSION")
                        {
                            serv.MongoVersion = mongodDBexploded[1];
                        }
                    }
                }
                command = client.RunCommand("docker inspect psc_mysql_1");
                if (command.ExitStatus == 0)
                {
                    JArray mongoDB = JArray.Parse(command.Result);
                    var mongoDBEnvArray = mongoDB[0]["Config"]["Env"];

                    foreach (String entry in mongoDBEnvArray)
                    {
                        var mongodDBexploded = entry.Split("=");
                        if (mongodDBexploded[0] == "MARIADB_VERSION")
                        {
                            serv.MysqlVersion = mongodDBexploded[1];
                        }
                    }
                }

                command = client.RunCommand("docker ps|wc -l");
                if (command.ExitStatus == 0)
                {
                    serv.RunningContainerCount = int.Parse(command.Result);
                }
                command = client.RunCommand("docker inspect psc_web_1");
                if (command.ExitStatus == 0)
                {
                    JArray web = JArray.Parse(command.Result);
                    var hostConfigArray = web[0]["HostConfig"];
                    if (hostConfigArray["RestartPolicy"]["Name"].ToString() == "always")
                    {
                        serv.IsRestartAlways = true;
                    }
                    
                    var webEnvArray = web[0]["Config"]["Env"];

                    foreach (String entry in webEnvArray)
                    {
                        var webExploded = entry.Split("=");
                        if (webExploded[0] == "LETSENCRYPT_HOST")
                        {
                            var webHosts = webExploded[1].Split(",");
                            serv.Domains.Clear();
                            foreach (String dom in webHosts)
                            {
                                serv.Domains.Add(new Domain(dom));
                            }
                            var httpClient = new HttpClient();
                            httpClient.DefaultRequestHeaders.Accept.Clear();
                            httpClient.DefaultRequestHeaders.Accept.Add(
                                new MediaTypeWithQualityHeaderValue("application/ld+json"));
                            httpClient.DefaultRequestHeaders.Add("User-Agent", "PSC Client");
                            try
                            {
                                var stringTask = httpClient.GetStringAsync("https://" + webHosts[0] + "/apps/api/system/version");

                                var msg = await stringTask;
                                JObject versionMSg = JObject.Parse(msg);

                                serv.Datum = versionMSg["datum"].ToString();
                                serv.Release = float.Parse(versionMSg["release"].ToString());
                            }
                            catch (Exception ex)
                            {
                            }
                            
                        }
                    }
                }

                if (serv.PscApiKey != "" && serv.Domains.Count > 0)
                {
                    var httpClient = new HttpClient();
                    httpClient.DefaultRequestHeaders.Accept.Clear();
                    httpClient.DefaultRequestHeaders.Accept.Add(
                        new MediaTypeWithQualityHeaderValue("application/ld+json"));
                    httpClient.DefaultRequestHeaders.Add("User-Agent", "PSC Client");
                    httpClient.DefaultRequestHeaders.Add("apiKey", serv.PscApiKey);
                    try
                    {
                        var stringPlugins =
                            httpClient.GetStringAsync("https://" + serv.Domains.First().Name + "/apps/api/plugins");
                        var msg = await stringPlugins;
                        JObject pluginMsg = JObject.Parse(msg);
                        foreach (var plugin in pluginMsg["data"])
                        {
                            serv.Plugins.Add(new Plugin()
                            {
                                Installed = bool.Parse(plugin["installed"].ToString()),
                                Title = plugin["title"].ToString(),
                                Uuid = plugin["uuid"].ToString()
                            });
                        }
                    }
                    catch (Exception ex)
                    {
                    }
                    
                }
                
                if (serv.PscApiKey != "" && serv.Domains.Count > 0)
                {
                    var httpClient = new HttpClient();
                    httpClient.DefaultRequestHeaders.Accept.Clear();
                    httpClient.DefaultRequestHeaders.Accept.Add(
                        new MediaTypeWithQualityHeaderValue("application/ld+json"));
                    httpClient.DefaultRequestHeaders.Add("User-Agent", "PSC Client");
                    httpClient.DefaultRequestHeaders.Add("apiKey", serv.PscApiKey);
                    try
                    {
                        var stringPlugins =
                            httpClient.GetStringAsync("https://" + serv.Domains.First().Name + "/apps/api/system/info");
                        var msg = await stringPlugins;
                        JObject systemInfo = JObject.Parse(msg);
                        serv.Instance.SftpUserName = systemInfo["sftpUserName"].ToString();
                        serv.Instance.SftpPassword = systemInfo["sftpPassword"].ToString();
                        serv.Instance.SftpHostName = systemInfo["sftpHost"].ToString();
                        serv.Instance.SmtpOwn = bool.Parse(systemInfo["smtpOwn"].ToString());
                    }
                    catch (Exception ex)
                    {
                    }
                    
                }

                if (serv.PscApiKey.Length > 0)
                {
                    serv.IsGoodIcon = MaterialIconKind.Check;
                    serv.IsGoodColor = Brushes.Green;
                }
                
                client.Disconnect();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }
    }
}