using System;
using System.Security.Principal;
using System.Threading;
using Serilog;
using ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Host.Backend;
using ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Host.Ipc;

namespace ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Host;

/// <summary>
///     Entry point for the <c>OtOpcUaFocasHost</c> Windows service / console host. The
///     supervisor (Proxy-side) spawns this process per FOCAS driver instance and passes the
///     pipe name, allowed-SID, and per-process shared secret as environment variables. In
///     PR B the backend is <see cref="StubFrameHandler"/> — PR C swaps in the real
///     Fwlib32-backed handler once the session state + STA thread move out of the .NET 10
///     driver.
/// </summary>
public static class Program
{
    public static int Main(string[] args)
    {
        Log.Logger = new LoggerConfiguration()
            .MinimumLevel.Information()
            .WriteTo.File(
                @"%ProgramData%\OtOpcUa\focas-host-.log".Replace("%ProgramData%", Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData)),
                rollingInterval: RollingInterval.Day)
            .CreateLogger();

        try
        {
            var pipeName = Environment.GetEnvironmentVariable("OTOPCUA_FOCAS_PIPE") ?? "OtOpcUaFocas";
            var allowedSidValue = Environment.GetEnvironmentVariable("OTOPCUA_ALLOWED_SID")
                ?? throw new InvalidOperationException(
                    "OTOPCUA_ALLOWED_SID not set — the FOCAS Proxy supervisor must pass the server principal SID");
            var sharedSecret = Environment.GetEnvironmentVariable("OTOPCUA_FOCAS_SECRET")
                ?? throw new InvalidOperationException(
                    "OTOPCUA_FOCAS_SECRET not set — the FOCAS Proxy supervisor must pass the per-process secret at spawn time");

            var allowedSid = new SecurityIdentifier(allowedSidValue);

            using var server = new PipeServer(pipeName, allowedSid, sharedSecret, Log.Logger);
            using var cts = new CancellationTokenSource();
            Console.CancelKeyPress += (_, e) => { e.Cancel = true; cts.Cancel(); };

            Log.Information("OtOpcUaFocasHost starting — pipe={Pipe} allowedSid={Sid}",
                pipeName, allowedSidValue);

            var backendKind = (Environment.GetEnvironmentVariable("OTOPCUA_FOCAS_BACKEND") ?? "unconfigured")
                .ToLowerInvariant();
            IFocasBackend backend = backendKind switch
            {
                "fake"         => new FakeFocasBackend(),
                "unconfigured" => new UnconfiguredFocasBackend(),
                "fwlib32"      => new UnconfiguredFocasBackend(), // real Fwlib32 backend lands with hardware integration follow-up
                _              => new UnconfiguredFocasBackend(),
            };
            Log.Information("OtOpcUaFocasHost backend={Backend}", backendKind);

            var handler = new FwlibFrameHandler(backend, Log.Logger);
            server.RunAsync(handler, cts.Token).GetAwaiter().GetResult();

            Log.Information("OtOpcUaFocasHost stopped cleanly");
            return 0;
        }
        catch (Exception ex)
        {
            Log.Fatal(ex, "OtOpcUaFocasHost fatal");
            return 2;
        }
        finally { Log.CloseAndFlush(); }
    }
}
