using System.Collections.ObjectModel;
using System.Net.Http.Headers;
using Avalonia.Threading;
using CommunityToolkit.Mvvm.DependencyInjection;
using DynamicData;
using DynamicData.Binding;
using HetznerCloudApi;
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.Id);
    private SettingsManager _settingsManager;
    private readonly DispatcherTimer _reloadTimer = new DispatcherTimer();
    private string _searchText = string.Empty;
    private static readonly HttpClient httpClient = new HttpClient();
    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(10);
        _reloadTimer.Start();
        
        this.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));
                });
                
            }
        }
        Task.Run(async () => await this.reloadServerStatus());
    }

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

        await uiDispatcher.InvokeAsync(() =>
        {
            _reloadTimer.Stop();
        });
        foreach (Server serv in SourceCache.Items)
        {
            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);
                        await uiDispatcher.InvokeAsync(() =>
                        {
                            serv.BackupLastModified = DateTime.Parse(borgMatic[0]["repository"]["last_modified"].ToString());
                        });

                    }
                    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 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));
                                }

                                httpClient.DefaultRequestHeaders.Accept.Clear();
                                httpClient.DefaultRequestHeaders.Accept.Add(
                                    new MediaTypeWithQualityHeaderValue("application/ld+json"));
                                httpClient.DefaultRequestHeaders.Add("User-Agent", "PSC Client");

                                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());

                                
                            }
                        }
                    }

                    client.Disconnect();
                    _toastManager.DisplayNewToast("Server " + serv.Name + " finished");
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
            }

        }
        
        await uiDispatcher.InvokeAsync(() =>
        {
            this._reloadTimer.Start();
        });
    }
}