/**
 * @description Test data factory for B2B Commerce components
 * Provides utility methods to create consistent test data for B2B functionality
 * @author Senior Developer, NULogic
 * @version 1.0
 */
@isTest
public class B2BComponentTestHelper {

    /**
     * Create a test WebStore for B2B Commerce
     */
    public static WebStore createTestWebStore() {
        WebStore store = new WebStore();
        store.Name = 'Test B2B Store';
        store.ExternalReference = 'test-store-' + System.now().getTime();
        store.Type = 'B2B';
        insert store;
        return store;
    }

    /**
     * Create a test BuyerAccount
     */
    public static BuyerAccount createTestBuyerAccount(Account account) {
        BuyerAccount buyerAccount = new BuyerAccount();
        buyerAccount.BuyerId = account.Id;
        buyerAccount.Name = 'Test Buyer - ' + account.Name;
        buyerAccount.IsActive = true;
        insert buyerAccount;
        return buyerAccount;
    }

    /**
     * Create a test BuyerGroup for account grouping
     */
    public static BuyerGroup createTestBuyerGroup() {
        BuyerGroup group = new BuyerGroup();
        group.Name = 'Test Buyer Group';
        group.Description = 'Test buyer group for migrations';
        insert group;
        return group;
    }

    /**
     * Create a test BuyerGroupPricebook association
     */
    public static BuyerGroupPricebook createTestBuyerGroupPricebook(BuyerGroup group, Pricebook2 pricebook) {
        BuyerGroupPricebook bgp = new BuyerGroupPricebook();
        bgp.BuyerGroupId = group.Id;
        bgp.Pricebook2Id = pricebook.Id;
        insert bgp;
        return bgp;
    }

    /**
     * Create test products with pricing
     */
    public static List<Product2> createTestProducts(Integer count) {
        List<Product2> products = new List<Product2>();

        for (Integer i = 0; i < count; i++) {
            Product2 product = new Product2();
            product.Name = 'Test Product ' + i;
            product.ProductCode = 'TEST-PROD-' + i;
            product.Description = 'Test product for B2B Commerce ' + i;
            product.Family = 'Test Family';
            product.IsActive = true;
            products.add(product);
        }

        insert products;
        return products;
    }

    /**
     * Create pricebook entries for products
     */
    public static List<PricebookEntry> createPricebookEntries(List<Product2> products, Pricebook2 pricebook) {
        List<PricebookEntry> entries = new List<PricebookEntry>();
        Pricebook2 standardPb = [SELECT Id FROM Pricebook2 WHERE IsStandard = true LIMIT 1];

        // First create entries in standard pricebook
        List<PricebookEntry> standardEntries = new List<PricebookEntry>();
        for (Product2 product : products) {
            PricebookEntry entry = new PricebookEntry();
            entry.Product2Id = product.Id;
            entry.Pricebook2Id = standardPb.Id;
            entry.UnitPrice = 99.99;
            entry.IsActive = true;
            standardEntries.add(entry);
        }
        insert standardEntries;

        // Then create entries in custom pricebook
        for (Integer i = 0; i < products.size(); i++) {
            PricebookEntry entry = new PricebookEntry();
            entry.Product2Id = products[i].Id;
            entry.Pricebook2Id = pricebook.Id;
            entry.UnitPrice = 79.99 + (i * 10);
            entry.IsActive = true;
            entries.add(entry);
        }

        insert entries;
        return entries;
    }

    /**
     * Create a test WebCart
     */
    public static WebCart createTestWebCart(WebStore store, BuyerAccount buyerAccount) {
        WebCart cart = new WebCart();
        cart.WebStoreId = store.Id;
        cart.AccountId = buyerAccount.BuyerId;
        cart.OwnerId = buyerAccount.BuyerId;
        cart.Name = 'Test Cart';
        cart.Type = 'Cart';
        insert cart;
        return cart;
    }

    /**
     * Create test cart items
     */
    public static List<CartItem> createTestCartItems(WebCart cart, List<Product2> products,
                                                      Pricebook2 pricebook) {
        List<CartItem> cartItems = new List<CartItem>();
        List<PricebookEntry> entries = [
            SELECT Id, Product2Id, UnitPrice
            FROM PricebookEntry
            WHERE Pricebook2Id = :pricebook.Id
            AND Product2Id IN :products
        ];

        Map<Id, PricebookEntry> entryMap = new Map<Id, PricebookEntry>();
        for (PricebookEntry entry : entries) {
            entryMap.put(entry.Product2Id, entry);
        }

        for (Integer i = 0; i < products.size(); i++) {
            CartItem item = new CartItem();
            item.CartId = cart.Id;
            item.Product2Id = products[i].Id;
            item.Quantity = (i + 1) * 2;
            item.Type = 'Product';

            PricebookEntry entry = entryMap.get(products[i].Id);
            if (entry != null) {
                item.SalesPrice = entry.UnitPrice;
            }

            cartItems.add(item);
        }

        insert cartItems;
        return cartItems;
    }

    /**
     * Create test orders with complete hierarchy
     */
    public static Order createTestOrder(Account account, List<Product2> products) {
        Order order = new Order();
        order.AccountId = account.Id;
        order.EffectiveDate = System.today();
        order.Status = 'Draft';
        order.Amount = 5000;
        insert order;

        // Create order items
        Pricebook2 standardPb = [SELECT Id FROM Pricebook2 WHERE IsStandard = true LIMIT 1];
        List<PricebookEntry> entries = [
            SELECT Id, Product2Id, UnitPrice
            FROM PricebookEntry
            WHERE Pricebook2Id = :standardPb.Id
            AND Product2Id IN :products
            LIMIT 10
        ];

        List<OrderItem> orderItems = new List<OrderItem>();
        for (Integer i = 0; i < entries.size(); i++) {
            OrderItem item = new OrderItem();
            item.OrderId = order.Id;
            item.PricebookEntryId = entries[i].Id;
            item.Quantity = 5;
            item.UnitPrice = entries[i].UnitPrice;
            orderItems.add(item);
        }

        if (!orderItems.isEmpty()) {
            insert orderItems;
        }

        // Create delivery group
        OrderDeliveryGroup deliveryGroup = new OrderDeliveryGroup();
        deliveryGroup.OrderId = order.Id;
        deliveryGroup.DeliverToStreet = '123 Main Street';
        deliveryGroup.DeliverToCity = 'Denver';
        deliveryGroup.DeliverToState = 'Colorado';
        deliveryGroup.DeliverToCountry = 'USA';
        deliveryGroup.DeliverToPostalCode = '80202';
        deliveryGroup.DesiredDeliveryDate = System.today().addDays(5);
        insert deliveryGroup;

        return order;
    }

    /**
     * Create test account with contacts
     */
    public static Account createTestAccount() {
        Account account = new Account();
        account.Name = 'Test B2B Account';
        account.Industry = 'Technology';
        account.BillingStreet = '123 Commerce Drive';
        account.BillingCity = 'Denver';
        account.BillingState = 'Colorado';
        account.BillingPostalCode = '80202';
        account.BillingCountry = 'USA';
        insert account;

        // Create contact
        Contact contact = new Contact();
        contact.AccountId = account.Id;
        contact.FirstName = 'John';
        contact.LastName = 'Buyer';
        contact.Email = 'john.buyer@example.com';
        contact.Phone = '303-555-0100';
        insert contact;

        return account;
    }

    /**
     * Create test user for buyer portal
     */
    public static User createTestBuyerUser(Account account) {
        // Get a standard community license profile
        Profile communityProfile = [
            SELECT Id FROM Profile
            WHERE Name LIKE '%Customer%' OR Name LIKE '%Community%'
            LIMIT 1
        ];

        User buyerUser = new User();
        buyerUser.FirstName = 'Test';
        buyerUser.LastName = 'Buyer';
        buyerUser.Email = 'test.buyer.' + System.now().getTime() + '@example.com';
        buyerUser.Username = 'testbuyer.' + System.now().getTime() + '@b2btest.com';
        buyerUser.ProfileId = communityProfile.Id;
        buyerUser.TimeZoneSidKey = 'America/Denver';
        buyerUser.LocaleSidKey = 'en_US';
        buyerUser.EmailEncodingKey = 'UTF-8';
        buyerUser.LanguageLocaleKey = 'en_US';

        insert buyerUser;
        return buyerUser;
    }

    /**
     * Create a complete B2B commerce setup
     */
    public static B2BTestSetup createCompleteB2BSetup(Integer productCount) {
        B2BTestSetup setup = new B2BTestSetup();

        // Create store
        setup.webStore = createTestWebStore();

        // Create account and buyer account
        setup.account = createTestAccount();
        setup.buyerAccount = createTestBuyerAccount(setup.account);

        // Create buyer group and pricebook
        setup.buyerGroup = createTestBuyerGroup();
        setup.pricebook = new Pricebook2();
        setup.pricebook.Name = 'Test Custom Pricebook';
        setup.pricebook.IsActive = true;
        insert setup.pricebook;

        setup.buyerGroupPricebook = createTestBuyerGroupPricebook(setup.buyerGroup, setup.pricebook);

        // Create products and pricing
        setup.products = createTestProducts(productCount);
        setup.pricebookEntries = createPricebookEntries(setup.products, setup.pricebook);

        // Create cart
        setup.webCart = createTestWebCart(setup.webStore, setup.buyerAccount);
        setup.cartItems = createTestCartItems(setup.webCart, setup.products, setup.pricebook);

        // Create order
        setup.order = createTestOrder(setup.account, setup.products);

        // Create buyer user
        setup.buyerUser = createTestBuyerUser(setup.account);

        return setup;
    }

    /**
     * Assert that a cart has expected number of items
     */
    public static void assertCartItemCount(Id cartId, Integer expectedCount) {
        List<CartItem> items = [SELECT Id FROM CartItem WHERE CartId = :cartId];
        System.assertEquals(expectedCount, items.size(), 'Cart should have ' + expectedCount + ' items');
    }

    /**
     * Assert that an order has expected number of items
     */
    public static void assertOrderItemCount(Id orderId, Integer expectedCount) {
        List<OrderItem> items = [SELECT Id FROM OrderItem WHERE OrderId = :orderId];
        System.assertEquals(expectedCount, items.size(), 'Order should have ' + expectedCount + ' items');
    }

    /**
     * Assert that pricing is applied correctly
     */
    public static void assertPricingApplied(Id pricebookId) {
        List<PricebookEntry> entries = [
            SELECT Id, UnitPrice FROM PricebookEntry
            WHERE Pricebook2Id = :pricebookId
        ];
        System.assert(!entries.isEmpty(), 'Pricebook should have entries');

        for (PricebookEntry entry : entries) {
            System.assertNotEquals(null, entry.UnitPrice, 'Entry should have unit price');
        }
    }

    /**
     * Wrapper class for B2B test setup
     */
    public class B2BTestSetup {
        public WebStore webStore;
        public Account account;
        public BuyerAccount buyerAccount;
        public BuyerGroup buyerGroup;
        public Pricebook2 pricebook;
        public BuyerGroupPricebook buyerGroupPricebook;
        public List<Product2> products;
        public List<PricebookEntry> pricebookEntries;
        public WebCart webCart;
        public List<CartItem> cartItems;
        public Order order;
        public User buyerUser;
    }
}
