using LittleShop.DTOs;
using LittleShop.Enums;
using LittleShop.Models;
using System;
using System.Collections.Generic;

namespace LittleShop.Tests.TestUtilities;

public static class TestDataBuilder
{
    public static Category CreateCategory(string? name = null, bool isActive = true)
    {
        return new Category
        {
            Id = Guid.NewGuid(),
            Name = name ?? $"Category-{Guid.NewGuid()}",
            Description = "Test category description",
            IsActive = isActive,
            CreatedAt = DateTime.UtcNow,
            UpdatedAt = DateTime.UtcNow
        };
    }

    public static Product CreateProduct(Guid? categoryId = null, string? name = null, decimal? price = null, bool isActive = true)
    {
        return new Product
        {
            Id = Guid.NewGuid(),
            Name = name ?? $"Product-{Guid.NewGuid()}",
            Description = "Test product description",
            Price = price ?? 99.99m,
            CategoryId = categoryId ?? Guid.NewGuid(),
            IsActive = isActive,
            Weight = 1.5m,
            WeightUnit = ProductWeightUnit.Kilograms,
            CreatedAt = DateTime.UtcNow,
            UpdatedAt = DateTime.UtcNow
        };
    }

    public static Order CreateOrder(string? identityReference = null, OrderStatus status = OrderStatus.PendingPayment)
    {
        var reference = identityReference ?? $"identity-{Guid.NewGuid()}";
        return new Order
        {
            Id = Guid.NewGuid(),
            IdentityReference = reference,
            Status = status,
            ShippingName = "Test Customer",
            ShippingAddress = "123 Test Street",
            ShippingCity = "Test City",
            ShippingPostCode = "TE5 7CD",
            ShippingCountry = "United Kingdom",
            TotalAmount = 199.99m,
            CreatedAt = DateTime.UtcNow,
            UpdatedAt = DateTime.UtcNow,
            Items = new List<OrderItem>()
        };
    }

    public static OrderItem CreateOrderItem(Guid orderId, Guid productId, int quantity = 1, decimal price = 99.99m)
    {
        return new OrderItem
        {
            Id = Guid.NewGuid(),
            OrderId = orderId,
            ProductId = productId,
            Quantity = quantity,
            UnitPrice = price,
            TotalPrice = price * quantity
        };
    }

    public static User CreateUser(string? username = null, string role = "User")
    {
        var user = username ?? $"user-{Guid.NewGuid()}";
        return new User
        {
            Id = Guid.NewGuid(),
            Username = user,
            PasswordHash = "hashed-password",
            IsActive = true,
            CreatedAt = DateTime.UtcNow
        };
    }

    public static CryptoPayment CreateCryptoPayment(Guid orderId, CryptoCurrency currency = CryptoCurrency.BTC, PaymentStatus status = PaymentStatus.Pending)
    {
        return new CryptoPayment
        {
            Id = Guid.NewGuid(),
            OrderId = orderId,
            Currency = currency,
            RequiredAmount = 0.0025m,
            WalletAddress = $"bc1q{Guid.NewGuid().ToString().Replace("-", "").Substring(0, 39)}",
            Status = status,
            CreatedAt = DateTime.UtcNow,
            ExpiresAt = DateTime.UtcNow.AddHours(1)
        };
    }

    public static CreateOrderDto CreateOrderDto(List<Guid>? productIds = null)
    {
        var items = new List<CreateOrderItemDto>();
        
        if (productIds != null)
        {
            foreach (var productId in productIds)
            {
                items.Add(new CreateOrderItemDto 
                { 
                    ProductId = productId, 
                    Quantity = 1 
                });
            }
        }
        else
        {
            items.Add(new CreateOrderItemDto 
            { 
                ProductId = Guid.NewGuid(), 
                Quantity = 1 
            });
        }

        return new CreateOrderDto
        {
            IdentityReference = $"test-identity-{Guid.NewGuid()}",
            ShippingName = "Test Customer",
            ShippingAddress = "123 Test Street",
            ShippingCity = "Test City",
            ShippingPostCode = "TE5 7CD",
            ShippingCountry = "United Kingdom",
            Items = items
        };
    }

    public static CreateProductDto CreateProductDto(Guid? categoryId = null)
    {
        return new CreateProductDto
        {
            Name = $"Product-{Guid.NewGuid()}",
            Description = "Test product description",
            Price = 99.99m,
            CategoryId = categoryId ?? Guid.NewGuid(),
            Weight = 1.5m,
            WeightUnit = ProductWeightUnit.Kilograms
        };
    }

    public static CreateCategoryDto CreateCategoryDto()
    {
        return new CreateCategoryDto
        {
            Name = $"Category-{Guid.NewGuid()}",
            Description = "Test category description"
        };
    }

    public static ProductPhoto CreateProductPhoto(Guid productId, int sortOrder = 1)
    {
        var fileName = $"{Guid.NewGuid()}.jpg";
        return new ProductPhoto
        {
            Id = Guid.NewGuid(),
            ProductId = productId,
            FileName = fileName,
            FilePath = $"/uploads/products/{fileName}",
            AltText = "Test product photo",
            SortOrder = sortOrder,
            CreatedAt = DateTime.UtcNow
        };
    }

    // Builder class for complex test scenarios
    public class OrderBuilder
    {
        private Order _order;
        private List<Product> _products = new();

        public OrderBuilder()
        {
            _order = CreateOrder();
        }

        public OrderBuilder WithStatus(OrderStatus status)
        {
            _order.Status = status;
            return this;
        }

        public OrderBuilder WithIdentity(string identityReference)
        {
            _order.IdentityReference = identityReference;
            return this;
        }

        public OrderBuilder WithShipping(string name, string address, string city, string postCode, string country)
        {
            _order.ShippingName = name;
            _order.ShippingAddress = address;
            _order.ShippingCity = city;
            _order.ShippingPostCode = postCode;
            _order.ShippingCountry = country;
            return this;
        }

        public OrderBuilder AddItem(Product product, int quantity)
        {
            _products.Add(product);
            var item = CreateOrderItem(_order.Id, product.Id, quantity, product.Price);
            _order.Items.Add(item);
            _order.TotalAmount = _order.Items.Sum(i => i.TotalPrice);
            return this;
        }

        public OrderBuilder WithPayment(CryptoCurrency currency, PaymentStatus status)
        {
            var payment = CreateCryptoPayment(_order.Id, currency, status);
            _order.Payments ??= new List<CryptoPayment>();
            _order.Payments.Add(payment);
            return this;
        }

        public Order Build()
        {
            return _order;
        }

        public (Order order, List<Product> products) BuildWithProducts()
        {
            return (_order, _products);
        }
    }

    // Bulk data generation for stress testing
    public static class BulkDataGenerator
    {
        public static List<Category> GenerateCategories(int count)
        {
            var categories = new List<Category>();
            for (int i = 0; i < count; i++)
            {
                categories.Add(CreateCategory($"Category {i + 1}"));
            }
            return categories;
        }

        public static List<Product> GenerateProducts(List<Category> categories, int productsPerCategory)
        {
            var products = new List<Product>();
            foreach (var category in categories)
            {
                for (int i = 0; i < productsPerCategory; i++)
                {
                    products.Add(CreateProduct(
                        category.Id, 
                        $"{category.Name} - Product {i + 1}",
                        Random.Shared.Next(10, 1000)));
                }
            }
            return products;
        }

        public static List<Order> GenerateOrders(int count, List<Product> availableProducts)
        {
            var orders = new List<Order>();
            var statuses = Enum.GetValues<OrderStatus>();
            
            for (int i = 0; i < count; i++)
            {
                var builder = new OrderBuilder()
                    .WithIdentity($"customer-{i}")
                    .WithStatus(statuses[Random.Shared.Next(statuses.Length)]);

                // Add random products to order
                var productCount = Random.Shared.Next(1, Math.Min(5, availableProducts.Count));
                var selectedProducts = availableProducts
                    .OrderBy(x => Random.Shared.Next())
                    .Take(productCount);

                foreach (var product in selectedProducts)
                {
                    builder.AddItem(product, Random.Shared.Next(1, 3));
                }

                orders.Add(builder.Build());
            }
            
            return orders;
        }
    }
}