using System.Text.Json.Serialization;
using YMhut.Box.Core.Tools;

namespace YMhut.Box.Core.Plugins;

public enum PluginPermission
{
    Input,
    Output,
    Log,
    Storage,
    Http,
    Clipboard,
    FilePicker,
    RunTool,
    OpenExternal,
    NetworkDiagnostics
}

public enum PluginSurfaceKind
{
    ToolboxTool,
    NavPage
}

public sealed record PluginManifest(
    string Id,
    string Name,
    string Version,
    string Author,
    string Description,
    string Entry,
    IReadOnlyList<PluginPermission> Permissions,
    IReadOnlyList<PluginSurface> Surfaces,
    IReadOnlyList<string> Resources)
{
    public static readonly string FileName = "ymhut.plugin.json";
}

public sealed record PluginSurface(
    PluginSurfaceKind Kind,
    string Id,
    string Name,
    string Description,
    string Entry = "",
    string Category = "dev",
    IReadOnlyList<string>? Keywords = null,
    string IconGlyph = "\uECAA")
{
    public string EffectiveEntry(string pluginEntry) => string.IsNullOrWhiteSpace(Entry) ? pluginEntry : Entry;
}

public sealed record PluginRuntimeState(
    string PluginId,
    bool Enabled,
    IReadOnlySet<PluginPermission> GrantedPermissions,
    IReadOnlySet<string> MountedSurfaceIds,
    DateTimeOffset? LastRunAt);

public sealed record LoadedPlugin(
    PluginManifest Manifest,
    string RootPath,
    PluginRuntimeState State,
    IReadOnlyList<string> Errors)
{
    public bool IsValid => Errors.Count == 0;
}

public sealed class PluginToolModule(LoadedPlugin plugin, PluginSurface surface) : IToolModule
{
    public LoadedPlugin Plugin { get; } = plugin;

    public PluginSurface Surface { get; } = surface;

    public string Id { get; } = PluginIds.ToolId(plugin.Manifest.Id, surface.Id);

    public ToolMetadata Metadata { get; } = new(
        PluginIds.ToolId(plugin.Manifest.Id, surface.Id),
        surface.Name,
        surface.Description,
        ToolCategory.Plugin,
        (surface.Keywords ?? []).Concat(["plugin", plugin.Manifest.Id, plugin.Manifest.Name]).Distinct(StringComparer.OrdinalIgnoreCase).ToArray(),
        false,
        string.IsNullOrWhiteSpace(surface.IconGlyph) ? "\uECAA" : surface.IconGlyph);

    public object CreateViewModel() => new ToolModuleViewModel(Metadata);
}

public static class PluginIds
{
    public const string Prefix = "plugin:";

    public static bool IsPluginToolId(string id) => id.StartsWith(Prefix, StringComparison.OrdinalIgnoreCase);

    public static string ToolId(string pluginId, string surfaceId) => $"{Prefix}{Normalize(pluginId)}:{Normalize(surfaceId)}";

    public static string Normalize(string id) => id.Trim().ToLowerInvariant();

    public static bool IsSafeId(string id)
    {
        return !string.IsNullOrWhiteSpace(id) &&
            id.Length <= 64 &&
            id.All(ch => char.IsAsciiLetterOrDigit(ch) || ch is '-' or '_' or '.');
    }

    public static ToolCategory ParseCategory(string? category)
    {
        return category?.Trim().ToLowerInvariant() switch
        {
            "plugin" => ToolCategory.Plugin,
            "network" => ToolCategory.Network,
            "security" => ToolCategory.Security,
            "data" => ToolCategory.Data,
            "calculator" => ToolCategory.Calculator,
            "text" => ToolCategory.Text,
            "image" => ToolCategory.Image,
            "design" => ToolCategory.Design,
            "life" => ToolCategory.Life,
            "system" => ToolCategory.System,
            _ => ToolCategory.Dev
        };
    }
}

[JsonSerializable(typeof(PluginManifest))]
[JsonSerializable(typeof(PluginSurface))]
internal sealed partial class PluginJsonContext : JsonSerializerContext;
