using NUnit.Framework;
using Moq;
using System.Collections.Generic;
using StructureHelperCommon.Models;
using StructureHelperLogics.Models.Primitives;
using StructureHelperLogics.NdmCalculations.Primitives.Logics;
using StructureHelperLogics.NdmCalculations.Primitives;
using StructureHelperCommon.Infrastructures.Interfaces;
using StructureHelper.Models.Materials;


namespace StructureHelperTests.UnitTests.Ndms
{
    [TestFixture]
    public class CheckPrimitiveCollectionLogicTests
    {
        private Mock<IShiftTraceLogger> _mockTraceLogger;
        private Mock<ICheckEntityLogic<IRebarNdmPrimitive>> _mockCheckRebarPrimitiveLogic;
        private Mock<IHasPrimitives> _mockHasPrimitives;
        private Mock<HasPrimitivesCheckLogic> _mockCheckPrimitiveCollectionLogic;

        [SetUp]
        public void SetUp()
        {
            _mockTraceLogger = new Mock<IShiftTraceLogger>();
            _mockCheckRebarPrimitiveLogic = new Mock<ICheckEntityLogic<IRebarNdmPrimitive>>();
            _mockHasPrimitives = new Mock<IHasPrimitives>();

            _mockCheckPrimitiveCollectionLogic = new Mock<HasPrimitivesCheckLogic>(_mockTraceLogger.Object, _mockCheckRebarPrimitiveLogic.Object)
            {
                CallBase = true
            };

            _mockCheckPrimitiveCollectionLogic.Object.Entity = _mockHasPrimitives.Object;
        }

        [Test]
        public void Check_PrimitivesIsNullOrEmpty_ReturnsFalseAndLogsError()
        {
            // Arrange
            _mockHasPrimitives.Setup(x => x.Primitives).Returns((List<INdmPrimitive>)null);

            // Act
            var result = _mockCheckPrimitiveCollectionLogic.Object.Check();

            // Assert
            Assert.That(result, Is.False);
            Assert.That(_mockCheckPrimitiveCollectionLogic.Object.CheckResult, Is.EqualTo("Calculator does not contain any primitives\n"));
            //_mockTraceLogger.Verify(x => x.AddMessage("Calculator does not contain any primitives\n", TraceLogStatuses.Error), Times.Once);
        }

        [Test]
        public void Check_RebarPrimitiveFailsCheck_ReturnsFalseAndAppendsCheckResult()
        {
            // Arrange
            var rebarMock = new Mock<IRebarNdmPrimitive>();
            var ndmElementMoq = new Mock<INdmElement>();
            var headMaterialMoq = new Mock<IHeadMaterial>();

            _mockHasPrimitives.Setup(x => x.Primitives).Returns(new List<INdmPrimitive> { rebarMock.Object });
            _mockCheckRebarPrimitiveLogic.Setup(x => x.Check()).Returns(false);
            _mockCheckRebarPrimitiveLogic.Setup(x => x.CheckResult).Returns("Rebar check failed\n");
            rebarMock.Setup(x => x.NdmElement).Returns(ndmElementMoq.Object);
            ndmElementMoq.Setup(x => x.HeadMaterial).Returns(headMaterialMoq.Object);

            // Act
            var result = _mockCheckPrimitiveCollectionLogic.Object.Check();

            // Assert
            Assert.That(result, Is.False);
            Assert.That(_mockCheckPrimitiveCollectionLogic.Object.CheckResult, Is.EqualTo("Rebar check failed\n"));
        }

        [Test]
        public void Check_RebarPrimitiveHasNoHostPrimitive_ReturnsFalseAndLogsError()
        {
            // Arrange
            var rebarMock = new Mock<IRebarNdmPrimitive>();
            var hostPrimitiveMock = new Mock<INdmPrimitive>();
            var ndmElementMoq = new Mock<INdmElement>();
            var headMaterialMoq = new Mock<IHeadMaterial>();

            rebarMock.Setup(x => x.HostPrimitive).Returns(hostPrimitiveMock.Object);
            rebarMock.Setup(x => x.Name).Returns("RebarName");
            hostPrimitiveMock.Setup(x => x.Name).Returns("HostPrimitiveName");
            rebarMock.Setup(x => x.NdmElement).Returns(ndmElementMoq.Object);
            ndmElementMoq.Setup(x => x.HeadMaterial).Returns(headMaterialMoq.Object);

            _mockHasPrimitives.Setup(x => x.Primitives).Returns(new List<INdmPrimitive> { rebarMock.Object });
            _mockCheckRebarPrimitiveLogic.Setup(x => x.Check()).Returns(true);  // Assume rebar check passes

            // Act
            var result = _mockCheckPrimitiveCollectionLogic.Object.Check();

            // Assert
            Assert.That(result, Is.False);
            Assert.That(_mockCheckPrimitiveCollectionLogic.Object.CheckResult, Is.EqualTo("Host RebarName (HostPrimitiveName) is not included in primitives\n"));
            //_mockTraceLogger.Verify(x => x.AddMessage("Host RebarName (HostPrimitiveName) is not included in primitives\n", TraceLogStatuses.Error), Times.Once);
        }

        [Test]
        public void Check_AllPrimitivesValid_ReturnsTrue()
        {
            // Arrange
            var rebarMock = new Mock<IRebarNdmPrimitive>();
            var ndmElementMoq = new Mock<INdmElement>();
            var headMaterialMoq = new Mock<IHeadMaterial>();
            var hostPrimitiveMock = new Mock<INdmPrimitive>();

            rebarMock.Setup(x => x.HostPrimitive).Returns(hostPrimitiveMock.Object);
            rebarMock.Setup(x => x.Name).Returns("RebarName");
            rebarMock.Setup(x => x.NdmElement).Returns(ndmElementMoq.Object);
            ndmElementMoq.Setup(x => x.HeadMaterial).Returns(headMaterialMoq.Object);
            hostPrimitiveMock.Setup(x => x.NdmElement).Returns(ndmElementMoq.Object);
            

            _mockHasPrimitives.Setup(x => x.Primitives).Returns(new List<INdmPrimitive> { rebarMock.Object, hostPrimitiveMock.Object });
            _mockCheckRebarPrimitiveLogic.Setup(x => x.Check()).Returns(true);

            // Act
            var result = _mockCheckPrimitiveCollectionLogic.Object.Check();

            // Assert
            Assert.That(result, Is.True);
            Assert.That(_mockCheckPrimitiveCollectionLogic.Object.CheckResult, Is.EqualTo(string.Empty));
        }
    }
}
