using System;
using NUnit.Framework;
using NcProgramManager.Cnc;
using NcProgramManager.Cnc.Fanuc;
using NcProgramManager.Cnc.Heidenhain;
using NcProgramManager.Cnc.Mitsubishi;
using NcProgramManager.Cnc.Models;
using NcProgramManager.Cnc.Siemens;
using NcProgramManager.Cnc.Fagor;
using NcProgramManager.Cnc.Mazak;

namespace NcProgramManager.Tests.Unit
{
    [TestFixture]
    public class CncMachineFactoryTests
    {
        private static T GetRequiredField<T>(object target, string name)
        {
            var f = target.GetType().GetField(name,
                System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance)
                ?? throw new InvalidOperationException(
                    string.Format("Field '{0}' not found on {1}. Field may have been renamed.", name, target.GetType().Name));
            return (T)f.GetValue(target);
        }

        private InputArgs BaseArgs()
        {
            return new InputArgs
            {
                ip = "192.168.1.1",
                porta = "",
                username = "user",
                password = "pass",
                nodoHssb = -1
            };
        }

        [Test]
        public void Create_Fanuc_ReturnsFanucMachine()
        {
            var args = BaseArgs();
            args.manufacturer = CncManufacturer.Fanuc;

            using (var m = CncMachineFactory.Create(args))
            {
                Assert.That(m, Is.InstanceOf<FanucMachine>());
            }
        }

        [Test]
        public void Create_Heidenhain_ReturnsHeidenhainMachine()
        {
            var args = BaseArgs();
            args.manufacturer = CncManufacturer.Heidenhain;

            using (var m = CncMachineFactory.Create(args))
            {
                Assert.That(m, Is.InstanceOf<HeidenhainMachine>());
            }
        }

        [Test]
        public void Create_Siemens_ReturnsSiemensMachine()
        {
            var args = BaseArgs();
            args.manufacturer = CncManufacturer.Siemens;

            using (var m = CncMachineFactory.Create(args))
            {
                Assert.That(m, Is.InstanceOf<SiemensMachine>());
            }
        }

        [Test]
        public void Create_Mitsubishi_ReturnsMitsubishiMachine()
        {
            var args = BaseArgs();
            args.manufacturer = CncManufacturer.Mitsubishi;

            using (var m = CncMachineFactory.Create(args))
            {
                Assert.That(m, Is.InstanceOf<MitsubishiMachine>());
            }
        }

        [Test]
        public void Create_Fagor_ReturnsFagorMachine()
        {
            var args = BaseArgs();
            args.manufacturer = CncManufacturer.Fagor;

            using (var m = CncMachineFactory.Create(args))
            {
                Assert.That(m, Is.InstanceOf<FagorMachine>());
            }
        }

        [Test]
        public void Create_Mazak_ReturnsMazakMachine()
        {
            var args = BaseArgs();
            args.manufacturer = CncManufacturer.Mazak;

            using (var m = CncMachineFactory.Create(args))
            {
                Assert.That(m, Is.InstanceOf<MazakMachine>());
            }
        }

        [Test]
        public void Create_Mazak_PortOverride_23()
        {
            var args = BaseArgs();
            args.manufacturer = CncManufacturer.Mazak;
            args.porta = "23";

            using (var m = CncMachineFactory.Create(args) as MazakMachine)
            {
                var config = GetRequiredField<MazakConnectionConfig>(m, "_config");

                Assert.That(config.Port, Is.EqualTo(23));
            }
        }

        [Test]
        public void Create_FanucHssbNode_TransportIsHssb()
        {
            var args = BaseArgs();
            args.manufacturer = CncManufacturer.Fanuc;
            args.nodoHssb = 0;

            using (var m = CncMachineFactory.Create(args) as FanucMachine)
            {
                var config = GetRequiredField<FanucConnectionConfig>(m, "_config");

                Assert.That(config.Transport, Is.EqualTo(FanucTransport.Hssb));
            }
        }

        [Test]
        public void Create_FanucNoHssb_TransportIsEthernet()
        {
            var args = BaseArgs();
            args.manufacturer = CncManufacturer.Fanuc;
            args.nodoHssb = -1;

            using (var m = CncMachineFactory.Create(args) as FanucMachine)
            {
                var config = GetRequiredField<FanucConnectionConfig>(m, "_config");

                Assert.That(config.Transport, Is.EqualTo(FanucTransport.Ethernet));
            }
        }
    }
}
