using System.ComponentModel;
using System.Text.Json;

namespace ClawdDotNet.Models;

static class ConfigHelper
{
    public static string GetString(Dictionary<string, object?> config, string key, string fallback = "")
    {
        var val = config.GetValueOrDefault(key);
        return val switch
        {
            JsonElement je when je.ValueKind == JsonValueKind.String => je.GetString() ?? fallback,
            JsonElement je => je.ToString(),
            string s => s,
            null => fallback,
            _ => val.ToString() ?? fallback
        };
    }

    public static int GetInt(Dictionary<string, object?> config, string key, int fallback = 0)
    {
        var val = config.GetValueOrDefault(key);
        return val switch
        {
            JsonElement je when je.ValueKind == JsonValueKind.Number => je.GetInt32(),
            JsonElement je => int.TryParse(je.ToString(), out var r) ? r : fallback,
            int i => i,
            _ => int.TryParse(val?.ToString(), out var r) ? r : fallback
        };
    }

    public static bool GetBool(Dictionary<string, object?> config, string key, bool fallback = false)
    {
        var val = config.GetValueOrDefault(key);
        return val switch
        {
            JsonElement je when je.ValueKind is JsonValueKind.True => true,
            JsonElement je when je.ValueKind is JsonValueKind.False => false,
            JsonElement je => bool.TryParse(je.ToString(), out var r) ? r : fallback,
            bool b => b,
            _ => bool.TryParse(val?.ToString(), out var r) ? r : fallback
        };
    }

    public static string GetStringArray(Dictionary<string, object?> config, string key)
    {
        var val = config.GetValueOrDefault(key);
        return val switch
        {
            JsonElement je when je.ValueKind == JsonValueKind.Array =>
                string.Join(",", je.EnumerateArray().Select(e => e.GetString())),
            object[] arr => string.Join(",", arr),
            string s => s,
            _ => ""
        };
    }
}

public enum FileRWAccessLevel
{
    Denied,
    Read,
    ReadWrite,
    Admin
}

public sealed class FileRWToolSettings
{
    [Category("Persönlicher Workspace")]
    [DisplayName("Erlaubte Endungen")]
    [Description("Dateiendungen für den eigenen Agenten-Workspace (z.B. .txt,.json,.md)")]
    public string PersonalAllowedExtensions { get; set; } = ".txt,.json,.md,.html,.js,.css";

    [Category("Shared Workspace")]
    [DisplayName("Zugriffslevel")]
    [Description("Legt fest, welche Operationen im SharedWorkspace erlaubt sind")]
    public FileRWAccessLevel SharedAccessLevel { get; set; } = FileRWAccessLevel.Denied;

    [Category("Shared Workspace")]
    [DisplayName("Erlaubte Endungen")]
    [Description("Dateiendungen für den geteilten Workspace")]
    public string SharedAllowedExtensions { get; set; } = ".txt,.json,.md";

    [Category("Shared Workspace – Schutz")]
    [DisplayName("Geschützte Pfade")]
    [Description("Komma-getrennte Pfade im SharedWorkspace die append-only sind (z.B. stocks/,archives/). Dateien dort können nur erstellt, nicht überschrieben oder gelöscht werden. Admin-Level umgeht den Schutz.")]
    public string ProtectedPaths { get; set; } = "stocks/";

    public Dictionary<string, object?> ToConfig() => new()
    {
        ["personalAllowedExtensions"] = PersonalAllowedExtensions.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries),
        ["sharedAccessLevel"] = SharedAccessLevel.ToString(),
        ["sharedAllowedExtensions"] = SharedAllowedExtensions.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries),
        ["protectedPaths"] = ProtectedPaths.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
    };

    public static FileRWToolSettings FromConfig(Dictionary<string, object?> config) => new()
    {
        PersonalAllowedExtensions = ConfigHelper.GetStringArray(config, "personalAllowedExtensions") is { Length: > 0 } s1
            ? s1 : (ConfigHelper.GetStringArray(config, "allowedExtensions") is { Length: > 0 } sOld ? sOld : ".txt,.json,.md,.html,.js,.css"),

        SharedAccessLevel = Enum.TryParse<FileRWAccessLevel>(ConfigHelper.GetString(config, "sharedAccessLevel"), true, out var level)
            ? level : FileRWAccessLevel.Denied,

        SharedAllowedExtensions = ConfigHelper.GetStringArray(config, "sharedAllowedExtensions") is { Length: > 0 } s2
            ? s2 : ".txt,.json,.md",

        ProtectedPaths = ConfigHelper.GetStringArray(config, "protectedPaths") is { Length: > 0 } s3
            ? s3 : "stocks/"
    };
}

public sealed class MailToolSettings
{
    [Category("Mail - Konto")]
    [DisplayName("Benutzername")]
    public string Username { get; set; } = "";

    [Category("Mail - Konto")]
    [DisplayName("Passwort")]
    [PasswordPropertyText(true)]
    public string Password { get; set; } = "";

    [Category("Mail - IMAP")]
    [DisplayName("IMAP-Host")]
    public string ImapHost { get; set; } = "";

    [Category("Mail - IMAP")]
    [DisplayName("IMAP-Port")]
    public int ImapPort { get; set; } = 993;

    [Category("Mail - SMTP")]
    [DisplayName("SMTP-Host")]
    public string SmtpHost { get; set; } = "";

    [Category("Mail - SMTP")]
    [DisplayName("SMTP-Port")]
    public int SmtpPort { get; set; } = 587;

    [Category("Mail - Sicherheit")]
    [DisplayName("Erlaubte Empfänger")]
    [Description("Komma-getrennte Liste erlaubter E-Mail-Adressen")]
    public string AllowedRecipients { get; set; } = "";

    public Dictionary<string, object?> ToConfig() => new()
    {
        ["username"] = Username,
        ["password"] = Password,
        ["imapHost"] = ImapHost,
        ["imapPort"] = ImapPort,
        ["smtpHost"] = SmtpHost,
        ["smtpPort"] = SmtpPort,
        ["allowedRecipients"] = AllowedRecipients.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
    };

    public static MailToolSettings FromConfig(Dictionary<string, object?> config) => new()
    {
        Username = ConfigHelper.GetString(config, "username"),
        Password = ConfigHelper.GetString(config, "password"),
        ImapHost = ConfigHelper.GetString(config, "imapHost"),
        ImapPort = ConfigHelper.GetInt(config, "imapPort", 993),
        SmtpHost = ConfigHelper.GetString(config, "smtpHost"),
        SmtpPort = ConfigHelper.GetInt(config, "smtpPort", 587),
        AllowedRecipients = ConfigHelper.GetStringArray(config, "allowedRecipients")
    };
}

public enum DatabaseType
{
    MySql,
    Postgres,
    MsSql,
    MongoDb
}

public enum DatabaseAccessLevel
{
    [Description("Nur Lesen (SELECT/find)")]
    ReadOnly,
    [Description("Lesen und Schreiben (INSERT/UPDATE/DELETE)")]
    ReadWrite,
    [Description("Vollzugriff (Admin/Schema-Änderungen)")]
    Admin
}

public sealed class DatabaseToolSettings
{
    [Category("Datenbank")]
    [DisplayName("Typ")]
    [Description("Der zu verwendende Datenbanktyp")]
    public DatabaseType Type { get; set; } = DatabaseType.MySql;

    [Category("Datenbank")]
    [DisplayName("Connection-String")]
    public string ConnectionString { get; set; } = "";

    [Category("Datenbank")]
    [DisplayName("Zugriffsebene")]
    [Description("Legt fest, welche Operationen der Agent ausführen darf")]
    public DatabaseAccessLevel AccessLevel { get; set; } = DatabaseAccessLevel.ReadOnly;

    [Category("Datenbank - Sicherheit")]
    [DisplayName("Erlaubte Tabellen")]
    [Description("Komma-getrennte Liste erlaubter Tabellen/Collections")]
    public string AllowedTables { get; set; } = "";

    public Dictionary<string, object?> ToConfig() => new()
    {
        ["type"] = Type.ToString().ToLowerInvariant(),
        ["connectionString"] = ConnectionString,
        ["accessLevel"] = AccessLevel.ToString(),
        ["allowedTables"] = AllowedTables.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
    };

    public static DatabaseToolSettings FromConfig(Dictionary<string, object?> config) => new()
    {
        Type = Enum.TryParse<DatabaseType>(config.GetValueOrDefault("type")?.ToString(), true, out var result) ? result : DatabaseType.MySql,
        ConnectionString = config.GetValueOrDefault("connectionString")?.ToString() ?? "",
        AccessLevel = Enum.TryParse<DatabaseAccessLevel>(config.GetValueOrDefault("accessLevel")?.ToString() ?? config.GetValueOrDefault("allowWrite")?.ToString(), true, out var level) 
            ? level 
            : (config.GetValueOrDefault("allowWrite") is true or "True" or "true" ? DatabaseAccessLevel.ReadWrite : DatabaseAccessLevel.ReadOnly),
        AllowedTables = config.GetValueOrDefault("allowedTables") is object[] arr
            ? string.Join(",", arr)
            : config.GetValueOrDefault("allowedTables")?.ToString() ?? ""
    };
}

public sealed class FTPToolSettings
{
    [Category("FTP Server")]
    [DisplayName("Host")]
    public string Host { get; set; } = "";

    [Category("FTP Server")]
    [DisplayName("Port")]
    public int Port { get; set; } = 21;

    [Category("FTP Server")]
    [DisplayName("Benutzername")]
    public string Username { get; set; } = "";

    [Category("FTP Server")]
    [DisplayName("Passwort")]
    [PasswordPropertyText(true)]
    public string Password { get; set; } = "";

    [Category("FTP Lokal")]
    [DisplayName("Root-Pfad")]
    [Description("Basisverzeichnis für Dateiübertragungen")]
    public string RootPath { get; set; } = "./data/";

    public Dictionary<string, object?> ToConfig() => new()
    {
        ["host"] = Host,
        ["port"] = Port,
        ["username"] = Username,
        ["password"] = Password,
        ["rootPath"] = RootPath
    };

    public static FTPToolSettings FromConfig(Dictionary<string, object?> config) => new()
    {
        Host = ConfigHelper.GetString(config, "host"),
        Port = ConfigHelper.GetInt(config, "port", 21),
        Username = ConfigHelper.GetString(config, "username"),
        Password = ConfigHelper.GetString(config, "password"),
        RootPath = ConfigHelper.GetString(config, "rootPath", "./data/")
    };
}

public sealed class TelegramToolSettings
{
    [Category("Telegram")]
    [DisplayName("Bot-Token")]
    [PasswordPropertyText(true)]
    public string BotToken { get; set; } = "";

    [Category("Telegram")]
    [DisplayName("Standard Chat-ID")]
    [Description("Die Standard-ID, an die Nachrichten gesendet werden, wenn keine andere ID angegeben ist.")]
    public string DefaultChatId { get; set; } = "";

    [Category("Telegram - Sicherheit")]
    [DisplayName("Erlaubte Chat-IDs")]
    [Description("Komma-getrennte Liste erlaubter Chat-IDs")]
    public string AllowedChatIds { get; set; } = "";

    public Dictionary<string, object?> ToConfig() => new()
    {
        ["botToken"] = BotToken,
        ["defaultChatId"] = DefaultChatId,
        ["allowedChatIds"] = AllowedChatIds.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
    };

    public static TelegramToolSettings FromConfig(Dictionary<string, object?> config) => new()
    {
        BotToken = ConfigHelper.GetString(config, "botToken"),
        DefaultChatId = ConfigHelper.GetString(config, "defaultChatId"),
        AllowedChatIds = ConfigHelper.GetStringArray(config, "allowedChatIds")
    };
}

public sealed class DirectAPIToolSettings
{
    [Category("DirectAPI")]
    [DisplayName("Standard-Provider")]
    public string DefaultProvider { get; set; } = "twelvedata";

    [Category("DirectAPI")]
    [DisplayName("Cache TTL (Sekunden)")]
    public int CacheTtlSeconds { get; set; } = 60;

    [Category("DirectAPI - API Keys")]
    [DisplayName("Twelve Data Key")]
    [PasswordPropertyText(true)]
    public string TwelveDataKey { get; set; } = "";

    [Category("DirectAPI - API Keys")]
    [DisplayName("Alpha Vantage Key")]
    [PasswordPropertyText(true)]
    public string AlphaVantageKey { get; set; } = "";

    public Dictionary<string, object?> ToConfig() => new()
    {
        ["defaultProvider"] = DefaultProvider,
        ["cacheTtlSeconds"] = CacheTtlSeconds,
        ["providers"] = new Dictionary<string, object?>
        {
            ["twelvedata"] = new { apiKey = TwelveDataKey },
            ["alphavantage"] = new { apiKey = AlphaVantageKey }
        }
    };

    public static DirectAPIToolSettings FromConfig(Dictionary<string, object?> config)
    {
        var settings = new DirectAPIToolSettings
        {
            DefaultProvider = ConfigHelper.GetString(config, "defaultProvider", "twelvedata"),
            CacheTtlSeconds = ConfigHelper.GetInt(config, "cacheTtlSeconds", 60)
        };

        if (config.GetValueOrDefault("providers") is JsonElement providersJe)
        {
            var providers = JsonSerializer.Deserialize<Dictionary<string, JsonElement>>(providersJe.GetRawText());
            if (providers != null)
            {
                if (providers.TryGetValue("twelvedata", out var td) && td.TryGetProperty("apiKey", out var tdk))
                    settings.TwelveDataKey = tdk.GetString() ?? "";
                if (providers.TryGetValue("alphavantage", out var av) && av.TryGetProperty("apiKey", out var avk))
                    settings.AlphaVantageKey = avk.GetString() ?? "";
            }
        }

        return settings;
    }
}

public sealed class WebFetchToolSettings
{
    [Category("WebFetch")]
    [DisplayName("Erlaubte Domains")]
    [Description("Komma-getrennte Liste (z.B. reuters.com,bloomberg.com)")]
    public string AllowedDomains { get; set; } = "";

    [Category("WebFetch")]
    [DisplayName("Max Response KB")]
    public int MaxResponseKb { get; set; } = 512;

    [Category("WebFetch")]
    [DisplayName("User Agent")]
    public string UserAgent { get; set; } = "ClawdDotNet-Agent/1.0";

    public Dictionary<string, object?> ToConfig() => new()
    {
        ["allowedDomains"] = AllowedDomains.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries),
        ["maxResponseKb"] = MaxResponseKb,
        ["userAgent"] = UserAgent
    };

    public static WebFetchToolSettings FromConfig(Dictionary<string, object?> config) => new()
    {
        AllowedDomains = ConfigHelper.GetStringArray(config, "allowedDomains"),
        MaxResponseKb = ConfigHelper.GetInt(config, "maxResponseKb", 512),
        UserAgent = ConfigHelper.GetString(config, "userAgent", "ClawdDotNet-Agent/1.0")
    };
}

public sealed class WebMonitorToolSettings
{
    [Category("WebMonitor")]
    [DisplayName("Monitore (JSON)")]
    [Description("JSON-Konfiguration der Monitore")]
    public string MonitorsJson { get; set; } = "{}";

    public Dictionary<string, object?> ToConfig()
    {
        try
        {
            return new Dictionary<string, object?>
            {
                ["monitors"] = JsonSerializer.Deserialize<Dictionary<string, object?>>(MonitorsJson) ?? new()
            };
        }
        catch { return new Dictionary<string, object?> { ["monitors"] = new Dictionary<string, object?>() }; }
    }

    public static WebMonitorToolSettings FromConfig(Dictionary<string, object?> config) => new()
    {
        MonitorsJson = config.GetValueOrDefault("monitors") is JsonElement je ? je.GetRawText() : "{}"
    };
}

public sealed class AgentCommToolSettings
{
    [Category("AgentComm")]
    [DisplayName("Info")]
    [Description("Dieses Tool benötigt keine Konfiguration. Es ermöglicht Agenten, mit anderen Agenten in der gleichen Instanz zu kommunizieren.")]
    [ReadOnly(true)]
    public string Status { get; set; } = "Aktiv";

    public Dictionary<string, object?> ToConfig() => new();

    public static AgentCommToolSettings FromConfig(Dictionary<string, object?> config) => new();
}

public sealed class SocialMediaManagerToolSettings
{
    // ─── X (Twitter) ───

    [Category("1. X (Twitter) - API")]
    [DisplayName("Bearer Token")]
    [Description("X API v2 Bearer Token für die Authentifizierung")]
    [PasswordPropertyText(true)]
    public string XApiKey { get; set; } = "";

    [Category("1. X (Twitter) - Monitoring")]
    [DisplayName("Überwachte Accounts")]
    [Description("Komma-getrennte Liste von X-Accounts die überwacht werden sollen (ohne @). Beispiel: elonmusk,unusual_whales,DeItaone")]
    public string XWatchAccounts { get; set; } = "";

    // ─── Reddit ───

    [Category("2. Reddit - Monitoring")]
    [DisplayName("Überwachte Subreddits")]
    [Description("Komma-getrennte Liste von Subreddits die überwacht werden sollen (ohne r/). Beispiel: wallstreetbets,stocks,options")]
    public string RedditWatchSubreddits { get; set; } = "";

    [Category("2. Reddit - Monitoring")]
    [DisplayName("Posts pro Subreddit")]
    [Description("Maximale Anzahl Posts die pro Subreddit bei jedem Check abgerufen werden (Standard: 15)")]
    public int RedditPostLimit { get; set; } = 15;

    // ─── YouTube / STT ───

    [Category("3. YouTube / STT")]
    [DisplayName("OpenRouter API Key")]
    [Description("API Key für Speech-to-Text Transkription über OpenRouter")]
    [PasswordPropertyText(true)]
    public string OpenRouterApiKey { get; set; } = "";

    [Category("3. YouTube / STT")]
    [DisplayName("STT Modell")]
    [Description("OpenRouter Modell-ID für die Transkription")]
    public string STTModel { get; set; } = "openai/whisper-1";

    [Category("3. YouTube / STT")]
    [DisplayName("YouTube Kanäle")]
    [Description("Komma-getrennte Liste von YouTube Kanal-URLs für automatische Überwachung")]
    public string YoutubeChannels { get; set; } = "";

    public Dictionary<string, object?> ToConfig() => new()
    {
        ["xApiKey"] = XApiKey,
        ["xWatchAccounts"] = SplitToArray(XWatchAccounts),
        ["redditWatchSubreddits"] = SplitToArray(RedditWatchSubreddits),
        ["redditPostLimit"] = RedditPostLimit,
        ["openRouterApiKey"] = OpenRouterApiKey,
        ["sttModel"] = STTModel,
        ["youtubeChannels"] = SplitToArray(YoutubeChannels)
    };

    public static SocialMediaManagerToolSettings FromConfig(Dictionary<string, object?> config) => new()
    {
        XApiKey = ConfigHelper.GetString(config, "xApiKey"),
        XWatchAccounts = ConfigHelper.GetStringArray(config, "xWatchAccounts"),
        RedditWatchSubreddits = ConfigHelper.GetStringArray(config, "redditWatchSubreddits"),
        RedditPostLimit = ConfigHelper.GetInt(config, "redditPostLimit", 15),
        OpenRouterApiKey = ConfigHelper.GetString(config, "openRouterApiKey"),
        STTModel = ConfigHelper.GetString(config, "sttModel", "openai/whisper-1"),
        YoutubeChannels = ConfigHelper.GetStringArray(config, "youtubeChannels")
    };

    private static string[] SplitToArray(string csv)
        => csv.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
}

public sealed class AgentEditorToolSettings
{
    [Category("AgentEditor")]
    [DisplayName("Info")]
    [Description("Erlaubt dem Agenten, Identity und Soul anderer Agenten zu lesen, zu bearbeiten und neue Agenten zu erstellen. Keine weitere Konfiguration nötig.")]
    [ReadOnly(true)]
    public string Status { get; set; } = "Aktiv";

    public Dictionary<string, object?> ToConfig() => new();

    public static AgentEditorToolSettings FromConfig(Dictionary<string, object?> config) => new();
}

public sealed class AgentSpawnToolSettings
{
    [Category("AgentSpawn")]
    [DisplayName("Info")]
    [Description("Dieses Tool benötigt keine Konfiguration. Es ermöglicht Agenten, andere Agenten zu starten und ihnen Aufgaben zuzuweisen.")]
    [ReadOnly(true)]
    public string Status { get; set; } = "Aktiv";

    public Dictionary<string, object?> ToConfig() => new();

    public static AgentSpawnToolSettings FromConfig(Dictionary<string, object?> config) => new();
}

public static class ToolSettingsFactory
{
    public static object? CreateViewModel(string toolName, Dictionary<string, object?>? config)
    {
        config ??= new();
        return toolName switch
        {
            "FileRW" => FileRWToolSettings.FromConfig(config),
            "Mail" => MailToolSettings.FromConfig(config),
            "Database" => DatabaseToolSettings.FromConfig(config),
            "Telegram" => TelegramToolSettings.FromConfig(config),
            "FTP" => FTPToolSettings.FromConfig(config),
            "DirectAPI" => DirectAPIToolSettings.FromConfig(config),
            "WebFetch" => WebFetchToolSettings.FromConfig(config),
            "WebMonitor" => WebMonitorToolSettings.FromConfig(config),
            "AgentComm" => AgentCommToolSettings.FromConfig(config),
            "SocialMediaManager" => SocialMediaManagerToolSettings.FromConfig(config),
            "AgentSpawn" => AgentSpawnToolSettings.FromConfig(config),
            "AgentEditor" => AgentEditorToolSettings.FromConfig(config),
            _ => null
        };
    }

    public static Dictionary<string, object?>? ToConfig(string toolName, object? viewModel)
    {
        return viewModel switch
        {
            FileRWToolSettings f => f.ToConfig(),
            MailToolSettings m => m.ToConfig(),
            DatabaseToolSettings d => d.ToConfig(),
            TelegramToolSettings t => t.ToConfig(),
            FTPToolSettings ftp => ftp.ToConfig(),
            DirectAPIToolSettings dapi => dapi.ToConfig(),
            WebFetchToolSettings wf => wf.ToConfig(),
            WebMonitorToolSettings wm => wm.ToConfig(),
            AgentCommToolSettings ac => ac.ToConfig(),
            SocialMediaManagerToolSettings smm => smm.ToConfig(),
            AgentSpawnToolSettings asp => asp.ToConfig(),
            AgentEditorToolSettings ae => ae.ToConfig(),
            _ => null
        };
    }
}
