using System.Diagnostics;
using System.IO;
using System.Net.Http;
using System.Reflection;
using System.Windows;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Microsoft.Extensions.Logging;
using PSLauncher.Core.Configuration;
using PSLauncher.Core.Downloads;
using PSLauncher.Core.Licensing;
using PSLauncher.Models;

namespace PSLauncher.App.ViewModels;

public sealed partial class SettingsViewModel : ObservableObject
{
    private readonly IConfigStore _configStore;
    private readonly LocalConfig _config;
    private readonly ILicenseService _licenseService;
    private readonly IDownloadStateStore _downloadStore;
    private readonly HttpClient _http;
    private readonly ILogger<SettingsViewModel> _logger;

    public string LauncherVersion { get; }
    public string MachineId { get; }
    public string LogsDirectory { get; }
    public string CacheDirectory { get; }

    [ObservableProperty] private string _serverBaseUrl;
    [ObservableProperty] private string _installRoot;
    [ObservableProperty] private string? _connectionStatus;
    [ObservableProperty] private bool _isTestingConnection;
    [ObservableProperty] private string _cacheSizeDisplay = "—";

    public string LicenseInfo
    {
        get
        {
            var l = _licenseService.GetCached();
            if (l is null) return "Aucune license activée — clique pour saisir une clé";
            if (l.Status == "valid")
                return $"{l.OwnerName} • valable jusqu'au {l.DownloadEntitlementUntil:dd/MM/yyyy}";
            if (l.Status == "expired")
                return $"{l.OwnerName} • expirée le {l.DownloadEntitlementUntil:dd/MM/yyyy}";
            return $"{l.OwnerName} • {l.Status}";
        }
    }

    public string LicenseIcon
    {
        get
        {
            var l = _licenseService.GetCached();
            if (l is null) return "🔒";
            return l.Status switch
            {
                "valid" when IsExpiringSoon(l) => "⏰",
                "valid"                         => "✓",
                "expired"                       => "⚠",
                "revoked"                       => "🚫",
                _                                => "❓",
            };
        }
    }

    public string LicenseSeverity
    {
        get
        {
            var l = _licenseService.GetCached();
            if (l is null) return "Error";
            return l.Status switch
            {
                "valid" when IsExpiringSoon(l) => "Warning",
                "valid"                         => "Ok",
                _                                => "Error",
            };
        }
    }

    private static bool IsExpiringSoon(LicenseValidationResponse l)
    {
        if (l.DownloadEntitlementUntil is not { } until) return false;
        return (until - DateTime.UtcNow).TotalDays < 30;
    }

    public SettingsViewModel(
        IConfigStore configStore,
        LocalConfig config,
        ILicenseService licenseService,
        IDownloadStateStore downloadStore,
        HttpClient http,
        ILogger<SettingsViewModel> logger)
    {
        _configStore = configStore;
        _config = config;
        _licenseService = licenseService;
        _downloadStore = downloadStore;
        _http = http;
        _logger = logger;

        _serverBaseUrl = config.ServerBaseUrl;
        _installRoot = config.InstallRoot;

        LauncherVersion = Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? "0.0.0";
        MachineId = licenseService.GetMachineId();
        LogsDirectory = App.LogsDirectory;
        CacheDirectory = downloadStore.GetDownloadsDirectory();
        RefreshCacheSize();
    }

    [RelayCommand]
    private async Task TestConnectionAsync()
    {
        ConnectionStatus = "Test en cours…";
        IsTestingConnection = true;
        try
        {
            var url = ServerBaseUrl.TrimEnd('/') + "/health";
            using var resp = await _http.GetAsync(url);
            if (resp.IsSuccessStatusCode)
            {
                var body = await resp.Content.ReadAsStringAsync();
                ConnectionStatus = $"✓ OK ({(int)resp.StatusCode}) — {body.Substring(0, Math.Min(80, body.Length))}";
            }
            else
            {
                ConnectionStatus = $"✗ HTTP {(int)resp.StatusCode}";
            }
        }
        catch (Exception ex)
        {
            ConnectionStatus = $"✗ Erreur : {ex.Message}";
        }
        finally
        {
            IsTestingConnection = false;
        }
    }

    [RelayCommand]
    private void BrowseInstallRoot()
    {
        var dlg = new Microsoft.Win32.OpenFolderDialog
        {
            Title = "Choisir le dossier d'installation",
            InitialDirectory = Directory.Exists(InstallRoot) ? InstallRoot : Environment.GetFolderPath(Environment.SpecialFolder.UserProfile),
        };
        if (dlg.ShowDialog() == true)
        {
            InstallRoot = dlg.FolderName;
        }
    }

    [RelayCommand]
    private void OpenLogsFolder()
    {
        if (Directory.Exists(LogsDirectory))
            Process.Start(new ProcessStartInfo { FileName = LogsDirectory, UseShellExecute = true, Verb = "open" });
    }

    [RelayCommand]
    private void OpenCacheFolder()
    {
        if (Directory.Exists(CacheDirectory))
            Process.Start(new ProcessStartInfo { FileName = CacheDirectory, UseShellExecute = true, Verb = "open" });
    }

    [RelayCommand]
    private void ClearCache()
    {
        var confirm = MessageBox.Show(
            "Vider le cache de téléchargements ? Les téléchargements en cours/pause seront perdus.",
            "Confirmer",
            MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No);
        if (confirm != MessageBoxResult.Yes) return;

        try
        {
            foreach (var f in Directory.EnumerateFiles(CacheDirectory))
            {
                try { File.Delete(f); } catch (Exception ex) { _logger.LogWarning(ex, "Cannot delete {F}", f); }
            }
            RefreshCacheSize();
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "ClearCache failed");
            MessageBox.Show("Échec : " + ex.Message, "Erreur", MessageBoxButton.OK, MessageBoxImage.Error);
        }
    }

    [RelayCommand]
    private void CopyMachineId()
    {
        try { Clipboard.SetText(MachineId); }
        catch (Exception ex) { _logger.LogWarning(ex, "Clipboard failed"); }
    }

    [RelayCommand]
    private void Save()
    {
        _config.ServerBaseUrl = ServerBaseUrl.TrimEnd('/');
        _config.InstallRoot = InstallRoot;
        _configStore.Save(_config);
        _logger.LogInformation("Settings saved");
    }

    [RelayCommand]
    private void DeactivateLicense()
    {
        var confirm = MessageBox.Show(
            "Désactiver la license sur cette machine ?\nTu pourras la réactiver avec ta clé.",
            "Confirmer",
            MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No);
        if (confirm != MessageBoxResult.Yes) return;
        _licenseService.Clear();
        OnPropertyChanged(nameof(LicenseInfo));
    }

    private void RefreshCacheSize()
    {
        try
        {
            long total = 0;
            if (Directory.Exists(CacheDirectory))
            {
                foreach (var f in Directory.EnumerateFiles(CacheDirectory))
                    total += new FileInfo(f).Length;
            }
            CacheSizeDisplay = FormatSize(total);
        }
        catch { CacheSizeDisplay = "—"; }
    }

    private static string FormatSize(long bytes)
    {
        if (bytes <= 0) return "0 o";
        string[] units = { "o", "Ko", "Mo", "Go", "To" };
        double v = bytes; int u = 0;
        while (v >= 1024 && u < units.Length - 1) { v /= 1024; u++; }
        return $"{v:0.#} {units[u]}";
    }
}
