using VigilCare.Simulation;

public interface IScenarioCatalog
{
    IReadOnlyList<ScenarioFile> ListScenarios();
    ScenarioFile? GetById(string scenarioId);
}

public sealed class ScenarioCatalog : IScenarioCatalog
{
    private readonly string _directory;
    private readonly object _gate = new();
    private IReadOnlyList<(ScenarioFile Scenario, string Path, DateTime LastWriteUtc)> _entries =
        Array.Empty<(ScenarioFile, string, DateTime)>();

    public ScenarioCatalog(Microsoft.Extensions.Options.IOptions<SimulationOptions> options)
    {
        _directory = options.Value.ScenarioDirectory;
    }

    public IReadOnlyList<ScenarioFile> ListScenarios()
    {
        RefreshIfNeeded();
        return _entries.Select(e => e.Scenario).ToList();
    }

    public ScenarioFile? GetById(string scenarioId)
    {
        RefreshIfNeeded();
        return _entries
            .Select(e => e.Scenario)
            .FirstOrDefault(s => string.Equals(
                s.Scenario.Id, scenarioId, StringComparison.OrdinalIgnoreCase));
    }

    private void RefreshIfNeeded()
    {
        lock (_gate)
        {
            if (!Directory.Exists(_directory))
            {
                _entries = Array.Empty<(ScenarioFile, string, DateTime)>();
                return;
            }

            var disk = Directory.EnumerateFiles(_directory, "*.json")
                .Where(p => !string.Equals(
                    Path.GetFileName(p), "schema.json", StringComparison.OrdinalIgnoreCase))
                .Select(p => (Path: p, LastWriteUtc: File.GetLastWriteTimeUtc(p)))
                .OrderBy(x => x.Path, StringComparer.OrdinalIgnoreCase)
                .ToList();

            var unchanged = _entries.Count == disk.Count
                && _entries.Zip(disk, (cached, onDisk) =>
                        cached.Path == onDisk.Path && cached.LastWriteUtc == onDisk.LastWriteUtc)
                    .All(eq => eq);

            if (unchanged)
                return;

            var loaded = new List<(ScenarioFile Scenario, string Path, DateTime LastWriteUtc)>();
            foreach (var file in disk)
            {
                try
                {
                    loaded.Add((ScenarioLoader.Load(file.Path), file.Path, file.LastWriteUtc));
                }
                catch
                {
                    // Skip corrupt files — catalogue must stay resilient.
                }
            }

            _entries = loaded
                .OrderBy(e => e.Scenario.Scenario.Id, StringComparer.OrdinalIgnoreCase)
                .ToList();
        }
    }
}
