using Flyshot.ControllerClientCompat;
using Flyshot.Core.Config;

namespace Flyshot.Core.Tests;

/// <summary>
/// 验证 ControllerClient 兼容层默认围绕运行目录 Config 读写配置和轨迹文件。
/// </summary>
public sealed class ControllerClientCompatConfigRootTests
{
    /// <summary>
    /// 验证路径兼容层优先命中运行目录 Config 下的 RobotConfig.json，而不是旧仓库根目录候选。
    /// </summary>
    [Fact]
    public void PathCompatibility_ResolvesRuntimeConfigBeforeLegacyCandidates()
    {
        var runtimeRoot = CreateTempDirectory();
        try
        {
            var configPath = Path.Combine(runtimeRoot, "Config", "RobotConfig.json");
            var legacyPath = Path.Combine(runtimeRoot, "RobotConfig.json");
            Directory.CreateDirectory(Path.GetDirectoryName(configPath)!);
            File.WriteAllText(configPath, "{}");
            File.WriteAllText(legacyPath, "{}");

            var resolved = PathCompatibility.ResolveConfigPath("RobotConfig.json", runtimeRoot);

            Assert.Equal(configPath, resolved);
        }
        finally
        {
            Directory.Delete(runtimeRoot, recursive: true);
        }
    }

    /// <summary>
    /// 验证机器人目录优先从显式 ConfigRoot/Models 加载现场 JSON 模型文件。
    /// </summary>
    [Fact]
    public void ControllerClientCompatRobotCatalog_LoadsModelFromConfigRootModels()
    {
        var configRoot = CreateTempConfigRoot();
        try
        {
            CopySampleRobotModel(configRoot);
            var options = new ControllerClientCompatOptions { ConfigRoot = configRoot };
            var catalog = new ControllerClientCompatRobotCatalog(options, new RobotModelLoader());

            var profile = catalog.LoadProfile("FANUC_LR_Mate_200iD");

            Assert.Equal(Path.Combine(configRoot, "Models", "LR_Mate_200iD_7L.json"), profile.ModelPath);
        }
        finally
        {
            Directory.Delete(configRoot, recursive: true);
        }
    }

    /// <summary>
    /// 验证 JSON 轨迹存储保存、加载和删除都落在 ConfigRoot/RobotConfig.json。
    /// </summary>
    [Fact]
    public void JsonFlyshotTrajectoryStore_PersistsTrajectoriesInRobotConfigJson()
    {
        var configRoot = CreateTempConfigRoot();
        try
        {
            var options = new ControllerClientCompatOptions { ConfigRoot = configRoot };
            var store = new JsonFlyshotTrajectoryStore(options, new RobotConfigLoader());
            var settings = new CompatibilityRobotSettings(
                useDo: true,
                ioAddresses: [7, 8],
                ioKeepCycles: 2,
                triggerSampleIndexOffsetCycles: 7,
                accLimitScale: 1.0,
                jerkLimitScale: 1.0,
                adaptIcspTryNum: 5,
                speedRatio: 0.65);
            var trajectory = TestRobotFactory.CreateUploadedTrajectoryWithSingleShot();

            store.Save("FANUC_LR_Mate_200iD", settings, trajectory);
            var expectedPath = Path.Combine(configRoot, "RobotConfig.json");

            Assert.True(File.Exists(expectedPath), $"应在运行目录 Config 下创建统一配置文件: {expectedPath}");
            Assert.False(Directory.Exists(Path.Combine(configRoot, "TrajectoryStore")), "不应再创建独立轨迹存储目录。");
            var loaded = store.LoadAll("FANUC_LR_Mate_200iD", out var loadedSettings);
            Assert.NotNull(loadedSettings);
            Assert.Equal(7, loadedSettings.TriggerSampleIndexOffsetCycles);
            Assert.Equal(0.65, loadedSettings.SpeedRatio, precision: 6);
            Assert.Contains(trajectory.Name, loaded);

            store.Delete("FANUC_LR_Mate_200iD", trajectory.Name);

            var afterDelete = store.LoadAll("FANUC_LR_Mate_200iD", out _);
            Assert.Empty(afterDelete);
        }
        finally
        {
            Directory.Delete(configRoot, recursive: true);
        }
    }

    /// <summary>
    /// 创建测试专用的运行目录 Config 根，避免污染真实输出目录。
    /// </summary>
    private static string CreateTempConfigRoot()
    {
        var root = Path.Combine(Path.GetTempPath(), "flyshot-config-root-tests", Guid.NewGuid().ToString("N"), "Config");
        Directory.CreateDirectory(root);
        return root;
    }

    /// <summary>
    /// 创建测试专用的临时目录。
    /// </summary>
    private static string CreateTempDirectory()
    {
        var root = Path.Combine(Path.GetTempPath(), "flyshot-config-root-tests", Guid.NewGuid().ToString("N"));
        Directory.CreateDirectory(root);
        return root;
    }

    /// <summary>
    /// 复制仓库内已固化的现场机器人 JSON 模型到临时 Config/Models 目录。
    /// </summary>
    private static void CopySampleRobotModel(string configRoot)
    {
        var modelDir = Path.Combine(configRoot, "Models");
        Directory.CreateDirectory(modelDir);
        File.Copy(
            Path.Combine(GetReplacementRoot(), "Config", "Models", "LR_Mate_200iD_7L.json"),
            Path.Combine(modelDir, "LR_Mate_200iD_7L.json"));
    }

    /// <summary>
    /// 定位 replacement 仓库根目录，供测试读取仓库内固化样本。
    /// </summary>
    private static string GetReplacementRoot()
    {
        var current = new DirectoryInfo(AppContext.BaseDirectory);
        while (current is not null)
        {
            if (File.Exists(Path.Combine(current.FullName, "FlyshotReplacement.sln")))
            {
                return current.FullName;
            }

            current = current.Parent;
        }

        throw new DirectoryNotFoundException("Unable to locate the flyshot replacement root.");
    }
}
