using System;
using NUnit.Framework;
using NcProgramManager.Cnc.Models;
using NcProgramManager.Cnc.Siemens;
using NcProgramManager.Tests.Integration.Stubs;

namespace NcProgramManager.Tests.Integration
{
    [TestFixture]
    [Category("Integration")]
    public class SiemensMachineIntegrationTests
    {
        private FtpServerStub _stub;
        private SiemensMachine _machine;
        private const string ProgramDir = "/_N_MPF_DIR/";

        [SetUp]
        public void SetUp()
        {
            _stub = new FtpServerStub();
            var config = new SiemensConnectionConfig
            {
                Name = "SiemensIntegration",
                IpAddress = "127.0.0.1",
                Port = _stub.Port,
                Username = "user",
                Password = "pass",
                ProgramDirectory = ProgramDir,
                RequestTimeout = TimeSpan.FromSeconds(5)
            };
            _machine = new SiemensMachine(config);
        }

        [TearDown]
        public void TearDown()
        {
            _machine?.Dispose();
            _stub?.Dispose();
        }

        [Test]
        public void ConnectAsync_StubListens_ResultOk()
        {
            var result = _machine.ConnectAsync().GetAwaiter().GetResult();

            Assert.That(result.Success, Is.True);
            Assert.That(_machine.State, Is.EqualTo(ConnectionState.Connected));
        }

        [Test]
        public void WriteThenRead_ProgramRoundTrips()
        {
            _machine.ConnectAsync().GetAwaiter().GetResult();
            // Siemens: name must end with .MPF; no semicolons; no lowercase
            string content = "G0 X0 Y0\nM30";
            var prog = new CncProgram { Name = "O1234.MPF", Content = content };

            var writeResult = _machine.WriteProgramAsync(ProgramDir, prog).GetAwaiter().GetResult();
            Assert.That(writeResult.Success, Is.True);

            // Determine where SiemensMachine stored the file
            string storedPath = ProgramDir + "O1234.MPF";
            var readResult = _machine.ReadProgramAsync(storedPath).GetAwaiter().GetResult();

            Assert.That(readResult.Success, Is.True);
            Assert.That(readResult.Value, Is.EqualTo(content));
        }

        [Test]
        public void DeleteProgramAsync_FileExistsInStub_RemovedFromStub()
        {
            _machine.ConnectAsync().GetAwaiter().GetResult();
            string path = ProgramDir + "O5678.MPF";
            _stub.Files[path] = "SOME_CONTENT";

            var result = _machine.DeleteProgramAsync(path).GetAwaiter().GetResult();

            Assert.That(result.Success, Is.True);
            Assert.That(_stub.Files.ContainsKey(path), Is.False);
        }

        [Test]
        public void ReadProgramAsync_FileNotInStub_ResultFail()
        {
            _machine.ConnectAsync().GetAwaiter().GetResult();

            var result = _machine.ReadProgramAsync(ProgramDir + "DOESNOTEXIST.MPF").GetAwaiter().GetResult();

            Assert.That(result.Success, Is.False);
        }

        [Test]
        public void WriteProgramAsync_InvalidName_ValidationFails()
        {
            _machine.ConnectAsync().GetAwaiter().GetResult();
            // Siemens requires .MPF extension — validator rejects before any FTP call
            var prog = new CncProgram { Name = "INVALID", Content = "G00 X10\nM30" };

            var result = _machine.WriteProgramAsync(ProgramDir, prog).GetAwaiter().GetResult();

            Assert.That(result.Success, Is.False);
        }

        [Test]
        [Category("Hardware")]
        public void Hardware_ConnectAsync_RealMachine()
        {
            string ip = HardwareTestHelper.GetIpOrSkip("SIEMENS_IP");
            var config = new SiemensConnectionConfig
            {
                Name             = "SiemensHardware",
                IpAddress        = ip,
                Port             = 21,
                Username         = Environment.GetEnvironmentVariable("SIEMENS_USER") ?? "user",
                Password         = Environment.GetEnvironmentVariable("SIEMENS_PASS") ?? "pass",
                ProgramDirectory = "/_N_MPF_DIR/",
                RequestTimeout   = TimeSpan.FromSeconds(10)
            };
            using (var machine = new SiemensMachine(config))
            {
                var result = machine.ConnectAsync().GetAwaiter().GetResult();
                Assert.That(result.Success, Is.True, "ConnectAsync failed: " + string.Join("; ", result.Errors));
            }
        }
    }
}
