using System;
using System.Linq;
using FluentAssertions;
using TeleBot.Models;
using Xunit;

namespace TeleBot.Tests.Models
{
    public class ShoppingCartTests
    {
        [Fact]
        public void NewCart_ShouldBeEmpty()
        {
            // Arrange & Act
            var cart = new ShoppingCart();

            // Assert
            cart.IsEmpty().Should().BeTrue();
            cart.GetTotalItems().Should().Be(0);
            cart.GetTotalAmount().Should().Be(0);
        }

        [Fact]
        public void AddItem_ShouldAddToCart()
        {
            // Arrange
            var cart = new ShoppingCart();
            var productId = Guid.NewGuid();

            // Act
            cart.AddItem(productId, "Test Product", 10.50m, 2);

            // Assert
            cart.IsEmpty().Should().BeFalse();
            cart.GetTotalItems().Should().Be(2);
            cart.GetTotalAmount().Should().Be(21.00m);
            cart.Items.Should().HaveCount(1);
            cart.Items.First().ProductName.Should().Be("Test Product");
        }

        [Fact]
        public void AddItem_SameProduct_ShouldIncreaseQuantity()
        {
            // Arrange
            var cart = new ShoppingCart();
            var productId = Guid.NewGuid();

            // Act
            cart.AddItem(productId, "Product A", 5.00m, 1);
            cart.AddItem(productId, "Product A", 5.00m, 2);

            // Assert
            cart.Items.Should().HaveCount(1);
            cart.Items.First().Quantity.Should().Be(3);
            cart.GetTotalAmount().Should().Be(15.00m);
        }

        [Fact]
        public void AddItem_DifferentProducts_ShouldAddSeparately()
        {
            // Arrange
            var cart = new ShoppingCart();
            var productId1 = Guid.NewGuid();
            var productId2 = Guid.NewGuid();

            // Act
            cart.AddItem(productId1, "Product A", 10.00m, 1);
            cart.AddItem(productId2, "Product B", 20.00m, 2);

            // Assert
            cart.Items.Should().HaveCount(2);
            cart.GetTotalItems().Should().Be(3);
            cart.GetTotalAmount().Should().Be(50.00m);
        }

        [Fact]
        public void RemoveItem_ShouldRemoveFromCart()
        {
            // Arrange
            var cart = new ShoppingCart();
            var productId = Guid.NewGuid();
            cart.AddItem(productId, "Test Product", 10.00m, 2);

            // Act
            cart.RemoveItem(productId);

            // Assert
            cart.IsEmpty().Should().BeTrue();
            cart.GetTotalItems().Should().Be(0);
        }

        [Fact]
        public void RemoveItem_NonExistent_ShouldNotThrow()
        {
            // Arrange
            var cart = new ShoppingCart();
            var productId = Guid.NewGuid();

            // Act & Assert
            var act = () => cart.RemoveItem(productId);
            act.Should().NotThrow();
        }

        [Fact]
        public void UpdateQuantity_ShouldUpdateExistingItem()
        {
            // Arrange
            var cart = new ShoppingCart();
            var productId = Guid.NewGuid();
            cart.AddItem(productId, "Test Product", 10.00m, 2);

            // Act
            cart.UpdateQuantity(productId, 5);

            // Assert
            cart.Items.First().Quantity.Should().Be(5);
            cart.GetTotalAmount().Should().Be(50.00m);
        }

        [Fact]
        public void UpdateQuantity_ToZero_ShouldRemoveItem()
        {
            // Arrange
            var cart = new ShoppingCart();
            var productId = Guid.NewGuid();
            cart.AddItem(productId, "Test Product", 10.00m, 2);

            // Act
            cart.UpdateQuantity(productId, 0);

            // Assert
            cart.IsEmpty().Should().BeTrue();
        }

        [Fact]
        public void UpdateQuantity_Negative_ShouldRemoveItem()
        {
            // Arrange
            var cart = new ShoppingCart();
            var productId = Guid.NewGuid();
            cart.AddItem(productId, "Test Product", 10.00m, 2);

            // Act
            cart.UpdateQuantity(productId, -1);

            // Assert
            cart.IsEmpty().Should().BeTrue();
        }

        [Fact]
        public void Clear_ShouldEmptyCart()
        {
            // Arrange
            var cart = new ShoppingCart();
            cart.AddItem(Guid.NewGuid(), "Product A", 10.00m, 2);
            cart.AddItem(Guid.NewGuid(), "Product B", 20.00m, 1);

            // Act
            cart.Clear();

            // Assert
            cart.IsEmpty().Should().BeTrue();
            cart.GetTotalItems().Should().Be(0);
            cart.GetTotalAmount().Should().Be(0);
        }

        [Fact]
        public void CartItem_UpdateTotalPrice_ShouldCalculateCorrectly()
        {
            // Arrange
            var item = new CartItem
            {
                UnitPrice = 15.50m,
                Quantity = 3
            };

            // Act
            item.UpdateTotalPrice();

            // Assert
            item.TotalPrice.Should().Be(46.50m);
        }

        [Fact]
        public void Cart_UpdatedAt_ShouldUpdateOnModification()
        {
            // Arrange
            var cart = new ShoppingCart();
            var originalTime = cart.UpdatedAt;
            System.Threading.Thread.Sleep(10);

            // Act
            cart.AddItem(Guid.NewGuid(), "Product", 10.00m, 1);

            // Assert
            cart.UpdatedAt.Should().BeAfter(originalTime);
        }

        [Theory]
        [InlineData(10.99, 1, 10.99)]
        [InlineData(5.50, 3, 16.50)]
        [InlineData(0.99, 100, 99.00)]
        [InlineData(123.45, 2, 246.90)]
        public void GetTotalAmount_ShouldCalculateCorrectly(decimal price, int quantity, decimal expectedTotal)
        {
            // Arrange
            var cart = new ShoppingCart();

            // Act
            cart.AddItem(Guid.NewGuid(), "Product", price, quantity);

            // Assert
            cart.GetTotalAmount().Should().Be(expectedTotal);
        }

        [Fact]
        public void ComplexCart_ShouldCalculateCorrectTotals()
        {
            // Arrange
            var cart = new ShoppingCart();
            
            // Act
            cart.AddItem(Guid.NewGuid(), "Laptop", 999.99m, 1);
            cart.AddItem(Guid.NewGuid(), "Mouse", 25.50m, 2);
            cart.AddItem(Guid.NewGuid(), "Keyboard", 75.00m, 1);
            cart.AddItem(Guid.NewGuid(), "Monitor", 350.00m, 2);

            // Assert
            cart.Items.Should().HaveCount(4);
            cart.GetTotalItems().Should().Be(6);
            cart.GetTotalAmount().Should().Be(1825.99m);
        }
    }
}