import { test, expect } from '@playwright/test';
import { testing_event_id } from './_helpers/env';
import {
    testing_exhibit_id,
    testing_exhibit_id_b,
    exhibit_staff_passcode,
    setup_leads_test_page,
    attach_leads_routes,
    seed_ae_loc,
    seed_leads_loc,
    seed_events_loc,
    minimal_exhibit,
} from './_helpers/leads_helpers';

const event_id = testing_event_id;
const exhibit_id = testing_exhibit_id;
const exhibit_url = `/events/${event_id}/leads/exhibit/${exhibit_id}`;

// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------

/** Locator for the sign-in form card. */
const signin_form = (page: Parameters<typeof expect>[0]) =>
    (page as import('@playwright/test').Page).locator('.exhibit-signin');

/** Locator for the shared-passcode input field. */
const passcode_input = (page: Parameters<typeof expect>[0]) =>
    (page as import('@playwright/test').Page).locator(
        'input[placeholder="Enter shared code..."]'
    );

/** Locator for the "Add Lead" / "Lead List" toggle button — only visible when signed in. */
const header_action_btn = (page: Parameters<typeof expect>[0]) =>
    (page as import('@playwright/test').Page).locator(
        'header button.preset-filled-primary'
    );

// ---------------------------------------------------------------------------
// Test suite
// ---------------------------------------------------------------------------

test.describe('Leads — Auth Gate', () => {
    // -----------------------------------------------------------------------
    // 1. Unauthenticated user sees sign-in form
    // -----------------------------------------------------------------------
    test('unauthenticated user sees sign-in form, not the lead list', async ({ page }) => {
        // No auth_kv → no exhibit in auth_exhibit_kv → is_signed_in = false
        await setup_leads_test_page(page, event_id, exhibit_id);

        await page.goto(exhibit_url);

        // Sign-in form must appear within a reasonable time
        await expect(signin_form(page)).toBeVisible({ timeout: 10_000 });

        // Header action buttons (Add Lead / Lead List) must NOT be visible
        await expect(header_action_btn(page)).not.toBeVisible();
    });

    // -----------------------------------------------------------------------
    // 2. manager_access bypasses sign-in entirely
    // -----------------------------------------------------------------------
    test('manager_access bypasses sign-in — list tab shown directly', async ({ page }) => {
        await setup_leads_test_page(page, event_id, exhibit_id, {
            // manager_access=true → is_signed_in = true without any exhibit auth
            access: {
                allow_access: true,
                authenticated_access: true,
                trusted_access: true,
                manager_access: true,
            },
        });

        await page.goto(exhibit_url);

        // Sign-in form must NOT appear
        await expect(signin_form(page)).not.toBeVisible({ timeout: 10_000 });

        // Header action button (Add Lead / Lead List) must be visible
        await expect(header_action_btn(page)).toBeVisible({ timeout: 10_000 });
    });

    // -----------------------------------------------------------------------
    // 3. Pre-authenticated user skips sign-in (already in auth_exhibit_kv)
    // -----------------------------------------------------------------------
    test('already-signed-in user sees lead list, not sign-in form', async ({ page }) => {
        await setup_leads_test_page(page, event_id, exhibit_id, {
            // Seed auth_exhibit_kv — simulates a returning user whose session survived
            auth_kv: {
                [exhibit_id]: { key: exhibit_staff_passcode, type: 'shared' },
            },
        });

        await page.goto(exhibit_url);

        await expect(signin_form(page)).not.toBeVisible({ timeout: 10_000 });
        await expect(header_action_btn(page)).toBeVisible({ timeout: 10_000 });
    });

    // -----------------------------------------------------------------------
    // 4. Shared passcode sign-in — success path
    //
    // trusted_access = true causes the sign-in component to auto-fill the
    // passcode field once $lq__exhibit_obj loads into Dexie via the mocked API.
    // Waiting for the input to have a value gives us a reliable timing signal
    // (exhibit is in Dexie, $lq__exhibit_obj is live, sign-in will process).
    // -----------------------------------------------------------------------
    test('shared passcode sign-in — correct passcode signs in successfully', async ({ page }) => {
        await setup_leads_test_page(page, event_id, exhibit_id, {
            // trusted_access triggers auto-fill once exhibit loads; no manager bypass
            access: { allow_access: true, trusted_access: true },
        });

        await page.goto(exhibit_url);

        // Sign-in form visible (trusted_access does NOT bypass the auth gate)
        await expect(signin_form(page)).toBeVisible({ timeout: 10_000 });

        // Wait for exhibit to load into Dexie — auto-fill kicks in for trusted users.
        // Input having the correct value means $lq__exhibit_obj is live.
        await expect(passcode_input(page)).toHaveValue(exhibit_staff_passcode, {
            timeout: 10_000,
        });

        // Submit
        await page.locator('button[type="submit"]').click();

        // After 800 ms UX delay + Svelte reactivity, form should disappear
        await expect(signin_form(page)).not.toBeVisible({ timeout: 5_000 });
        await expect(header_action_btn(page)).toBeVisible({ timeout: 5_000 });
    });

    // -----------------------------------------------------------------------
    // 5. Wrong passcode shows error and keeps the form open
    // -----------------------------------------------------------------------
    test('wrong passcode shows error message, form stays visible', async ({ page }) => {
        await setup_leads_test_page(page, event_id, exhibit_id, {
            access: { allow_access: true, trusted_access: true },
        });

        await page.goto(exhibit_url);

        // Wait for exhibit to be ready (auto-fill is the readiness signal)
        await expect(passcode_input(page)).toHaveValue(exhibit_staff_passcode, {
            timeout: 10_000,
        });

        // Override with an incorrect passcode
        await passcode_input(page).fill('WRONGCODE');
        await page.locator('button[type="submit"]').click();

        // Error text must appear
        await expect(
            page.locator('text=Invalid shared passcode')
        ).toBeVisible({ timeout: 5_000 });

        // Sign-in form must still be visible
        await expect(signin_form(page)).toBeVisible({ timeout: 3_000 });

        // Header action button must NOT appear (not signed in)
        await expect(header_action_btn(page)).not.toBeVisible();
    });

    // -----------------------------------------------------------------------
    // 6. Simultaneous multi-exhibit auth
    //
    // auth_exhibit_kv is keyed by exhibit_id, so Booth A and Booth B auth are
    // completely independent entries. A user can be signed into both at the
    // same time — this mirrors real-world use where staff manages adjacent booths.
    //
    // We pre-seed both exhibits in auth_exhibit_kv and verify that navigating
    // between them never triggers the sign-in form.
    // -----------------------------------------------------------------------
    test('multi-exhibit: both booths authorized simultaneously, neither shows sign-in', async ({ page }) => {
        const exhibit_id_b = testing_exhibit_id_b;
        const exhibit_url_b = `/events/${event_id}/leads/exhibit/${exhibit_id_b}`;

        page.on('pageerror', (err) => console.error(`BROWSER ERROR: ${err.message}`));

        // Route mock covering both exhibit IDs
        await page.route('**/v3/**', async (route) => {
            const req = route.request();
            const url = req.url();
            const method = req.method();

            if (url.includes('site_domain/search')) {
                return route.fulfill({
                    status: 200,
                    contentType: 'application/json',
                    body: JSON.stringify({ data: [
                        {
                            id: '_6jcTbnJk-o', site_id: '92vkYC4fVEl',
                            site_domain_id: '_6jcTbnJk-o', account_id: '_XY7DXtc9MY',
                            account_id_random: '_XY7DXtc9MY', account_code: 'OSIT_DEMO',
                            account_name: 'One Sky IT Demo', fqdn: 'demo.localhost:5173',
                            enable: '1', cfg_json: {}, style_href: '', header_image_path: '',
                        }
                    ] }),
                });
            }
            if (url.includes(`/v3/crud/event_exhibit/${exhibit_id}`) && method === 'GET') {
                return route.fulfill({ status: 200, contentType: 'application/json',
                    body: JSON.stringify(minimal_exhibit(exhibit_id)) });
            }
            if (url.includes(`/v3/crud/event_exhibit/${exhibit_id_b}`) && method === 'GET') {
                return route.fulfill({ status: 200, contentType: 'application/json',
                    body: JSON.stringify(minimal_exhibit(exhibit_id_b, {
                        name: 'Test Booth — Beta Corp', code: 'BETA', staff_passcode: 'BOOTHB99',
                    })) });
            }
            if (url.includes(`/v3/crud/event/${event_id}`) && method === 'GET') {
                return route.fulfill({ status: 200, contentType: 'application/json',
                    body: JSON.stringify({ data: { id: event_id, event_id,
                        name: 'Test Event', mod_exhibits_json: { leads_require_payment: false } } }) });
            }
            return route.fulfill({ status: 200, contentType: 'application/json',
                body: JSON.stringify({ data: [] }) });
        });

        // Seed ae_loc (regular shared-passcode user — no manager bypass)
        await seed_ae_loc(page, { allow_access: true });

        // Pre-seed BOTH exhibits as authorized — independent KV entries.
        // Must seed ae_leads_loc (new PersistedState store) in addition to ae_events_loc.
        await seed_leads_loc(page, {
            auth_exhibit_kv: {
                [exhibit_id]:   { key: exhibit_staff_passcode, type: 'shared', updated_on: new Date().toISOString() },
                [exhibit_id_b]: { key: 'BOOTHB99',            type: 'shared', updated_on: new Date().toISOString() },
            },
        });
        await seed_events_loc(page, {
            [exhibit_id]:   { key: exhibit_staff_passcode, type: 'shared' },
            [exhibit_id_b]: { key: 'BOOTHB99',            type: 'shared' },
        });

        // Booth A → no sign-in form
        await page.goto(exhibit_url);
        await expect(signin_form(page)).not.toBeVisible({ timeout: 10_000 });
        await expect(header_action_btn(page)).toBeVisible({ timeout: 10_000 });

        // Booth B → no sign-in form (independent KV entry, unaffected by Booth A)
        await page.goto(exhibit_url_b);
        await expect(signin_form(page)).not.toBeVisible({ timeout: 10_000 });
        await expect(header_action_btn(page)).toBeVisible({ timeout: 10_000 });

        // Back to Booth A → still authorized
        await page.goto(exhibit_url);
        await expect(signin_form(page)).not.toBeVisible({ timeout: 10_000 });
        await expect(header_action_btn(page)).toBeVisible({ timeout: 10_000 });
    });

    // -----------------------------------------------------------------------
    // 7. Unauthorized exhibit shows sign-in even when another booth is auth'd
    //
    // Verifies that auth_exhibit_kv[booth_A] does not bleed into booth_B.
    // -----------------------------------------------------------------------
    test('multi-exhibit: authorized for Booth A only → Booth B still shows sign-in', async ({ page }) => {
        const exhibit_id_b = testing_exhibit_id_b;
        const exhibit_url_b = `/events/${event_id}/leads/exhibit/${exhibit_id_b}`;

        page.on('pageerror', (err) => console.error(`BROWSER ERROR: ${err.message}`));

        await page.route('**/v3/**', async (route) => {
            const url = route.request().url();
            const method = route.request().method();
            if (url.includes('site_domain/search')) {
                return route.fulfill({ status: 200, contentType: 'application/json',
                    body: JSON.stringify({ data: [
                        { id: '_6jcTbnJk-o', site_id: '92vkYC4fVEl',
                          site_domain_id: '_6jcTbnJk-o', account_id: '_XY7DXtc9MY',
                          account_id_random: '_XY7DXtc9MY', account_code: 'OSIT_DEMO',
                          account_name: 'One Sky IT Demo', fqdn: 'demo.localhost:5173',
                          enable: '1', cfg_json: {}, style_href: '', header_image_path: '' }
                    ] }) });
            }
            if (url.includes(`/v3/crud/event_exhibit/${exhibit_id}`) && method === 'GET') {
                return route.fulfill({ status: 200, contentType: 'application/json',
                    body: JSON.stringify(minimal_exhibit(exhibit_id)) });
            }
            if (url.includes(`/v3/crud/event_exhibit/${exhibit_id_b}`) && method === 'GET') {
                return route.fulfill({ status: 200, contentType: 'application/json',
                    body: JSON.stringify(minimal_exhibit(exhibit_id_b, { name: 'Beta Corp', code: 'BETA' })) });
            }
            return route.fulfill({ status: 200, contentType: 'application/json',
                body: JSON.stringify({ data: [] }) });
        });

        await seed_ae_loc(page, { allow_access: true });
        // Only Booth A authorized — Booth B not in auth_kv
        await seed_events_loc(page, {
            [exhibit_id]: { key: exhibit_staff_passcode, type: 'shared' },
        });

        // Booth A → no sign-in form
        await page.goto(exhibit_url);
        await expect(signin_form(page)).not.toBeVisible({ timeout: 10_000 });

        // Booth B → must show sign-in form (auth does not cross exhibit boundaries)
        await page.goto(exhibit_url_b);
        await expect(signin_form(page)).toBeVisible({ timeout: 10_000 });
        await expect(header_action_btn(page)).not.toBeVisible();
    });
});
