using Sdt.Config;

namespace Sdt.Core;

public sealed class RequirementResolver : IRequirementResolver
{
    public List<ToolRequirement> Resolve(WorkflowStep step)
    {
        if (step.Requires.Count > 0)
            return step.Requires.ToList();

        if (!string.IsNullOrWhiteSpace(step.Action))
            return InferActionRequirements(step.Action);

        if (string.IsNullOrWhiteSpace(step.Command))
            return [];

        return InferCommandRequirements(step.Command, step.Args);
    }

    public List<ToolRequirement> Resolve(BuildTarget target)
    {
        if (string.IsNullOrWhiteSpace(target.Command))
            return [];

        return InferCommandRequirements(target.Command, target.Args);
    }

    private static List<ToolRequirement> InferActionRequirements(string action)
    {
        return action.ToLowerInvariant() switch
        {
            "dotnet-restore" or "dotnet-build" or "dotnet-test" or "dotnet-publish" => [Req("dotnet")],
            "npm-install" or "npm-ci" or "npm-build" or "npm-test" or "npm-audit" => [Req("node"), Req("npm")],
            "python-venv-create" or "python-pip-install" or "python-pip-sync" or "python-pytest" => [Req("python")],
            "cargo-build" or "cargo-test" => [Req("cargo")],
            "tauri-build" => [Req("cargo"), Req("node"), Req("npm")],
            "git-status" or "git-fetch" or "git-pull" or "git-clean" => [Req("git")],
            "docker-build" or "docker-compose-up" or "docker-compose-down" => [Req("docker")],
            _ => [],
        };
    }

    private static List<ToolRequirement> InferCommandRequirements(string command, IReadOnlyList<string> args)
    {
        return command.ToLowerInvariant() switch
        {
            "dotnet" => [Req("dotnet")],
            "npm" => [Req("node"), Req("npm")],
            "pnpm" => [Req("node"), Req("pnpm")],
            "yarn" => [Req("node"), Req("yarn")],
            "python" or "py" => [Req("python")],
            "cargo" => [Req("cargo")],
            "tauri" => [Req("cargo"), Req("node"), Req("npm")],
            "git" => [Req("git")],
            "docker" => [Req("docker")],
            "pwsh" or "powershell" => LegacyScriptRequirementResolver.InferForPowerShellArgs(args),
            _ => [],
        };
    }

    private static ToolRequirement Req(string tool) => new()
    {
        Tool = tool,
        InstallPolicy = InstallPolicy.Prompt,
    };
}
