import { test, expect } from '@playwright/test';
import { testing_event_id } from './_helpers/env';
import {
    testing_exhibit_id,
    exhibit_staff_passcode,
    setup_leads_test_page,
    minimal_badge,
} 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}`;

// Pre-seeded auth used by all tests in this suite
const signed_in_kv = { [exhibit_id]: { key: exhibit_staff_passcode, type: 'shared' } };

// Seed leads_overrides to start in search mode (not QR).
// Without this, the add tab shows the QR scanner which cannot be exercised in Playwright.
const search_mode_seed = { tab_add_mode: { [exhibit_id]: 'search' } };

test.describe('Leads — Add Lead (manual search)', () => {
    // -----------------------------------------------------------------------
    // 1. Navigate to Add tab and see search form
    // -----------------------------------------------------------------------
    test('clicking Add Lead shows manual search form', async ({ page }) => {
        await setup_leads_test_page(page, event_id, exhibit_id, {
            auth_kv: signed_in_kv,
            leads_overrides: search_mode_seed,
        });

        await page.goto(exhibit_url);

        // Click "Add Lead" header button to enter the add tab
        await page.locator('header button.preset-filled-primary').click();

        // Manual search form must be visible
        await expect(
            page.locator('input[placeholder="Attendee name, email, or badge ID..."]')
        ).toBeVisible({ timeout: 8_000 });
    });

    // -----------------------------------------------------------------------
    // 2. Search returns results
    // -----------------------------------------------------------------------
    test('badge search returns results and shows Add button for opted-in attendees', async ({ page }) => {
        await setup_leads_test_page(page, event_id, exhibit_id, {
            auth_kv: signed_in_kv,
            leads_overrides: search_mode_seed,
            // badge_li defaults to [minimal_badge()] — one badge with allow_tracking=true
        });

        await page.goto(exhibit_url);
        await page.locator('header button.preset-filled-primary').click();

        const search_input = page.locator(
            'input[placeholder="Attendee name, email, or badge ID..."]'
        );
        await expect(search_input).toBeVisible({ timeout: 8_000 });

        // Type a query and submit the search form
        await search_input.fill('Scott');
        await page.locator('button:has-text("Search")').click();

        // Result card with the badge full_name should appear
        await expect(page.locator('text=Scott Idem')).toBeVisible({ timeout: 8_000 });

        // The "Add" button must be visible (allow_tracking=true on the mock badge)
        await expect(
            page.locator('.results-list button.preset-filled-success')
        ).toBeVisible({ timeout: 5_000 });
    });

    // -----------------------------------------------------------------------
    // 3. Opted-out attendee shows "Opt-Out" badge instead of Add button
    // -----------------------------------------------------------------------
    test('opted-out attendee shows Opt-Out label instead of Add button', async ({ page }) => {
        await setup_leads_test_page(page, event_id, exhibit_id, {
            auth_kv: signed_in_kv,
            leads_overrides: search_mode_seed,
            // Override badge_li with one badge that has allow_tracking=false
            badge_li: [minimal_badge({ allow_tracking: false, full_name: 'Jane Opted Out' })],
        });

        await page.goto(exhibit_url);
        await page.locator('header button.preset-filled-primary').click();

        const search_input = page.locator(
            'input[placeholder="Attendee name, email, or badge ID..."]'
        );
        await expect(search_input).toBeVisible({ timeout: 8_000 });

        await search_input.fill('Jane');
        await page.locator('button:has-text("Search")').click();

        await expect(page.locator('text=Jane Opted Out')).toBeVisible({ timeout: 8_000 });

        // Add button must NOT appear
        await expect(
            page.locator('.results-list button.preset-filled-success')
        ).not.toBeVisible();

        // "Opt-Out" label must appear instead
        await expect(page.locator('text=Opt-Out')).toBeVisible({ timeout: 5_000 });
    });

    // -----------------------------------------------------------------------
    // 4. Clicking Add creates a lead and shows View link
    //
    // After a successful create_ae_obj__exhibit_tracking(), the search result
    // row switches from "Add" button to a "View" link pointing to the lead
    // detail page. This is the primary success path.
    // -----------------------------------------------------------------------
    test('clicking Add button creates lead and shows View link', async ({ page }) => {
        await setup_leads_test_page(page, event_id, exhibit_id, {
            auth_kv: signed_in_kv,
            leads_overrides: search_mode_seed,
        });

        await page.goto(exhibit_url);
        await page.locator('header button.preset-filled-primary').click();

        const search_input = page.locator(
            'input[placeholder="Attendee name, email, or badge ID..."]'
        );
        await expect(search_input).toBeVisible({ timeout: 8_000 });

        await search_input.fill('Scott');
        await page.locator('button:has-text("Search")').click();

        // Wait for results
        await expect(page.locator('text=Scott Idem')).toBeVisible({ timeout: 8_000 });

        // Intercept the tracking create request before clicking Add
        const create_promise = page.waitForRequest(
            (r) =>
                r.url().includes('event_exhibit_tracking') &&
                r.method() === 'POST',
            { timeout: 5_000 }
        );

        await page.locator('.results-list button.preset-filled-success').click();

        // The POST must have been made
        const create_req = await create_promise;
        const body = JSON.parse(create_req.postData() ?? '{}');
        expect(body.event_badge_id).toBe('UIJT-73-63-61');
        // Shared-passcode users store 'shared_passcode' as their identity
        expect(body.external_person_id).toBe('shared_passcode');

        // "Add" button should disappear; "View" link should appear
        await expect(
            page.locator('.results-list button.preset-filled-success')
        ).not.toBeVisible({ timeout: 5_000 });
        await expect(
            page.locator('.results-list a.preset-filled-secondary')
        ).toBeVisible({ timeout: 5_000 });

        // View link must point to the tracking detail page
        const view_href = await page
            .locator('.results-list a.preset-filled-secondary')
            .getAttribute('href');
        expect(view_href).toContain(`/leads/exhibit/${exhibit_id}/lead/`);
    });

    // -----------------------------------------------------------------------
    // 5. Search with no results shows empty-state message
    // -----------------------------------------------------------------------
    test('search with no results shows empty-state message', async ({ page }) => {
        await setup_leads_test_page(page, event_id, exhibit_id, {
            auth_kv: signed_in_kv,
            leads_overrides: search_mode_seed,
            badge_li: [],  // empty results
        });

        await page.goto(exhibit_url);
        await page.locator('header button.preset-filled-primary').click();

        const search_input = page.locator(
            'input[placeholder="Attendee name, email, or badge ID..."]'
        );
        await expect(search_input).toBeVisible({ timeout: 8_000 });

        await search_input.fill('nobody');
        await page.locator('button:has-text("Search")').click();

        await expect(
            page.locator('text=No attendees found matching')
        ).toBeVisible({ timeout: 5_000 });
    });

    // -----------------------------------------------------------------------
    // 6. "My Leads" filter resolves correctly for shared-passcode users
    //
    // When tracking__qry__licensee_email = 'my' and the user is authenticated
    // via shared passcode, the filter must resolve to 'shared_passcode'
    // (not the literal passcode string, which would never match any record).
    // This is the bug fixed in 2026-04-01 — a regression guard.
    // -----------------------------------------------------------------------
    test('My Leads filter resolves to shared_passcode for shared-auth users', async ({ page }) => {
        const tracking_record = {
            id: 'TRK-MY-001',
            event_exhibit_tracking_id: 'TRK-MY-001',
            event_exhibit_id: exhibit_id,
            event_badge_id: 'UIJT-73-63-61',
            event_badge_full_name: 'Scott Idem',
            event_badge_email: 'scott@demo.oneskyit.com',
            // Stored identity for shared-passcode captures must be the literal
            // 'shared_passcode', not the actual passcode value.
            external_person_id: 'shared_passcode',
            group: 'shared_passcode',
            enable: 1,
            hide: false,
            created_on: new Date().toISOString(),
            updated_on: new Date().toISOString(),
        };

        await setup_leads_test_page(page, event_id, exhibit_id, {
            auth_kv: signed_in_kv,
            tracking_li: [tracking_record],
            leads_overrides: {
                // Pre-set the filter to "My Leads"
                tracking__qry__licensee_email: 'my',
            },
        });

        await page.goto(exhibit_url);

        // The list tab should show; with the "My Leads" filter active and the
        // tracking record's external_person_id = 'shared_passcode', it must pass
        // through the HARD GUARD in filtered_lead_li.
        //
        // We cannot directly assert the filter resolved correctly without reading
        // the store, but we can assert the lead card IS visible (meaning the filter
        // did not incorrectly drop it). If the filter resolved to the raw passcode
        // string ('BOOTH2026'), the record would be excluded and the list empty.
        await expect(page.locator('text=Lead List')).toBeVisible({ timeout: 8_000 });

        // The search will run against Dexie (which is empty — IDB not pre-seeded here).
        // Asserting no crash and correct page structure is the smoke-level check.
        // Full IDB-backed "My Leads" verification belongs in an IDB inject-then-reload test.
        await expect(page.locator('.ae_events_leads_tracking_new')).toBeVisible();
    });
});
