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

namespace NcProgramManager.Tests.Integration
{
    [TestFixture]
    [Category("Integration")]
    public class HeidenhainMachineIntegrationTests
    {
        private Lsv2ServerStub _stub;
        private HeidenhainMachine _machine;

        [SetUp]
        public void SetUp()
        {
            _stub = new Lsv2ServerStub();
            var config = new HeidenhainConnectionConfig
            {
                Name = "HeidenhainIntegration",
                IpAddress = "127.0.0.1",
                Port = _stub.Port,
                Username = "user",
                Password = "pass",
                ConnectTimeout = TimeSpan.FromSeconds(5)
            };
            _machine = new HeidenhainMachine(config);
        }

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

        [Test]
        public void ConnectAsync_StubHandlesLoginHandshake_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();
            // Heidenhain: name must end with .H; no % or ; forbidden chars; no lowercase; no O#### required
            string content = "L X+0 Y+0 R0 FMAX\nM30";
            var prog = new CncProgram { Name = "O1234.H", Content = content };
            string folder = "TNC:/nc_prog/";

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

            // HeidenhainMachine appends .H only if name has no extension — name already has .H
            string storedPath = folder + "O1234.H";
            Assert.That(_stub.Files.ContainsKey(storedPath), Is.True,
                "File should be in stub at " + storedPath);

            var readResult = _machine.ReadProgramAsync(storedPath).GetAwaiter().GetResult();
            Assert.That(readResult.Success, Is.True);
            Assert.That(readResult.Value, Is.EqualTo(content));
        }

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

            var result = _machine.ReadProgramAsync("TNC:/nc_prog/DOESNOTEXIST.H").GetAwaiter().GetResult();

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

        [Test]
        [Category("Hardware")]
        public void Hardware_ConnectAsync_RealMachine()
        {
            string ip = HardwareTestHelper.GetIpOrSkip("HEIDENHAIN_IP");
            var config = new HeidenhainConnectionConfig
            {
                Name          = "HeidenhainHardware",
                IpAddress     = ip,
                Port          = 19000,
                Username      = Environment.GetEnvironmentVariable("HEIDENHAIN_USER") ?? "user",
                Password      = Environment.GetEnvironmentVariable("HEIDENHAIN_PASS") ?? "pass",
                ConnectTimeout = TimeSpan.FromSeconds(10)
            };
            using (var machine = new HeidenhainMachine(config))
            {
                var result = machine.ConnectAsync().GetAwaiter().GetResult();
                Assert.That(result.Success, Is.True, "ConnectAsync failed: " + string.Join("; ", result.Errors));
            }
        }
    }
}
