using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Xml.Serialization;

namespace PolyTraderSharp.Models
{
    /// <summary>Farbschema der Oberfläche.</summary>
    public enum AppThemeVariant
    {
        /// <summary>Folgt der Einstellung des Betriebssystems.</summary>
        System,
        Hell,
        Dunkel
    }

    public class ServerSettings
    {
        [Category("Module")]
        [DisplayName("Deaktivierte Module")]
        [Description("Namen der Module (z.B. \"CopyTrading\"), die beim App-Start NICHT geladen werden. " +
            "Leer = alle Module aktiv. Änderungen greifen nach dem nächsten Neustart. " +
            "Wird i.d.R. über das Dashboard gepflegt.")]
        [XmlArray("DisabledModules")]
        [XmlArrayItem("Module")]
        public List<string> DisabledModules { get; set; } = new();

        [Category("Anzeige")]
        [DisplayName("Farbschema")]
        [Description("Hell, Dunkel oder der Einstellung des Betriebssystems folgen. " +
            "Lässt sich jederzeit über den Umschalter in der Fensterleiste wechseln; " +
            "der zuletzt gewählte Stand wird hier gespeichert.")]
        public AppThemeVariant Theme { get; set; } = AppThemeVariant.System;

        [Category("Anzeige")]
        [DisplayName("Zeitzone")]
        [Description("Zeitzone für Anzeige und Logdatei-Tagesgrenzen, IANA-Schreibweise (z.B. \"Europe/Berlin\", " +
            "\"America/New_York\"). Leer = Zeitzone des Systems. Wird üblicherweise EINMALIG bei der " +
            "Installation gesetzt: eine spätere Änderung verschiebt Tagesgrenzen in Logs und Auswertungen. " +
            "Greift erst nach einem Neustart.")]
        public string ApplicationTimeZoneId { get; set; } = PolyTraderSharp.Services.AppTimeZone.DefaultId;

        [Category("Mullvad VPN")]
        [DisplayName("VPN Enabled")]
        [Description("Enable or disable automatic VPN rotation.")]
        public bool VpnEnabled { get; set; } = false;

        [Category("Mullvad VPN")]
        [DisplayName("Mullvad Account")]
        [Description("Account ID for Mullvad VPN. In server_settings.xml (gitignored) hinterlegen – NICHT im Code committen.")]
        public string MullvadAccount { get; set; } = "";   // F3: Secret nicht mehr im Quellcode

        [Category("Mullvad VPN")]
        [DisplayName("VPN Location")]
        [Description("Target VPN location (e.g. cz).")]
        public string VpnLocation { get; set; } = "cz";

        [Category("Mullvad VPN")]
        [DisplayName("Mullvad CLI Path")]
        [Description("Path to mullvad.exe")]
        public string MullvadCliPath { get; set; } = @"C:\Program Files\Mullvad VPN\resources\mullvad.exe";


        [Category("Blockchain Listener")]
        [DisplayName("Enable Blockchain Listener")]
        [Description("If true, connects to Alchemy WSS for faster on-chain signal detection.")]
        public bool EnableBlockchainListener { get; set; } = true;

        [Category("Blockchain Listener")]
        [DisplayName("Polygon RPC URL")]
        [Description("RPC-/WSS-URL inkl. Alchemy-API-Key. In server_settings.xml (gitignored) hinterlegen – der Key gehört NICHT in den Quellcode/Git. Format: wss://polygon-mainnet.g.alchemy.com/v2/<KEY>")]
        public string PolygonRpcUrl { get; set; } = "";   // F3: Alchemy-Key nicht mehr im Quellcode

        [Category("Polymarket WebSockets")]
        [DisplayName("Use Polymarket WebSockets")]
        [Description("If true, connects to Polymarket WSS for live market prices and user events.")]
        public bool UsePolymarketWebsockets { get; set; } = false;


        [Category("Watchdog Monitoring")]
        [DisplayName("Watchdog Enabled")]
        [Description("Wenn true, sendet PolyTrader im festen Takt einen Heartbeat an den Watchdog " +
            "des Deploymentcenters. Bleiben die Heartbeats aus, alarmiert der Watchdog " +
            "(Dead-Man's-Switch). Ein nicht erreichbarer Watchdog beeinträchtigt PolyTrader NIE.")]
        public bool WatchdogEnabled { get; set; } = false;

        [Category("Watchdog Monitoring")]
        [DisplayName("Deploymentcenter-URL")]
        [Description("Basis-URL des Deploymentcenters, z.B. https://dc.mhdf.de (ersetzt den früheren " +
            "eigenständigen Watchdog-Server). HTTPS ist Pflicht – http:// wird nur für localhost " +
            "akzeptiert, damit der Agent-Token nicht im Klartext über das Netz geht.")]
        public string WatchdogUrl { get; set; } = "";

        /// <summary>
        /// Agent-Token für den Header <c>X-Watchdog-Key</c>. Bewusst NICHT im PropertyGrid sichtbar:
        /// Setzen erfolgt über den Button „Watchdog-Token setzen …" mit maskierter Eingabe, damit das
        /// Secret nicht offen im Fenster steht und bei gesetztem Master-Key verschlüsselt
        /// (<c>enc:v1:…</c>) in der gitignorierten server_settings.xml landet.
        /// </summary>
        [Browsable(false)]
        public string WatchdogToken { get; set; } = "";

        [Category("Watchdog Monitoring")]
        [DisplayName("Agent-Token")]
        [Description("Status des Agent-Tokens. Setzen/Ändern über den Button „Watchdog-Token setzen …" +
            "\" in der Werkzeugleiste (maskierte Eingabe).")]
        [ReadOnly(true)]
        [XmlIgnore]
        public string WatchdogTokenStatus =>
            string.IsNullOrWhiteSpace(WatchdogToken)
                ? "nicht gesetzt"
                : (WatchdogToken.StartsWith("enc:v1:", System.StringComparison.Ordinal)
                    ? "gesetzt (verschlüsselt)"
                    : "gesetzt (Klartext)");

        [Category("Watchdog Monitoring")]
        [DisplayName("Source")]
        [Description("Dienst-Kennung im Watchdog (muss dem dort angelegten Monitor entsprechen), z.B. \"polytrader\".")]
        public string WatchdogSource { get; set; } = "polytrader";

        [Category("Watchdog Monitoring")]
        [DisplayName("Instance")]
        [Description("Instanz-Kennung, falls mehrere PolyTrader-Instanzen laufen, z.B. \"prod-1\".")]
        public string WatchdogInstance { get; set; } = "prod-1";

        [Category("Watchdog Monitoring")]
        [DisplayName("Heartbeat-Intervall (Sekunden)")]
        [Description("Sende-Takt des Heartbeats. Der Watchdog leitet daraus seine Staleness-Frist ab " +
            "(Intervall × Faktor + Grace). Minimum 10 s, Empfehlung 60 s.")]
        public int WatchdogIntervalSeconds { get; set; } = 60;


        /// <summary>
        /// Lizenzschlüssel (LicenseLabrador). Wie der Watchdog-Token bewusst NICHT im PropertyGrid
        /// sichtbar; gepflegt über den Button „Lizenzschlüssel setzen …" bzw. den Startdialog. Bei
        /// gesetztem Master-Key verschlüsselt (<c>enc:v1:…</c>) in der gitignorierten server_settings.xml.
        /// </summary>
        [Browsable(false)]
        public string LicenseKey { get; set; } = "";

        [Category("Lizenz")]
        [DisplayName("Lizenzschlüssel")]
        [Description("Status des Lizenzschlüssels. Setzen/Ändern über den Button „Lizenzschlüssel setzen …\" " +
            "in der Werkzeugleiste bzw. beim Programmstart, falls keine gültige Lizenz vorliegt.")]
        [ReadOnly(true)]
        [XmlIgnore]
        public string LicenseKeyStatus =>
            string.IsNullOrWhiteSpace(LicenseKey)
                ? "nicht gesetzt"
                : (LicenseKey.StartsWith("enc:v1:", System.StringComparison.Ordinal)
                    ? "gesetzt (verschlüsselt)"
                    : "gesetzt (Klartext)");


        public static ServerSettings Load(string path)
        {
            if (!File.Exists(path))
                return new ServerSettings();

            try
            {
                var serializer = new XmlSerializer(typeof(ServerSettings));
                using var fs = new FileStream(path, FileMode.Open);
                return (ServerSettings?)serializer.Deserialize(fs) ?? new ServerSettings();
            }
            catch
            {
                return new ServerSettings();
            }
        }

        public void Save(string path)
        {
            var serializer = new XmlSerializer(typeof(ServerSettings));
            using var fs = new FileStream(path, FileMode.Create);
            serializer.Serialize(fs, this);
        }
    }
}
