using Sdt.Config;
using Spectre.Console;

namespace Sdt.Tui;

public sealed class WorkspaceScreen(WorkspaceConfig workspace, string workspaceRoot, string currentProjectRoot)
{
    private readonly WorkspaceConfig _workspace = workspace;
    private readonly string _workspaceRoot = workspaceRoot;
    private readonly string _currentProjectRoot = currentProjectRoot;

    /// <summary>
    /// Shows the project switcher. Returns the absolute path to the selected project root,
    /// or null if the user cancelled.
    /// </summary>
    public string? SelectProject()
    {
        while (true)
        {
            AnsiConsole.Clear();
            AnsiConsole.Write(Theme.SectionRule("WORKSPACE — " + _workspace.Name));
            AnsiConsole.WriteLine();

            var projects = _workspace.Projects;
            if (projects.Count == 0)
            {
                AnsiConsole.MarkupLine(Theme.Warn("No projects defined in sdt-workspace.json."));
                AnsiConsole.MarkupLine(Theme.Faint("Add entries to the \"projects\" array."));
                if (AnsiConsole.Confirm($"[{Theme.Amber}]Add an external project now?[/]", defaultValue: true))
                {
                    AddExternalProject();
                    continue;
                }

                AnsiConsole.MarkupLine("\n" + Theme.Faint("Press any key to go back..."));
                Console.ReadKey(intercept: true);
                return null;
            }

            // Build choice list with current project marked
            var choices = new List<WorkspaceMenuItem>();
            foreach (var proj in projects)
            {
                var absPath = WorkspaceLoader.ResolveProjectRoot(_workspaceRoot, proj);
                var devtoolPath = Path.Combine(absPath, "devtool.json");
                var isCurrent = string.Equals(absPath, _currentProjectRoot, StringComparison.OrdinalIgnoreCase);
                var exists = File.Exists(devtoolPath);

                var label = isCurrent
                    ? $"[bold {Theme.GreenBold}]► {Markup.Escape(proj.Name)}[/]  [{Theme.GreenDim}](current)[/]"
                    : $"[{Theme.Green}]  {Markup.Escape(proj.Name)}[/]";
                if (proj.Disabled)
                    label += $"  [{Theme.Amber}](disabled)[/]";

                var desc = !exists
                    ? $"  [{Theme.Red}]devtool.json not found[/]"
                    : string.IsNullOrWhiteSpace(proj.Description)
                        ? $"  [{Theme.GreenDim}]{Markup.Escape(absPath)}[/]"
                        : $"  [{Theme.GreenDim}]{Markup.Escape(proj.Description)}[/]";
                if (proj.Tags.Count > 0)
                    desc += $"  [{Theme.GreenDim}]tags: {Markup.Escape(string.Join(",", proj.Tags))}[/]";

                choices.Add(new WorkspaceMenuItem(label + "\n" + desc, absPath, exists && !isCurrent && !proj.Disabled));
            }

            choices.Add(new WorkspaceMenuItem($"[{Theme.Green}]＋ Add external project[/]", "__add__", true));
            choices.Add(new WorkspaceMenuItem($"[{Theme.GreenDim}]← Cancel[/]", null, true));

            // Show project table for overview
            var table = new Table()
                .Border(TableBorder.Rounded)
                .BorderStyle(Theme.DimStyle)
                .AddColumn(new TableColumn($"[{Theme.Amber}]Project[/]"))
                .AddColumn(new TableColumn($"[{Theme.Amber}]Path[/]"))
                .AddColumn(new TableColumn($"[{Theme.Amber}]Status[/]").Width(12));

            foreach (var proj in projects)
            {
                var absPath = WorkspaceLoader.ResolveProjectRoot(_workspaceRoot, proj);
                var isCurrent = string.Equals(absPath, _currentProjectRoot, StringComparison.OrdinalIgnoreCase);
                var hasConfig = File.Exists(Path.Combine(absPath, "devtool.json"));
                var status = proj.Disabled
                    ? Theme.Warn("disabled")
                    : hasConfig ? Theme.Ok("ready") : Theme.Fail("no config");

                table.AddRow(
                    isCurrent
                        ? $"[bold {Theme.GreenBold}]► {Markup.Escape(proj.Name)}[/]"
                        : Theme.G(proj.Name),
                    Theme.Faint(proj.Path),
                    status);
            }

            AnsiConsole.Write(table);
            AnsiConsole.WriteLine();

            var switchable = choices.Where(c => c.Selectable).ToList();
            if (switchable.Count == 1) // only Cancel
            {
                AnsiConsole.MarkupLine(Theme.Warn("No other projects available to switch to."));
                AnsiConsole.MarkupLine("\n" + Theme.Faint("Press any key to go back..."));
                Console.ReadKey(intercept: true);
                return null;
            }

            var selected = AnsiConsole.Prompt(
                new SelectionPrompt<WorkspaceMenuItem>()
                    .Title($"[{Theme.Green}]Switch to project:[/]")
                    .PageSize(15)
                    .UseConverter(m => m.Display)
                    .AddChoices(switchable));

            if (selected.AbsPath == "__add__")
            {
                AddExternalProject();
                continue;
            }

            return selected.AbsPath; // null = cancelled
        }
    }

    private void AddExternalProject()
    {
        var raw = AnsiConsole.Ask<string>($"[{Theme.Amber}]Project root path[/]");
        if (string.IsNullOrWhiteSpace(raw))
            return;

        var absolutePath = Path.GetFullPath(raw.Trim());
        if (!Directory.Exists(absolutePath))
        {
            AnsiConsole.MarkupLine(Theme.Fail("Directory does not exist."));
            Thread.Sleep(700);
            return;
        }

        var configPath = Path.Combine(absolutePath, "devtool.json");
        if (!File.Exists(configPath))
        {
            var create = AnsiConsole.Confirm(
                $"[{Theme.Amber}]No devtool.json found. Create a minimal template?[/]",
                defaultValue: true);
            if (!create)
                return;

            File.WriteAllText(configPath, "{\n  \"name\": \"SDT Project\",\n  \"version\": \"0.1.0\",\n  \"workflows\": []\n}\n");
        }

        if (_workspace.Projects.Any(p =>
                string.Equals(WorkspaceLoader.ResolveProjectRoot(_workspaceRoot, p), absolutePath, StringComparison.OrdinalIgnoreCase)))
        {
            AnsiConsole.MarkupLine(Theme.Warn("Project already exists in workspace."));
            Thread.Sleep(700);
            return;
        }

        var relativePath = Path.GetRelativePath(_workspaceRoot, absolutePath);
        var useRelative = !relativePath.StartsWith("..", StringComparison.OrdinalIgnoreCase) && !Path.IsPathRooted(relativePath);
        var projectEntry = new WorkspaceProject
        {
            Name = new DirectoryInfo(absolutePath).Name,
            Description = $"External project at {absolutePath}",
            Path = useRelative ? relativePath : absolutePath,
            Disabled = false,
        };

        _workspace.Projects.Add(projectEntry);
        WorkspaceLoader.Save(_workspaceRoot, _workspace);
        AnsiConsole.MarkupLine(Theme.Ok("Project added to workspace."));
        Thread.Sleep(700);
    }

    private sealed record WorkspaceMenuItem(string Display, string? AbsPath, bool Selectable);
}
