using System;
using System.Linq;
using Deploymentcenter.Client;
using PolyTrader.Core;
using PolyTrader.Core.Security;
using PolyTraderSharp.Models;

namespace PolyTrader.App.Avalonia.Licensing
{
    /// <summary>
    /// Kopflose Lizenzverwaltung von der Kommandozeile aus (D-2), nach der Konvention aus
    /// LICENSE_INTEGRATION_GUIDE §4: <c>--license-status</c>, <c>--license-set-key</c>,
    /// <c>--license-deactivate</c>. Diese Schalter baut die Anwendung selbst, das SDK bringt nur die
    /// Bausteine mit. Läuft VOR dem Host-Aufbau und beendet den Prozess über den Rückgabewert.
    /// </summary>
    internal static class LicenseCli
    {
        /// <summary>Liefert <c>true</c>, wenn einer der Lizenz-Schalter erkannt und abgearbeitet wurde.</summary>
        public static bool TryHandle(string[] args, out int exitCode)
        {
            exitCode = 0;

            if (args.Any(a => string.Equals(a, "--license-status", StringComparison.OrdinalIgnoreCase)))
            {
                exitCode = Status();
                return true;
            }

            int setIdx = Array.FindIndex(args, a => string.Equals(a, "--license-set-key", StringComparison.OrdinalIgnoreCase));
            if (setIdx >= 0)
            {
                string? key = setIdx + 1 < args.Length ? args[setIdx + 1] : null;
                exitCode = SetKey(key);
                return true;
            }

            if (args.Any(a => string.Equals(a, "--license-deactivate", StringComparison.OrdinalIgnoreCase)))
            {
                exitCode = Deactivate();
                return true;
            }

            return false;
        }

        private static int Status()
        {
            var options = Program.LoadDeploymentcenterOptions();
            var hw = HardwareId.GetHardwareId(options.ProjectSlug);
            var cached = LicenseClient.TryGetCachedState(options.ProjectSlug);

            Console.WriteLine($"HWID v2:   {hw.HardwareId} ({hw.HwidSource})");
            Console.WriteLine($"Produkt:   {options.ProjectSlug}");
            Console.WriteLine($"Server:    {(string.IsNullOrWhiteSpace(options.BaseUrl) ? "(keine URL konfiguriert)" : options.BaseUrl)}");
            Console.WriteLine($"Cache:     {(cached == null ? "leer" : cached.Status)}");

            if (cached != null && cached.CacheExpiresAt > 0)
            {
                var until = DateTimeOffset.FromUnixTimeSeconds(cached.CacheExpiresAt);
                Console.WriteLine($"Offline noch bis: {until:u}");
            }

            var settings = ServerSettings.Load("server_settings.xml");
            Console.WriteLine($"Gespeicherter Schlüssel (server_settings.xml): {(string.IsNullOrWhiteSpace(settings.LicenseKey) ? "keiner" : settings.LicenseKeyStatus)}");
            return 0;
        }

        private static int SetKey(string? key)
        {
            if (string.IsNullOrWhiteSpace(key))
            {
                Console.Error.WriteLine("Fehler: --license-set-key erwartet den Schlüssel als nächstes Argument.");
                return 1;
            }

            var options = Program.LoadDeploymentcenterOptions();
            if (string.IsNullOrWhiteSpace(options.BaseUrl))
            {
                Console.Error.WriteLine("Fehler: Keine Deploymentcenter-URL konfiguriert (appsettings.json: Deploymentcenter:BaseUrl).");
                return 1;
            }

            LicenseClient.DefaultAppVersion = BuildInfo.Version;
            var client = new LicenseClient();
            LicenseValidationResult result = client
                .ValidateAsync(options.ProjectSlug, key.Trim(), options.BaseUrl, BuildInfo.Version)
                .GetAwaiter().GetResult();

            Console.WriteLine($"{result.Status}: {result.Message}");
            if (!result.IsValid)
            {
                return 1;
            }

            const string settingsPath = "server_settings.xml";
            var settings = ServerSettings.Load(settingsPath);
            settings.LicenseKey = SecretProtection.Protect(key.Trim());
            settings.Save(settingsPath);
            Console.WriteLine($"Lizenz gültig und in {settingsPath} gespeichert " +
                               $"({(SecretProtection.IsEncrypted(settings.LicenseKey) ? "verschlüsselt" : "Klartext")}).");
            return 0;
        }

        private static int Deactivate()
        {
            var options = Program.LoadDeploymentcenterOptions();
            var settings = ServerSettings.Load("server_settings.xml");

            string key;
            try { key = SecretProtection.Unprotect(settings.LicenseKey); }
            catch (Exception ex)
            {
                Console.Error.WriteLine($"Fehler: gespeicherter Schlüssel nicht lesbar: {ex.Message}");
                return 1;
            }

            if (string.IsNullOrWhiteSpace(key))
            {
                Console.Error.WriteLine("Fehler: kein Lizenzschlüssel hinterlegt.");
                return 1;
            }

            // Die Deaktivierung gibt einen Aktivierungsplatz frei und ist deshalb geschützt - der
            // shared_key gehört auf den Administrationsrechner, nicht in die ausgelieferte
            // Anwendung (siehe LICENSE_INTEGRATION_GUIDE). Ohne ihn: klarer Hinweis statt Versuch.
            string? sharedKey = Environment.GetEnvironmentVariable("DC_SHARED_KEY");
            if (string.IsNullOrWhiteSpace(sharedKey))
            {
                Console.Error.WriteLine("Fehler: DC_SHARED_KEY nicht gesetzt. Die Deaktivierung braucht den " +
                                         "administrativen Shared Key - alternativ im Deploymentcenter-WebUI unter " +
                                         "der Hardware-Liste auf „Freigeben\" klicken.");
                return 1;
            }

            var client = new LicenseClient();
            bool ok = client.DeactivateAsync(options.ProjectSlug, key, options.BaseUrl, sharedKey)
                .GetAwaiter().GetResult();

            Console.WriteLine(ok ? "Aktivierung freigegeben." : "Deaktivierung fehlgeschlagen.");
            return ok ? 0 : 1;
        }
    }
}
