import { test as base, expect } from '@playwright/test';
import { type ProductConfig, type ProductId, products, productPath } from '../config/products';
import { siteConfig } from '../config/siteConfig';
import { waitForHydration, navigateToPdp, findAddToCartButton, findActionButton, findProductOptions, selectOptionValue, waitForLoadingIndicators } from '../support/cart-helpers';

/**
 * Extended Playwright test with product catalog helpers.
 *
 * Usage:
 *   import { test, expect } from '../../fixtures/test-base';
 *   test('PAY-001 @payment: ...', async ({ page, product, goToProduct, addToCart }) => { ... });
 */

type TestFixtures = {
    /** Get product config by ID */
    product: (id: ProductId) => ProductConfig;
    /** Navigate to a product's PDP */
    goToProduct: (id: ProductId) => Promise<void>;
    /** Add a product to cart (navigates to PDP, selects options if needed, adds, waits) */
    addToCart: (id: ProductId) => Promise<void>;
    /** Add product to cart and go to checkout */
    addToCartAndCheckout: (id: ProductId) => Promise<void>;
    /** Navigate to a product and click the reservation button */
    reserveProduct: (id: ProductId) => Promise<void>;
};

export const test = base.extend<TestFixtures>({
    product: async ({}, use) => {
        await use((id: ProductId) => {
            const p = products[id];
            if (!p) throw new Error(`Product "${id}" not found in catalog`);
            return p;
        });
    },

    goToProduct: async ({ page }, use) => {
        await use(async (id: ProductId) => {
            const path = productPath(id);
            await navigateToPdp(page, path);
        });
    },

    addToCart: async ({ page }, use) => {
        await use(async (id: ProductId) => {
            const path = productPath(id);
            await navigateToPdp(page, path);

            // Try to select variant options, but don't fail if they're already selected
            const p = products[id];
            if (p.variants.length > 0) {
                try {
                    const optionsContainer = await findProductOptions(page);
                    if (optionsContainer) await selectOptionValue(page, optionsContainer);
                } catch {
                    // Default variant is likely pre-selected — continue
                }
            }

            const action = await findActionButton(page);
            if (!action) throw new Error(`No action button found for product "${id}"`);
            if (action.type === 'reservation') {
                throw new Error(`Product "${id}" is appointment-only (reservation). Use goToProduct() instead.`);
            }

            await action.button.click();
            await waitForLoadingIndicators(page);
            await page.waitForTimeout(2000);
        });
    },

    reserveProduct: async ({ page }, use) => {
        await use(async (id: ProductId) => {
            const path = productPath(id);
            await navigateToPdp(page, path);

            const action = await findActionButton(page);
            if (!action) throw new Error(`No action button found for product "${id}"`);

            await action.button.click();
            await page.waitForTimeout(2000);
        });
    },

    addToCartAndCheckout: async ({ page }, use) => {
        await use(async (id: ProductId) => {
            const path = productPath(id);
            await navigateToPdp(page, path);

            // Try to select variant options, but don't fail if pre-selected
            const p = products[id];
            if (p.variants.length > 0) {
                try {
                    const optionsContainer = await findProductOptions(page);
                    if (optionsContainer) await selectOptionValue(page, optionsContainer);
                } catch {
                    // Default variant is likely pre-selected
                }
            }

            const addBtn = await findAddToCartButton(page);
            if (!addBtn) throw new Error(`Add to cart button not found for product "${id}"`);

            await addBtn.click();
            await waitForLoadingIndicators(page);
            await page.waitForTimeout(2000);

            await page.goto(siteConfig.routes.checkout, { waitUntil: 'domcontentloaded' });
            await page.waitForLoadState('networkidle').catch(() => {});
            await waitForHydration(page);
        });
    },
});

export { expect };
