using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Management;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;

namespace LicenseClient
{
    /// <summary>
    /// Vollständige Lizenzserver-Integration für .NET-Anwendungen
    /// </summary>
    public class LicenseManager : IDisposable
    {
        private readonly HttpClient httpClient;
        private readonly string apiKey;
        private readonly string appVersion;
        private readonly string serverUrl = "https://api-software-undso.z5m7q9dk3ah2v1plx6ju.com";
        private readonly string cacheFilePath;
        
        private string licenseKey;
        private int? activationId;
        private DateTime? expiresAt;
        private bool isValid;
        
        private Timer heartbeatTimer;
        private readonly SemaphoreSlim semaphore = new SemaphoreSlim(1, 1);

        public LicenseManager(string apiKey, string appVersion = "1.0.0")
        {
            this.apiKey = apiKey;
            this.appVersion = appVersion;
            
            // HttpClient Setup
            var handler = new HttpClientHandler
            {
                ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true // Für Entwicklung
            };
            
            httpClient = new HttpClient(handler);
            httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {apiKey}");
            httpClient.Timeout = TimeSpan.FromSeconds(30);
            
            // Cache-Verzeichnis
            string appDataPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
            string appFolder = Path.Combine(appDataPath, "MyApp", "License");
            Directory.CreateDirectory(appFolder);
            cacheFilePath = Path.Combine(appFolder, "license.json");
        }

        /// <summary>
        /// Eindeutige Maschinen-ID generieren
        /// </summary>
        private string GetMachineId()
        {
            try
            {
                // CPU-ID abrufen
                string cpuId = "";
                using (ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT ProcessorId FROM Win32_Processor"))
                {
                    foreach (ManagementObject obj in searcher.Get())
                    {
                        cpuId = obj["ProcessorId"]?.ToString() ?? "";
                        break;
                    }
                }

                // Motherboard Serial Number
                string motherboardId = "";
                using (ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT SerialNumber FROM Win32_BaseBoard"))
                {
                    foreach (ManagementObject obj in searcher.Get())
                    {
                        motherboardId = obj["SerialNumber"]?.ToString() ?? "";
                        break;
                    }
                }

                return $"{cpuId}-{motherboardId}";
            }
            catch
            {
                // Fallback: Machine Name + User
                return $"{Environment.MachineName}-{Environment.UserName}";
            }
        }

        /// <summary>
        /// Hardware-Fingerprint erstellen
        /// </summary>
        private string GetHardwareHash()
        {
            var components = new List<string>
            {
                GetMachineId(),
                Environment.MachineName,
                Environment.OSVersion.ToString(),
                Environment.ProcessorCount.ToString()
            };

            // MAC-Adressen hinzufügen
            try
            {
                using (var searcher = new ManagementObjectSearcher("SELECT MACAddress FROM Win32_NetworkAdapter WHERE MACAddress IS NOT NULL"))
                {
                    foreach (ManagementObject obj in searcher.Get())
                    {
                        string mac = obj["MACAddress"]?.ToString();
                        if (!string.IsNullOrEmpty(mac))
                            components.Add(mac);
                    }
                }
            }
            catch { }

            string combined = string.Join("-", components);
            using (SHA256 sha256 = SHA256.Create())
            {
                byte[] hashBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(combined));
                return BitConverter.ToString(hashBytes).Replace("-", "").ToLowerInvariant();
            }
        }

        /// <summary>
        /// Lizenz-Cache speichern
        /// </summary>
        private async Task SaveLicenseCacheAsync()
        {
            var cacheData = new
            {
                license_key = licenseKey,
                activation_id = activationId,
                expires_at = expiresAt?.ToString("O"),
                hardware_hash = GetHardwareHash(),
                last_verified = DateTime.UtcNow.ToString("O")
            };

            string json = JsonSerializer.Serialize(cacheData, new JsonSerializerOptions { WriteIndented = true });
            await File.WriteAllTextAsync(cacheFilePath, json);
        }

        /// <summary>
        /// Lizenz-Cache laden
        /// </summary>
        private async Task<LicenseCache> LoadLicenseCacheAsync()
        {
            if (!File.Exists(cacheFilePath))
                return null;

            try
            {
                string json = await File.ReadAllTextAsync(cacheFilePath);
                return JsonSerializer.Deserialize<LicenseCache>(json);
            }
            catch
            {
                return null;
            }
        }

        /// <summary>
        /// Lizenz aktivieren
        /// </summary>
        public async Task<(bool Success, string Message)> ActivateLicenseAsync(string licenseKey)
        {
            await semaphore.WaitAsync();
            try
            {
                var requestData = new
                {
                    license_key = licenseKey,
                    machine_id = GetMachineId(),
                    hardware_hash = GetHardwareHash(),
                    os_info = new
                    {
                        os = "Windows",
                        version = Environment.OSVersion.Version.ToString(),
                        platform = Environment.OSVersion.Platform.ToString(),
                        service_pack = Environment.OSVersion.ServicePack
                    },
                    app_version = appVersion
                };

                var json = JsonSerializer.Serialize(requestData);
                var content = new StringContent(json, Encoding.UTF8, "application/json");

                var response = await httpClient.PostAsync($"{serverUrl}/api/license/activate", content);
                var responseContent = await response.Content.ReadAsStringAsync();

                if (response.IsSuccessStatusCode)
                {
                    var result = JsonSerializer.Deserialize<ActivationResponse>(responseContent);
                    
                    if (result.success)
                    {
                        this.licenseKey = licenseKey;
                        this.activationId = result.activation_id;
                        this.isValid = true;
                        
                        if (!string.IsNullOrEmpty(result.expires_at))
                            this.expiresAt = DateTime.Parse(result.expires_at);

                        await SaveLicenseCacheAsync();
                        StartHeartbeat();

                        return (true, result.message ?? "Lizenz erfolgreich aktiviert");
                    }
                    else
                    {
                        return (false, result.message ?? "Aktivierung fehlgeschlagen");
                    }
                }
                else
                {
                    return (false, $"Server-Fehler: {response.StatusCode}");
                }
            }
            catch (HttpRequestException ex)
            {
                return (false, $"Verbindungsfehler: {ex.Message}");
            }
            catch (Exception ex)
            {
                return (false, $"Fehler: {ex.Message}");
            }
            finally
            {
                semaphore.Release();
            }
        }

        /// <summary>
        /// Lizenz verifizieren (Heartbeat)
        /// </summary>
        public async Task<(bool Valid, string Message)> VerifyLicenseAsync()
        {
            if (string.IsNullOrEmpty(licenseKey) || !activationId.HasValue)
                return (false, "Keine aktive Lizenz");

            await semaphore.WaitAsync();
            try
            {
                var requestData = new
                {
                    license_key = licenseKey,
                    machine_id = GetMachineId(),
                    hardware_hash = GetHardwareHash(),
                    activation_id = activationId.Value
                };

                var json = JsonSerializer.Serialize(requestData);
                var content = new StringContent(json, Encoding.UTF8, "application/json");

                var response = await httpClient.PostAsync($"{serverUrl}/api/license/verify", content);
                var responseContent = await response.Content.ReadAsStringAsync();

                if (response.IsSuccessStatusCode)
                {
                    var result = JsonSerializer.Deserialize<VerificationResponse>(responseContent);
                    isValid = result.valid;

                    if (isValid)
                    {
                        await SaveLicenseCacheAsync();

                        if (result.requires_update)
                        {
                            OnUpdateAvailable?.Invoke(result.update_url);
                        }
                    }

                    return (isValid, result.message ?? "");
                }
                else
                {
                    return (false, $"Server-Fehler: {response.StatusCode}");
                }
            }
            catch (HttpRequestException)
            {
                // Offline-Verifizierung
                return await VerifyOfflineAsync();
            }
            catch (Exception ex)
            {
                return (false, $"Fehler: {ex.Message}");
            }
            finally
            {
                semaphore.Release();
            }
        }

        /// <summary>
        /// Offline-Verifizierung mit Grace Period
        /// </summary>
        private async Task<(bool Valid, string Message)> VerifyOfflineAsync()
        {
            var cache = await LoadLicenseCacheAsync();
            if (cache == null)
                return (false, "Keine gecachte Lizenz vorhanden");

            // Hardware-Hash prüfen
            if (cache.hardware_hash != GetHardwareHash())
            {
                // Grace Period bei Hardware-Änderung
                var lastVerified = DateTime.Parse(cache.last_verified);
                var gracePeriod = TimeSpan.FromDays(7);

                if (DateTime.UtcNow - lastVerified > gracePeriod)
                    return (false, "Hardware geändert - Grace Period abgelaufen");
            }

            // Ablaufdatum prüfen
            if (!string.IsNullOrEmpty(cache.expires_at))
            {
                var expiresAt = DateTime.Parse(cache.expires_at);
                if (DateTime.UtcNow > expiresAt)
                    return (false, "Lizenz abgelaufen");
            }

            licenseKey = cache.license_key;
            activationId = cache.activation_id;
            isValid = true;

            return (true, "Offline-Modus (gecachte Lizenz)");
        }

        /// <summary>
        /// Nach Updates suchen
        /// </summary>
        public async Task<UpdateInfo> CheckForUpdatesAsync()
        {
            if (string.IsNullOrEmpty(licenseKey))
                return null;

            try
            {
                var requestData = new
                {
                    current_version = appVersion,
                    license_key = licenseKey
                };

                var json = JsonSerializer.Serialize(requestData);
                var content = new StringContent(json, Encoding.UTF8, "application/json");

                var response = await httpClient.PostAsync($"{serverUrl}/api/version/check", content);
                
                if (response.IsSuccessStatusCode)
                {
                    var responseContent = await response.Content.ReadAsStringAsync();
                    return JsonSerializer.Deserialize<UpdateInfo>(responseContent);
                }
            }
            catch { }

            return null;
        }

        /// <summary>
        /// Heartbeat starten
        /// </summary>
        private void StartHeartbeat()
        {
            heartbeatTimer?.Dispose();
            
            // Alle 15 Minuten
            heartbeatTimer = new Timer(async _ =>
            {
                var (valid, message) = await VerifyLicenseAsync();
                if (!valid)
                {
                    OnLicenseInvalid?.Invoke(message);
                }
            }, null, TimeSpan.FromMinutes(15), TimeSpan.FromMinutes(15));
        }

        /// <summary>
        /// Lizenz-Informationen abrufen
        /// </summary>
        public LicenseInfo GetLicenseInfo()
        {
            return new LicenseInfo
            {
                IsValid = isValid,
                LicenseKey = string.IsNullOrEmpty(licenseKey) ? null : licenseKey.Substring(0, 4) + "****",
                ExpiresAt = expiresAt,
                MachineId = GetMachineId()
            };
        }

        // Events
        public event Action<string> OnUpdateAvailable;
        public event Action<string> OnLicenseInvalid;

        public void Dispose()
        {
            heartbeatTimer?.Dispose();
            httpClient?.Dispose();
            semaphore?.Dispose();
        }
    }

    // Hilfsklassen
    public class LicenseCache
    {
        public string license_key { get; set; }
        public int? activation_id { get; set; }
        public string expires_at { get; set; }
        public string hardware_hash { get; set; }
        public string last_verified { get; set; }
    }

    public class ActivationResponse
    {
        public bool success { get; set; }
        public string message { get; set; }
        public int? activation_id { get; set; }
        public string expires_at { get; set; }
    }

    public class VerificationResponse
    {
        public bool valid { get; set; }
        public string message { get; set; }
        public string expires_at { get; set; }
        public bool requires_update { get; set; }
        public string update_url { get; set; }
    }

    public class UpdateInfo
    {
        public string latest_version { get; set; }
        public string current_version { get; set; }
        public bool update_available { get; set; }
        public bool is_mandatory { get; set; }
        public string download_url { get; set; }
        public string release_notes { get; set; }
    }

    public class LicenseInfo
    {
        public bool IsValid { get; set; }
        public string LicenseKey { get; set; }
        public DateTime? ExpiresAt { get; set; }
        public string MachineId { get; set; }
    }

    // Beispiel-Anwendung
    class Program
    {
        static async Task Main(string[] args)
        {
            // API-Key aus Umgebungsvariable oder Konfiguration
            string apiKey = Environment.GetEnvironmentVariable("LICENSE_API_KEY") ?? "your-api-key-here";
            
            using (var licenseManager = new LicenseManager(apiKey, "1.0.0"))
            {
                // Event-Handler registrieren
                licenseManager.OnUpdateAvailable += url => Console.WriteLine($"Update verfügbar: {url}");
                licenseManager.OnLicenseInvalid += msg => Console.WriteLine($"Lizenz ungültig: {msg}");

                // Lizenz prüfen/aktivieren
                var cache = await licenseManager.LoadLicenseCacheAsync();
                
                if (cache != null)
                {
                    Console.WriteLine("Gecachte Lizenz gefunden, verifiziere...");
                    var (valid, message) = await licenseManager.VerifyLicenseAsync();
                    
                    if (!valid)
                    {
                        Console.WriteLine($"Lizenz ungültig: {message}");
                        await ActivateNewLicense(licenseManager);
                    }
                    else
                    {
                        Console.WriteLine($"✓ Lizenz gültig: {message}");
                    }
                }
                else
                {
                    await ActivateNewLicense(licenseManager);
                }

                // Update-Check
                var updateInfo = await licenseManager.CheckForUpdatesAsync();
                if (updateInfo?.update_available == true)
                {
                    Console.WriteLine($"Update verfügbar: {updateInfo.latest_version}");
                    if (updateInfo.is_mandatory)
                        Console.WriteLine("⚠️ Dies ist ein Pflicht-Update!");
                }

                // Lizenz-Info anzeigen
                var info = licenseManager.GetLicenseInfo();
                Console.WriteLine($"\nLizenz-Status:");
                Console.WriteLine($"- Gültig: {info.IsValid}");
                Console.WriteLine($"- Ablauf: {info.ExpiresAt}");
                Console.WriteLine($"- Maschine: {info.MachineId}");

                // App läuft...
                Console.WriteLine("\n✓ Anwendung gestartet");
                Console.WriteLine("Drücken Sie eine Taste zum Beenden...");
                Console.ReadKey();
            }
        }

        static async Task ActivateNewLicense(LicenseManager licenseManager)
        {
            Console.Write("Bitte Lizenzschlüssel eingeben: ");
            string licenseKey = Console.ReadLine();
            
            var (success, message) = await licenseManager.ActivateLicenseAsync(licenseKey);
            
            if (success)
            {
                Console.WriteLine($"✓ {message}");
            }
            else
            {
                Console.WriteLine($"✗ {message}");
                Environment.Exit(1);
            }
        }
    }
}