context: using System;
  using Hybrasyl;
  using Hybrasyl.Xml;
  using Hybrasyl.Objects;
  using System.Collections.Generic;
  using System.Linq;
  using Xunit;
  [assembly: CollectionBehavior(DisableTestParallelization = true)]
  
  namespace HybrasylTests
  {
      [Collection("Hybrasyl")]
      public class Inventory
      {
          private static HybrasylFixture Fixture;
  
          public Inventory(HybrasylFixture fixture)
          {
              Fixture = fixture;
          }
  
          public static IEnumerable<object[]> XmlItems()
          {
              yield return new object[] {Fixture.TestItem, Fixture.StackableTestItem};
  
          }
  
          public static IEnumerable<object[]> StackableXmlItems()
          {
              yield return new object[] {Fixture.StackableTestItem};
  
          }
  
          [Fact]
          public void NewInventorySizeIsCorrect()
          {
              var f = new Hybrasyl.Inventory(HybrasylFixture.InventorySize);
              Assert.Equal(HybrasylFixture.InventorySize, f.Size);
          }
  
          [Fact]
          public void NewInventoryEmptySlotsEqualsSize()
          {
              var f = new Hybrasyl.Inventory(HybrasylFixture.InventorySize);
              Assert.Equal(HybrasylFixture.InventorySize, f.EmptySlots);
          }
  
          [Fact]
          public void NewInventoryFirstEmptySlotIsOne()
          {
              var f = new Hybrasyl.Inventory(HybrasylFixture.InventorySize);
              Assert.Equal(1, f.FindEmptySlot());
          }
  
          [Fact]
          public void NewInventoryWeightIsZero()
          {
              var f = new Hybrasyl.Inventory(HybrasylFixture.InventorySize);
              Assert.Equal(0, f.Weight);
          }
  
          [Fact]
          public void NewInventoryIsNotFull()
          {
              var f = new Hybrasyl.Inventory(HybrasylFixture.InventorySize);
              Assert.False(f.IsFull, "new inventory should not be full");
          }
  
          [Fact]
          public void ClearInventory()
          {
              Fixture.TestUser.Inventory.Clear();
              Assert.True(Fixture.TestUser.Inventory.Count == 0, "Inventory cleared but count is non-zero");
              Assert.True(Fixture.TestUser.Inventory.ToList().Count == 0,
                  "Inventory cleared but enumerated count is non-zero");
              Assert.True(Fixture.TestUser.Inventory.Weight == 0, "Inventory cleared but weight is non-zero");
              Fixture.TestUser.Inventory.RecalculateWeight();
              Assert.True(Fixture.TestUser.Inventory.Weight == 0,
                  "Inventory cleared but weight is non-zero after recalculation");
          }
  
  
          [Theory]
          [MemberData(nameof(XmlItems))]
          public void AddRetrieveAndRemoveItems(params Item[] items)
          {
              Fixture.TestUser.Inventory.Clear();
  
              var numItems = 0;
              var startWeight = 0;
              var expectedWeight = 0;
              foreach (var i in items)
              {
                  Assert.True(expectedWeight == startWeight,
                      $"Weight calculation is incorrect (expected {expectedWeight}, got {startWeight}");
                  var itemObj = Game.World.CreateItem(i.Id);
                  Assert.True(Fixture.TestUser.AddItem(itemObj),
                      $"Item {itemObj.Name} could not be added to inventory");
                  expectedWeight += itemObj.Weight;
                  startWeight = expectedWeight;
                  Assert.True(Fixture.TestUser.Inventory.Weight == expectedWeight,
                      $"Item added to inventory: start weight {startWeight}, item weight {itemObj.Weight}, expected {expectedWeight}, weight is {Fixture.TestUser.Inventory.Weight}");
                  numItems++;
                  Assert.True(Fixture.TestUser.Inventory.TryGetValue(i.Id, out var invObj),
                      $"Inventory had {i.Name} added but is not found by template ID");
                  var objList = Fixture.TestUser.Inventory.TryGetValueByName(i.Name, out var invObjName);
                  Assert.True(objList, $"Inventory had {i.Name} added but TryGetValueByName fails");
                  Assert.Contains(invObjName, x => x.obj == itemObj);
                      //$"Inventory had {i.Name} but return list from TryGetValueByName does not contain it");
  
                  Assert.True(Fixture.TestUser.Inventory.Count == numItems,
                      $"Inventory has had {numItems} items added, but count ({Fixture.TestUser.Inventory.Count}) is not equivalent");
                  Assert.True(invObj.Name == i.Name,
                      $"TryGetValue: Inventory contains an item {invObj.Name} but it isn't the test item {i.Name}");
                  Assert.True(invObjName.Select(x => x.obj.Name == itemObj.Name).Count() == invObjName.Count,
                      $"TryGetValueByName: Inventory contains a singular item {itemObj.Name} but multiple items returned");
                  Assert.True(Fixture.TestUser.Inventory.ContainsId(i.Id),
                      $"Contains: Inventory should contain {i.Name} but returned false");
                  Assert.True(Fixture.TestUser.Inventory.ContainsName(i.Name),
                      "ContainsName: Inventory should contain {i.Name} but returned false");
              }
          }
  
          [Theory]
          [MemberData(nameof(XmlItems))]
          public void FindItemsByCategory(params Item[] items)
          {
              Fixture.TestUser.Inventory.Clear();
  
              foreach (var item in items)
              {
                  // Add five of each item to the inventory
                  Assert.True(Fixture.TestUser.AddItem(Game.World.CreateItem(item.Id)));
                  Assert.True(Fixture.TestUser.AddItem(Game.World.CreateItem(item.Id)));
                  Assert.True(Fixture.TestUser.AddItem(Game.World.CreateItem(item.Id)));
                  Assert.True(Fixture.TestUser.AddItem(Game.World.CreateItem(item.Id)));
                  Assert.True(Fixture.TestUser.AddItem(Game.World.CreateItem(item.Id)));
              }
              // All 10 slots contain xmlitem tagged items
              Assert.Equal(new List<byte> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 },
                  Fixture.TestUser.Inventory.GetSlotsByCategory("xmlitem"));
              // Assert first five slots contain junk
              Assert.Equal(new List<byte> {1, 2, 3, 4, 5},
                  Fixture.TestUser.Inventory.GetSlotsByCategory("junk"));
              // Next five slots should contain "stackable"
              Assert.Equal(new List<byte> { 6, 7, 8, 9, 10 },
                  Fixture.TestUser.Inventory.GetSlotsByCategory("stackable"));
              // Categories should be case insensitive
              Assert.Equal(new List<byte> { 6, 7, 8, 9, 10 },
                  Fixture.TestUser.Inventory.GetSlotsByCategory("StAcKaBlE"));
  
              // After a swap, GetSlotsByCategory should return correct results
              for (byte x = 6; x <= 10; x++)
              {
                  Assert.True(Fixture.TestUser.Inventory.Swap(x, (byte) (59 - x)));
              }
              Assert.Equal(new List<byte> { 53, 52, 51, 50, 49 },
                  Fixture.TestUser.Inventory.GetSlotsByCategory("stackable"));
  
  
          }
          [Theory]
          [MemberData(nameof(XmlItems))]
          public void AddItemsToInventory(params Item[] items)
          {
              Fixture.TestUser.Inventory.Clear();
  
              for (var x = 1; x < 6; x++)
              {
                  Fixture.TestUser.AddItem(Game.World.CreateItem(items[0].Id));
              }
  
              Assert.True(Fixture.TestUser.Inventory.Count == 5,
                  $"Inventory with five items should have count of 5, count is {Fixture.TestUser.Inventory.Count}");
              Assert.True(Fixture.TestUser.Inventory[1].Name == "Test Item",
                  "First slot: Inventory contains an item but it isn't a test item");
              Assert.True(Fixture.TestUser.Inventory[5].Name == "Test Item",
                  "Fifth slot: Inventory contains an item but it isn't a test item");
          }
  
          [Theory]
          [MemberData(nameof(XmlItems))]
          public void SwapItems(params Item[] items)
          {
              Fixture.TestUser.Inventory.Clear();
  
              foreach (var item in items)
              {
                  Assert.True(Fixture.TestUser.AddItem(Game.World.CreateItem(item.Id)));
                  Assert.True(Fixture.TestUser.AddItem(Game.World.CreateItem(item.Id)));
                  Assert.True(Fixture.TestUser.AddItem(Game.World.CreateItem(item.Id)));
                  Assert.True(Fixture.TestUser.AddItem(Game.World.CreateItem(item.Id)));
                  Assert.True(Fixture.TestUser.AddItem(Game.World.CreateItem(item.Id)));
              }
  
              for (byte x = 1; x <= 10; x++)
              {
                  Assert.True(Fixture.TestUser.Inventory[x] != null,
                      "SwapItems: slot {x} is null but should not be");
              }
              // Swap with inventory between two filled slots
              Fixture.TestUser.Inventory.Swap(1, 6);
              Assert.True(Fixture.TestUser.Inventory[1].Name == "Stackable Test Item");
              Assert.True(Fixture.TestUser.Inventory[6].Name == "Test Item");
  
              // Swap with inventory between a filled slot and an empty slot
              Fixture.TestUser.Inventory.Swap(2, 59);
              Assert.True(Fixture.TestUser.Inventory[2] is null);
              Assert.True(Fixture.TestUser.Inventory[59].Name == "Test Item");
  
              // Swap with user function between two filled slots
              Fixture.TestUser.SwapItem(3,7);
              Assert.True(Fixture.TestUser.Inventory[3].Name == "Stackable Test Item");
              Assert.True(Fixture.TestUser.Inventory[7].Name == "Test Item");
  
              // Swap with user function between a filled slot and an empty slot
              Fixture.TestUser.SwapItem(4, 58);
              Assert.True(Fixture.TestUser.Inventory[4] is null);
              Assert.True(Fixture.TestUser.Inventory[58].Name == "Test Item");
  
  
          }
  
  
          [Theory]
          [MemberData(nameof(XmlItems))]
          public void MoveItemBetweenSlotsInInventory(params Item[] item)
          {
              Fixture.TestUser.Inventory.Clear();
              Assert.True(Fixture.TestUser.AddItem(Game.World.CreateItem(item[0].Id)),
                  $"Adding item {item[0].Name} to inventory failed");
              Assert.True(Fixture.TestUser.Inventory.Count == 1,
                  "Inventory with one item should have count of 1");
              Assert.True(Fixture.TestUser.Inventory.Swap(1, 5),
                  "Swap {item[0].Name} from slot 1 to slot 5 failed");
              Assert.False(Fixture.TestUser.Inventory[5] == null, "Swap to slot 5 failed, slot 5 is null");
              Assert.True(Fixture.TestUser.Inventory[1] == null,
                  "Swap to slot 5 failed, slot 1 still contains an item");
              Assert.True(Fixture.TestUser.Inventory.Count == 1,
                  "Inventory with one item should have count of 1");
              Assert.True(Fixture.TestUser.Inventory[5].Name == "Test Item",
                  "Slot 5 contains an item but it isn't a test item");
              Assert.True(Fixture.TestUser.Inventory[4] == null,
  
gt:                 "Item fencepost error? Inventory slot 4 is not null");