using System.Reflection;
using System.Text.Json;
using Microsoft.Extensions.Configuration;

namespace ZB.MOM.WW.ScadaBridge.Host.Tests;

/// <summary>
/// Host-014 regression: REQ-HOST-8 requires the Host's Serilog sinks
/// (console and file at minimum) to be <em>configuration-driven</em>. The sinks
/// must be defined in a <c>Serilog</c> section in <c>appsettings.json</c> and
/// applied via <c>ReadFrom.Configuration</c> — they must not be hard-coded in
/// <c>Program.cs</c>, so an operator can change the file path, rolling interval or
/// output template without recompiling.
/// </summary>
public class SerilogSinkConfigTests
{
    private static string FindHostProjectDirectory()
    {
        var assemblyDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!;
        var dir = new DirectoryInfo(assemblyDir);
        while (dir != null)
        {
            var hostPath = Path.Combine(dir.FullName, "src", "ZB.MOM.WW.ScadaBridge.Host");
            if (Directory.Exists(hostPath))
                return hostPath;
            dir = dir.Parent;
        }
        throw new DirectoryNotFoundException("Could not locate src/ZB.MOM.WW.ScadaBridge.Host");
    }

    [Fact]
    public void ShippedAppSettings_HasSerilogSection_WithConsoleAndFileSinks()
    {
        var path = Path.Combine(FindHostProjectDirectory(), "appsettings.json");
        using var doc = JsonDocument.Parse(File.ReadAllText(path));

        Assert.True(
            doc.RootElement.TryGetProperty("Serilog", out var serilog),
            "appsettings.json must contain a `Serilog` section so ReadFrom.Configuration " +
            "drives the sinks (REQ-HOST-8 / Host-014).");

        Assert.True(
            serilog.TryGetProperty("WriteTo", out var writeTo),
            "the `Serilog` section must contain a `WriteTo` array defining the sinks.");

        var sinkNames = writeTo.EnumerateArray()
            .Select(e => e.TryGetProperty("Name", out var n) ? n.GetString() : null)
            .ToList();

        Assert.Contains("Console", sinkNames);
        Assert.Contains("File", sinkNames);
    }

    [Fact]
    public void LoggerConfigurationFactory_AppliesConfiguredFileSink()
    {
        // A `Serilog` section in configuration must actually reach the built logger
        // via ReadFrom.Configuration — proving the sink set is configuration-driven.
        var logDir = Path.Combine(Path.GetTempPath(), "scadabridge-host014-" + Guid.NewGuid().ToString("N"));
        var logPath = Path.Combine(logDir, "test-.log");
        try
        {
            var configuration = new ConfigurationBuilder()
                .AddInMemoryCollection(new Dictionary<string, string?>
                {
                    ["Serilog:Using:0"] = "Serilog.Sinks.File",
                    ["Serilog:WriteTo:0:Name"] = "File",
                    ["Serilog:WriteTo:0:Args:path"] = logPath,
                    ["Serilog:WriteTo:0:Args:rollingInterval"] = "Day",
                })
                .Build();

            var logger = LoggerConfigurationFactory
                .Build(configuration, "Central", "central", "node1")
                .CreateLogger();

            logger.Information("host-014 configured-sink probe");
            logger.Dispose();

            Assert.True(Directory.Exists(logDir), "the configured file sink must have created its directory.");
            var written = Directory.GetFiles(logDir, "test-*.log");
            Assert.NotEmpty(written);
            Assert.Contains(
                "host-014 configured-sink probe",
                File.ReadAllText(written[0]));
        }
        finally
        {
            if (Directory.Exists(logDir))
                Directory.Delete(logDir, recursive: true);
        }
    }
}
