using System.CommandLine;
using NatsNet.PortTracker.Data;

namespace NatsNet.PortTracker.Commands;

public static class LibraryCommands
{
    public static Command Create(Option<string> dbOption, Option<string> schemaOption)
    {
        var libraryCommand = new Command("library", "Manage library mappings");

        // list
        var listStatus = new Option<string?>("--status") { Description = "Filter by status" };
        var listCmd = new Command("list", "List library mappings");
        listCmd.Add(listStatus);
        listCmd.SetAction(parseResult =>
        {
            var dbPath = parseResult.GetValue(dbOption)!;
            var status = parseResult.GetValue(listStatus);
            using var db = new Database(dbPath);
            var sql = "SELECT id, go_import_path, go_library_name, dotnet_package, dotnet_namespace, status FROM library_mappings";
            var parameters = new List<(string, object?)>();
            if (status is not null)
            {
                sql += " WHERE status = @status";
                parameters.Add(("@status", status));
            }
            sql += " ORDER BY go_import_path";

            var rows = db.Query(sql, parameters.ToArray());
            Console.WriteLine($"{"ID",-5} {"Go Import Path",-40} {"Go Library",-20} {"DotNet Package",-25} {"DotNet Namespace",-25} {"Status",-12}");
            Console.WriteLine(new string('-', 127));
            foreach (var row in rows)
            {
                Console.WriteLine($"{row["id"],-5} {Truncate(row["go_import_path"]?.ToString(), 39),-40} {Truncate(row["go_library_name"]?.ToString(), 19),-20} {Truncate(row["dotnet_package"]?.ToString(), 24),-25} {Truncate(row["dotnet_namespace"]?.ToString(), 24),-25} {row["status"],-12}");
            }
            Console.WriteLine($"\nTotal: {rows.Count} library mappings");
        });

        // map
        var mapId = new Argument<int>("id") { Description = "Library mapping ID" };
        var mapPackage = new Option<string?>("--package") { Description = ".NET NuGet package" };
        var mapNamespace = new Option<string?>("--namespace") { Description = ".NET namespace" };
        var mapNotes = new Option<string?>("--notes") { Description = "Usage notes" };
        var mapCmd = new Command("map", "Map Go library to .NET package");
        mapCmd.Add(mapId);
        mapCmd.Add(mapPackage);
        mapCmd.Add(mapNamespace);
        mapCmd.Add(mapNotes);
        mapCmd.SetAction(parseResult =>
        {
            var dbPath = parseResult.GetValue(dbOption)!;
            var id = parseResult.GetValue(mapId);
            var package = parseResult.GetValue(mapPackage);
            var ns = parseResult.GetValue(mapNamespace);
            var notes = parseResult.GetValue(mapNotes);
            using var db = new Database(dbPath);
            var affected = db.Execute(
                "UPDATE library_mappings SET dotnet_package = COALESCE(@package, dotnet_package), dotnet_namespace = COALESCE(@ns, dotnet_namespace), dotnet_usage_notes = COALESCE(@notes, dotnet_usage_notes), status = 'mapped' WHERE id = @id",
                ("@package", package), ("@ns", ns), ("@notes", notes), ("@id", id));
            Console.WriteLine(affected > 0 ? $"Library {id} mapped." : $"Library {id} not found.");
        });

        // suggest
        var suggestCmd = new Command("suggest", "Show unmapped libraries");
        suggestCmd.SetAction(parseResult =>
        {
            var dbPath = parseResult.GetValue(dbOption)!;
            using var db = new Database(dbPath);
            var rows = db.Query(
                "SELECT id, go_import_path, go_library_name, go_usage_description FROM library_mappings WHERE status = 'not_mapped' ORDER BY go_import_path");
            if (rows.Count == 0)
            {
                Console.WriteLine("All libraries have been mapped!");
                return;
            }
            Console.WriteLine($"{"ID",-5} {"Go Import Path",-45} {"Library",-20} {"Usage",-40}");
            Console.WriteLine(new string('-', 110));
            foreach (var row in rows)
            {
                Console.WriteLine($"{row["id"],-5} {Truncate(row["go_import_path"]?.ToString(), 44),-45} {Truncate(row["go_library_name"]?.ToString(), 19),-20} {Truncate(row["go_usage_description"]?.ToString(), 39),-40}");
            }
            Console.WriteLine($"\n{rows.Count} unmapped libraries need attention.");
        });

        libraryCommand.Add(listCmd);
        libraryCommand.Add(mapCmd);
        libraryCommand.Add(suggestCmd);

        return libraryCommand;
    }

    private static string Truncate(string? s, int maxLen)
    {
        if (s is null) return "";
        return s.Length <= maxLen ? s : s[..(maxLen - 2)] + "..";
    }
}
