import { type Page, type Locator, expect } from '@playwright/test';
import { siteConfig } from '../config/siteConfig';
import {
    waitForHydration,
    navigateToPdp,
    findAddToCartButton,
    openMiniCart,
    waitForLoadingIndicators,
} from './cart-helpers';
import { STRIPE_CARDS, fillStripeCard as _fillStripeCard } from './payment-helpers';

/**
 * Default test shipping address (Japan format)
 */
export const TEST_SHIPPING_ADDRESS = {
    lastName: 'Test',
    firstName: 'Taro',
    postalCode: '104-0061',
    prefecture: 'Tokyo',
    city: 'Chuo-ku',
    street: 'Ginza 3-6-1',
    building: 'Matsuya Ginza',
    phone: '03-3567-1211',
    email: 'e2e-guest@test.matsuyaginza.com',
};

/**
 * Stripe test card details — re-exported from payment-helpers for backwards compatibility.
 */
export const STRIPE_TEST_CARD = STRIPE_CARDS.standard;

/**
 * Fill Stripe card details — re-exported from payment-helpers for backwards compatibility.
 */
export const fillStripeCard = _fillStripeCard;

/**
 * Add a product to cart and navigate to checkout page.
 */
export async function addProductAndGoToCheckout(page: Page): Promise<boolean> {
    // Navigate to PDP
    await navigateToPdp(page, siteConfig.routes.pdp);

    // Find and click add to cart
    const addBtn = await findAddToCartButton(page);
    if (!addBtn) {
        console.error('Add to cart button not found');
        return false;
    }

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

    // Navigate to checkout
    await page.goto(siteConfig.routes.checkout, {
        waitUntil: 'domcontentloaded',
    });
    await page
        .waitForLoadState('networkidle')
        .catch(() => console.log('Network idle timeout on checkout, continuing...'));
    await waitForHydration(page);

    // Verify we're on checkout
    const isCheckout =
        page.url().includes('checkout') ||
        (await page.locator('[class*="checkout" i], [data-testid*="checkout"]').count()) > 0;

    return isCheckout;
}

/**
 * Select delivery fulfillment method (vs in-store pickup).
 */
export async function selectDeliveryFulfillment(page: Page): Promise<void> {
    // Feature branch: toggle switch for pickup
    const toggleSwitch = page.getByRole('switch').first();
    if (await toggleSwitch.isVisible().catch(() => false)) {
        const isChecked = await toggleSwitch.getAttribute('aria-checked');
        if (isChecked === 'true') {
            await toggleSwitch.click();
            await page.waitForTimeout(500);
        }
        return;
    }

    // Fall through to existing selectors for staging compatibility
    const deliverySelectors = [
        'input[value*="delivery" i]',
        'input[value*="DELIVERY" i]',
        'label:has-text("Delivery")',
        'label:has-text("配送")',
        'button:has-text("Delivery")',
        '[data-testid*="delivery"]',
        '[class*="delivery" i] input[type="radio"]',
    ];

    for (const selector of deliverySelectors) {
        const el = page.locator(selector).first();
        const visible = await el.isVisible().catch(() => false);
        if (visible) {
            await el.click();
            await page.waitForTimeout(500);
            return;
        }
    }
    // Delivery might be pre-selected or the only option
    console.log('Delivery option not found or already selected');
}

/**
 * Fill shipping address form (Japanese format).
 * Uses Playwright accessible-name / placeholder selectors first (feature branch),
 * then falls back to CSS attribute selectors (staging compatibility).
 */
export async function fillShippingAddress(
    page: Page,
    address: typeof TEST_SHIPPING_ADDRESS = TEST_SHIPPING_ADDRESS
): Promise<void> {
    // Wait for shipping form to be visible
    await page.waitForTimeout(1000);

    // Last name / Family Name
    try {
        const familyName = page.getByPlaceholder('Family Name');
        await familyName.waitFor({ state: 'visible', timeout: 5000 });
        await familyName.fill(address.lastName);
    } catch {
        await fillField(page, [
            'input[name*="lastname" i]',
            'input[name*="last_name" i]',
            'input[name*="familyName" i]',
            'input[placeholder*="last name" i]',
            'input[placeholder*="姓"]',
        ], address.lastName);
    }

    // First name
    try {
        const firstName = page.getByPlaceholder(/first name/i);
        await firstName.waitFor({ state: 'visible', timeout: 5000 });
        await firstName.fill(address.firstName);
    } catch {
        await fillField(page, [
            'input[name*="firstname" i]',
            'input[name*="first_name" i]',
            'input[name*="givenName" i]',
            'input[placeholder*="first name" i]',
            'input[placeholder*="名"]:not([placeholder*="姓"])',
        ], address.firstName);
    }

    // Postal code
    try {
        const postalCode = page.getByPlaceholder('000-0000').first();
        await postalCode.waitFor({ state: 'visible', timeout: 5000 });
        await postalCode.fill(address.postalCode);
    } catch {
        await fillField(page, [
            'input[name*="postcode" i]',
            'input[name*="postal" i]',
            'input[name*="zip" i]',
            'input[placeholder*="postal" i]',
            'input[placeholder*="郵便番号"]',
        ], address.postalCode);
    }

    // Click "Search Address" button if available (feature branch requires this)
    const searchBtn = page.getByRole('button', { name: /search address/i }).first();
    if (await searchBtn.isVisible().catch(() => false)) {
        const isDisabled = await searchBtn.isDisabled().catch(() => true);
        if (!isDisabled) {
            await searchBtn.scrollIntoViewIfNeeded();
            await searchBtn.click({ force: true });
            await page.waitForTimeout(3000); // Wait for address lookup
        } else {
            await page.waitForTimeout(2000);
        }
    } else {
        // Wait for postal code auto-fill (staging: auto-lookup)
        await page.waitForTimeout(2000);
    }

    // Also scroll and force-click prefecture if needed (sticky header blocks it)
    const prefFieldScroll = page.getByPlaceholder('Prefecture').first();
    if (await prefFieldScroll.isVisible().catch(() => false)) {
        await prefFieldScroll.scrollIntoViewIfNeeded().catch(() => {});
    }

    // Prefecture / Region — feature branch uses a clickable searchable dropdown
    try {
        const prefField = page.getByPlaceholder('Prefecture').first();
        if (await prefField.isVisible().catch(() => false)) {
            const currentVal = await prefField.inputValue().catch(() => '');
            if (!currentVal) {
                await prefField.scrollIntoViewIfNeeded();
                await prefField.click({ force: true });
                await page.waitForTimeout(500);

                // Try typing to filter the dropdown (keyboard input)
                await page.keyboard.type(address.prefecture, { delay: 100 });
                await page.waitForTimeout(1000);

                // Try clicking the matching dropdown option
                const option = page.getByText(address.prefecture, { exact: true }).last();
                try {
                    await option.waitFor({ state: 'visible', timeout: 3000 });
                    await option.click({ force: true });
                } catch {
                    // Try pressing Enter or ArrowDown + Enter
                    await page.keyboard.press('ArrowDown');
                    await page.keyboard.press('Enter');
                }
                await page.waitForTimeout(500);
            }
        } else {
            throw new Error('Prefecture placeholder not visible, fall back');
        }
    } catch {
        // Fall back to old selectors for staging compatibility
        const prefectureField = await findVisibleInput(page, [
            'select[name*="region" i]',
            'input[name*="region" i]',
            'select[name*="prefecture" i]',
            'input[name*="prefecture" i]',
        ]);
        if (prefectureField) {
            const tagName = await prefectureField.evaluate((el) => el.tagName.toLowerCase());
            if (tagName === 'select') {
                await prefectureField
                    .selectOption({ label: address.prefecture })
                    .catch(() =>
                        prefectureField.selectOption({ value: address.prefecture }).catch(() =>
                            console.log('Prefecture select failed, may be auto-filled')
                        )
                    );
            } else {
                const currentVal = await prefectureField.inputValue().catch(() => '');
                if (!currentVal) {
                    await prefectureField.fill(address.prefecture);
                }
            }
        }
    }

    // City (might be auto-filled by postal code)
    try {
        const cityField = page.getByPlaceholder('City').first();
        await cityField.waitFor({ state: 'visible', timeout: 5000 });
        const currentVal = await cityField.inputValue().catch(() => '');
        if (!currentVal) {
            await cityField.fill(address.city);
        }
    } catch {
        const cityField = await findVisibleInput(page, [
            'input[name*="city" i]',
            'input[placeholder*="city" i]',
            'input[placeholder*="市区町村"]',
        ]);
        if (cityField) {
            const currentVal = await cityField.inputValue().catch(() => '');
            if (!currentVal) {
                await cityField.fill(address.city);
            }
        }
    }

    // Street
    try {
        const streetField = page.getByPlaceholder(/street/i).first();
        await streetField.waitFor({ state: 'visible', timeout: 5000 });
        await streetField.fill(address.street);
    } catch {
        await fillField(page, [
            'input[name*="street[0]" i]',
            'input[name*="street1" i]',
            'input[name*="street" i]:not([name*="street2" i]):not([name*="street[1]" i])',
            'input[placeholder*="street" i]',
            'input[placeholder*="番地"]',
        ], address.street);
    }

    // Building / apartment (optional)
    try {
        const buildingField = page.getByPlaceholder(/building/i).first();
        await buildingField.waitFor({ state: 'visible', timeout: 5000 });
        await buildingField.fill(address.building);
    } catch {
        await fillField(page, [
            'input[name*="street[1]" i]',
            'input[name*="street2" i]',
            'input[name*="building" i]',
            'input[name*="apartment" i]',
            'input[placeholder*="building" i]',
            'input[placeholder*="建物"]',
        ], address.building);
    }

    // Phone
    try {
        const phoneField = page.getByPlaceholder('000-0000-0000').first();
        await phoneField.waitFor({ state: 'visible', timeout: 5000 });
        await phoneField.fill(address.phone);
    } catch {
        await fillField(page, [
            'input[name*="telephone" i]',
            'input[name*="phone" i]',
            'input[type="tel"]',
            'input[placeholder*="phone" i]',
            'input[placeholder*="電話番号"]',
        ], address.phone);
    }

    // Email (guest checkout only)
    try {
        const emailField = page.getByPlaceholder('Email').first();
        await emailField.waitFor({ state: 'visible', timeout: 5000 });
        await emailField.fill(address.email);

        // Confirm email
        try {
            const confirmEmail = page.getByPlaceholder('Email confirmation');
            await confirmEmail.waitFor({ state: 'visible', timeout: 3000 });
            await confirmEmail.fill(address.email);
        } catch {
            // Fall back to old confirm email selectors
            const confirmEmailField = await findVisibleInput(page, [
                'input[name*="confirm_email" i]',
                'input[name*="confirmEmail" i]',
                'input[name*="email_confirm" i]',
            ]);
            if (confirmEmailField) {
                await confirmEmailField.fill(address.email);
            }
        }
    } catch {
        // Fall back to old email selectors
        const emailField = await findVisibleInput(page, [
            'input[name*="email" i][type="email"]',
            'input[name*="email" i]',
        ]);
        if (emailField) {
            await emailField.fill(address.email);

            // Confirm email
            const confirmEmailField = await findVisibleInput(page, [
                'input[name*="confirm_email" i]',
                'input[name*="confirmEmail" i]',
                'input[name*="email_confirm" i]',
            ]);
            if (confirmEmailField) {
                await confirmEmailField.fill(address.email);
            }
        }
    }
}

/**
 * Accept terms & conditions and place order.
 */
export async function acceptTermsAndPlaceOrder(page: Page): Promise<boolean> {
    // Check terms & conditions checkbox
    const termsSelectors = [
        'input[name*="terms" i]',
        'input[name*="agree" i]',
        'input[id*="terms" i]',
        'label:has-text("Terms") input[type="checkbox"]',
        'label:has-text("利用規約") input[type="checkbox"]',
        '[data-testid*="terms"] input[type="checkbox"]',
    ];

    for (const selector of termsSelectors) {
        const checkbox = page.locator(selector).first();
        const visible = await checkbox.isVisible().catch(() => false);
        if (visible) {
            const checked = await checkbox.isChecked().catch(() => false);
            if (!checked) await checkbox.check();
        }
    }

    // Check privacy policy checkbox
    const privacySelectors = [
        'input[name*="privacy" i]',
        'label:has-text("Privacy") input[type="checkbox"]',
        'label:has-text("プライバシー") input[type="checkbox"]',
        '[data-testid*="privacy"] input[type="checkbox"]',
    ];

    for (const selector of privacySelectors) {
        const checkbox = page.locator(selector).first();
        const visible = await checkbox.isVisible().catch(() => false);
        if (visible) {
            const checked = await checkbox.isChecked().catch(() => false);
            if (!checked) await checkbox.check();
        }
    }

    await page.waitForTimeout(500);

    // Click place order button
    const placeOrderSelectors = [
        'button:has-text("Confirm")',
        'button:has-text("確認")',
        'button:has-text("Place Order")',
        'button:has-text("注文する")',
        'button:has-text("注文を確定")',
        'button:has-text("Submit Order")',
        'button:has-text("Complete Order")',
        '[data-testid*="place-order"]',
        '[data-testid*="submit-order"]',
        'button[type="submit"]:has-text("Order")',
    ];

    for (const selector of placeOrderSelectors) {
        const button = page.locator(selector).first();
        const visible = await button.isVisible().catch(() => false);
        if (visible) {
            const disabled = await button.isDisabled().catch(() => true);
            if (!disabled) {
                await button.click();
                return true;
            }
        }
    }

    console.error('Place order button not found or disabled');
    return false;
}

/**
 * Verify the order confirmation page loaded successfully.
 */
export async function verifyOrderConfirmation(page: Page): Promise<boolean> {
    // Wait for navigation to order confirmation
    try {
        await page.waitForURL(
            (url) =>
                url.pathname.includes('order-confirmation') ||
                url.pathname.includes('success') ||
                url.pathname.includes('thank'),
            { timeout: 30000 }
        );
    } catch {
        console.log('URL did not change to confirmation, checking page content...');
    }

    const confirmationSelectors = [
        ':text("Order Confirmation")',
        ':text("Thank you")',
        ':text("ご注文ありがとうございます")',
        ':text("注文確認")',
        ':text("Order Number")',
        ':text("注文番号")',
        '[class*="confirmation" i]',
        '[class*="receipt" i]',
        '[data-testid*="confirmation"]',
        '[data-testid*="order-success"]',
    ];

    for (const selector of confirmationSelectors) {
        const el = page.locator(selector).first();
        const visible = await el.isVisible().catch(() => false);
        if (visible) return true;
    }

    return false;
}

// --- Private helpers ---

async function fillField(
    page: Page,
    selectors: string[],
    value: string
): Promise<void> {
    const input = await findVisibleInput(page, selectors);
    if (input) {
        await input.fill(value);
    }
}

async function findVisibleInput(
    page: Page,
    selectors: string[]
): Promise<Locator | null> {
    for (const selector of selectors) {
        const el = page.locator(selector).first();
        const visible = await el.isVisible().catch(() => false);
        if (visible) return el;
    }
    return null;
}
