using ClaudeDo.Worker.Skills;

namespace ClaudeDo.Worker.Tests.Skills;

/// <summary>
/// Test double for IRepoCloner: "clones" by copying a pre-built local fixture directory,
/// so tests never touch the network or invoke real git. One fixture dir + pinned ref can
/// be registered per source URL.
/// </summary>
public sealed class FakeRepoCloner : IRepoCloner
{
    private readonly Dictionary<string, (string FixtureDir, string PinnedRef)> _sources = new();
    private int _cloneCount;

    public int CloneCount => _cloneCount;

    public void Register(string url, string fixtureDir, string pinnedRef) =>
        _sources[url] = (fixtureDir, pinnedRef);

    public Task<ClonedRepo> CloneAsync(string url, string destDir, CancellationToken ct)
    {
        _cloneCount++;
        if (!_sources.TryGetValue(url, out var source))
            throw new InvalidOperationException($"FakeRepoCloner has no fixture registered for '{url}'.");

        CopyDirectory(source.FixtureDir, destDir);
        return Task.FromResult(new ClonedRepo(destDir, source.PinnedRef));
    }

    private static void CopyDirectory(string sourceDir, string destDir)
    {
        Directory.CreateDirectory(destDir);
        foreach (var file in Directory.EnumerateFiles(sourceDir, "*", SearchOption.AllDirectories))
        {
            var relative = Path.GetRelativePath(sourceDir, file);
            var destPath = Path.Combine(destDir, relative);
            var destParent = Path.GetDirectoryName(destPath);
            if (!string.IsNullOrEmpty(destParent))
                Directory.CreateDirectory(destParent);
            File.Copy(file, destPath, overwrite: true);
        }
    }
}
