using System;
using System.Net;
using System.Threading;
using Tesla;
using VPod;
using Xunit;

namespace TeslaConsole.DiffTests
{
    /// <summary>
    /// End-to-end loopback exercise of vPOD's pod-side SecureConfig provisioning
    /// against the REAL console-side implementation (Tesla.PodConfigurationServer,
    /// the exact code the console runs behind Manage Site's "Configure" button):
    /// RQST beacon reception, the AES "RPLY" config broadcast, and the OFB+RSA
    /// session-key exchange must all interoperate.
    ///
    /// Uses the protocol's fixed ports (UDP 53291/53292, TCP 53292) and real UDP
    /// broadcasts on loopback — do not run while a console or another vPOD is
    /// provisioning on this machine.
    /// </summary>
    public class VPodProvisioningTests
    {
        [Fact]
        public void Console_Provisions_VPod_And_Both_Hold_The_Same_Session_Key()
        {
            byte[] mac = PodProvisioning.MacForHost(7);
            var provisioning = new PodProvisioning(mac);

            byte[] beaconMac = null;
            string beaconRequestId = null;
            using (var beaconSeen = new ManualResetEventSlim())
            using (var podProvisioned = new ManualResetEventSlim())
            {
                byte[] podKey = null;
                provisioning.ConfigReceived += _ => { };
                provisioning.Provisioned += key =>
                {
                    podKey = key;
                    podProvisioned.Set();
                };

                // The console side: listens on UDP 53291 for RQST beacons; the
                // delegate fires on vPOD's first beacon (sent at Start).
                PodConfigurationServer consoleServer;
                try
                {
                    consoleServer = new PodConfigurationServer(53291, 53292, (m, id) =>
                    {
                        beaconMac = m;
                        beaconRequestId = id;
                        beaconSeen.Set();
                    });
                }
                catch (System.Net.Sockets.SocketException)
                {
                    // UDP 53291 already bound — a real TeslaConsole is running on
                    // this machine. The protocol ports are fixed, so the test can't
                    // run; treat as inconclusive rather than failing the suite.
                    return;
                }

                try
                {
                    provisioning.Start();
                    Assert.True(beaconSeen.Wait(TimeSpan.FromSeconds(15)),
                        "console never received vPOD's RQST beacon");
                    Assert.Equal(mac, beaconMac);
                    Assert.Equal(provisioning.RequestId, beaconRequestId);

                    // The console side of Configure: broadcast the AES-encrypted
                    // network config and run the RSA key exchange against the pod.
                    byte[] consoleKey = consoleServer.SendEncryptionKey(
                        provisioning.Passphrase,
                        IPAddress.Loopback,
                        IPAddress.Parse("255.255.255.0"),
                        IPAddress.Any,
                        IPAddress.Any,
                        "vpod-test",
                        TimeSpan.FromSeconds(30));

                    Assert.True(podProvisioned.Wait(TimeSpan.FromSeconds(15)),
                        "vPOD never completed provisioning");
                    Assert.NotNull(consoleKey);
                    Assert.Equal(32, consoleKey.Length);
                    Assert.Equal(consoleKey, podKey);
                }
                finally
                {
                    provisioning.Stop();
                }
            }
        }
    }
}
