using NUnit.Framework;
using FluentAssertions;

using Encompass;
using System.Collections.Generic;
using System;

namespace Tests
{
    struct MockComponent : IComponent
    {
        public string myString;
        public int myInt;
    }

    public class EntityTest
    {
        [Test]
        public void AddComponent()
        {
            var worldBuilder = new WorldBuilder();
            var entity = worldBuilder.CreateEntity();

            MockComponent mockComponent;
            mockComponent.myInt = 3;
            mockComponent.myString = "hello";

            entity.AddComponent(mockComponent);

            var world = worldBuilder.Build();

            Assert.IsTrue(entity.HasComponent<MockComponent>());
            Assert.That(entity.GetComponent<MockComponent>().Value, Is.EqualTo(mockComponent));
        }

        [Test]
        public void GetComponents()
        {
            var worldBuilder = new WorldBuilder();
            var entity = worldBuilder.CreateEntity();

            MockComponent mockComponentA;
            mockComponentA.myInt = 3;
            mockComponentA.myString = "hello";

            MockComponent mockComponentB;
            mockComponentB.myInt = 5;
            mockComponentB.myString = "wassup";

            MockComponent mockComponentC;
            mockComponentC.myInt = 1;
            mockComponentC.myString = "howdy";

            var componentAID = entity.AddComponent(mockComponentA);
            var componentBID = entity.AddComponent(mockComponentB);
            var componentCID = entity.AddComponent(mockComponentC);

            var world = worldBuilder.Build();

            var components = entity.GetComponents<MockComponent>();
            components.Should().Contain(new KeyValuePair<Guid, MockComponent>(componentAID, mockComponentA));
            components.Should().Contain(new KeyValuePair<Guid, MockComponent>(componentBID, mockComponentB));
            components.Should().Contain(new KeyValuePair<Guid, MockComponent>(componentCID, mockComponentC));
        }

        [Test]
        public void GetComponent()
        {
            var worldBuilder = new WorldBuilder();
            var entity = worldBuilder.CreateEntity();

            MockComponent mockComponent;
            mockComponent.myInt = 3;
            mockComponent.myString = "hello";

            var componentID = entity.AddComponent<MockComponent>(mockComponent);

            var world = worldBuilder.Build();

            Assert.AreEqual(new KeyValuePair<Guid, MockComponent>(componentID, mockComponent), entity.GetComponent<MockComponent>());
        }

        [Test]
        public void HasComponent()
        {
            var worldBuilder = new WorldBuilder();
            var entity = worldBuilder.CreateEntity();

            MockComponent mockComponent;
            mockComponent.myInt = 3;
            mockComponent.myString = "hello";

            entity.AddComponent(mockComponent);

            var world = worldBuilder.Build();

            Assert.IsTrue(entity.HasComponent<MockComponent>());
        }

        [Test]
        public void HasComponentWhenInactive()
        {
            var worldBuilder = new WorldBuilder();
            var entity = worldBuilder.CreateEntity();
            
            MockComponent mockComponent;
            mockComponent.myInt = 3;
            mockComponent.myString = "hello";

            var componentID = entity.AddComponent(mockComponent);

            var world = worldBuilder.Build();

            entity.DeactivateComponent(componentID);

            world.Update(0.01f);

            Assert.IsFalse(entity.HasComponent<MockComponent>());
        }

        [Test]
        public void RemoveComponent()
        {
            var worldBuilder = new WorldBuilder();
            var entity = worldBuilder.CreateEntity();

            MockComponent mockComponent;
            mockComponent.myInt = 3;
            mockComponent.myString = "hello";

            var componentID = entity.AddComponent(mockComponent);

            var world = worldBuilder.Build();

            entity.RemoveComponent(componentID);

            world.Update(0.01f);

            Assert.IsFalse(entity.HasComponent<MockComponent>());
            Assert.IsEmpty(entity.GetComponents<MockComponent>());
        }

        [Test]
        public void ReactivateComponent()
        {
            var worldBuilder = new WorldBuilder();
            var entity = worldBuilder.CreateEntity();

            MockComponent mockComponent;
            mockComponent.myInt = 3;
            mockComponent.myString = "hello";

            var componentID = entity.AddComponent(mockComponent);

            var world = worldBuilder.Build();

            entity.DeactivateComponent(componentID);

            world.Update(0.01f);

            Assert.IsFalse(entity.HasComponent<MockComponent>());
            Assert.IsEmpty(entity.GetComponents<MockComponent>());

            entity.ActivateComponent(componentID);

            world.Update(0.01f);

            Assert.IsTrue(entity.HasComponent<MockComponent>());
            Assert.IsNotEmpty(entity.GetComponents<MockComponent>());
        }
    }
}