namespace ClaudeDo.Ui.Services;

// Two named types because DI resolves them by type, not by key.
public sealed class InstallerLocator() : InstallArtifactLocator("uninstaller", "ClaudeDo.Installer.exe");

public sealed class WorkerLocator() : InstallArtifactLocator("worker", "ClaudeDo.Worker.exe");

/// <summary>
/// Locates an executable inside a ClaudeDo install: walk up from the running
/// directory to the folder containing install.json, otherwise read the
/// uninstall registry key (which is what makes this work from a dev build).
/// </summary>
public abstract class InstallArtifactLocator(string subdir, string exeName)
{
    private const string InstallJson = "install.json";

    public string? Find()
        => FindByWalkingUp(AppContext.BaseDirectory)
           ?? (OperatingSystem.IsWindows() ? FindByRegistry() : null);

    public string? FindByWalkingUp(string startDir)
    {
        var dir = new DirectoryInfo(startDir);
        while (dir is not null)
        {
            if (File.Exists(Path.Combine(dir.FullName, InstallJson)))
                return Candidate(dir.FullName);
            dir = dir.Parent;
        }
        return null;
    }

    [System.Runtime.Versioning.SupportedOSPlatform("windows")]
    public string? FindByRegistry()
    {
        if (!OperatingSystem.IsWindows()) return null;
        try
        {
            using var key = Microsoft.Win32.Registry.LocalMachine
                .OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Uninstall\ClaudeDo");
            var location = key?.GetValue("InstallLocation") as string;
            return string.IsNullOrEmpty(location) ? null : Candidate(location);
        }
        catch { return null; }
    }

    private string? Candidate(string installDir)
    {
        var path = Path.Combine(installDir, subdir, exeName);
        return File.Exists(path) ? path : null;
    }
}
