<script lang="ts">
/**
 * src/routes/events/[event_id]/(leads)/leads/exhibit/[exhibit_id]/ae_comp__lead_qr_scanner.svelte
 * Badge QR Scanner for adding leads.
 *
 * scan_qualify modes (controlled by parent ae_tab__add):
 *  - 'rapid':   after add → auto-reset scanner (scan next person fast)
 *  - 'qualify': after add → navigate to lead detail (fill notes/qualifiers)
 */
import { page } from '$app/state';
import { goto } from '$app/navigation';
import { liveQuery } from 'dexie';
import { db_events } from '$lib/ae_events/db_events';
import { ae_api, ae_loc } from '$lib/stores/ae_stores';
import { leads_loc } from '$lib/stores/ae_events_stores__leads.svelte';
import { events_func } from '$lib/ae_events/ae_events_functions';
import Element_qr_scanner from '$lib/elements/element_qr_scanner.svelte';
import { ae_util } from '$lib/ae_utils/ae_utils';
import {
    Camera,
    CircleAlert,
    CircleCheck,
    Eye,
    LoaderCircle,
    RefreshCw,
    RotateCcw,
    ShieldOff,
    X
} from '@lucide/svelte';
import { SvelteMap } from 'svelte/reactivity';
import type { ae_EventBadge } from '$lib/types/ae_types';

interface Props {
    exhibit_id: string;
    scan_qualify?: 'rapid' | 'qualify' | 'auto';
    on_lead_added?: (badge: ae_EventBadge) => void;
}

let { exhibit_id, scan_qualify = 'rapid', on_lead_added }: Props = $props();

// Track existing leads to detect duplicates and previously-removed records.
// Value includes tracking_id AND enabled status so we can offer re-activation.
let existing_leads_map = $derived(
    liveQuery(async () => {
        const leads = await db_events.exhibit_tracking
            .where('event_exhibit_id')
            .equals(exhibit_id)
            .toArray();

        const map = new SvelteMap<
            string,
            { tracking_id: string; enabled: boolean }
        >();
        leads.forEach((l) => {
            const b_id = l.event_badge_id?.toString();
            if (b_id)
                map.set(b_id, {
                    tracking_id: l.event_exhibit_tracking_id?.toString() ?? '',
                    // enable stored as 1/0 or true/false — !! normalises all falsy values
                    enabled: !!l.enable
                });
        });
        return map;
    })
);

let start_qr_scanner = $state(true);
let scanning_status = $state('idle'); // idle, scanning, found, adding, success, error, already_added, tracking_blocked, reenable
let found_badge: ae_EventBadge | null = $state(null);
let existing_tracking_id = $state('');
let new_tracking_id = $state(''); // ID of the lead just created — used for "View Details" link
let error_msg = $state('');

async function handle_qr_scan_result(event: {
    detail: { result: string; entry_method: string };
}) {
    const qr_result = event.detail.result;
    const obj = ae_util.process_data_string(qr_result);

    if (obj && obj.type === 'event_badge' && obj.id) {
        start_qr_scanner = false;

        // Check if already exists (enabled or disabled/removed)
        if ($existing_leads_map?.has(obj.id)) {
            const existing = $existing_leads_map.get(obj.id)!;
            existing_tracking_id = existing.tracking_id;
            // Distinguish: active lead vs previously-removed lead
            scanning_status = existing.enabled ? 'already_added' : 'reenable';
        } else {
            scanning_status = 'found';
        }

        // Load full badge info (needed for allow_tracking check and display)
        try {
            found_badge = await events_func.load_ae_obj_id__event_badge({
                api_cfg: $ae_api,
                event_badge_id: obj.id,
                log_lvl: 1
            });

            // Gate: attendee must have opted in to lead tracking.
            // allow_tracking must be explicitly true — default on badges is false (opt-in model).
            // Only applies to the 'found' state; already-captured badges are left as-is.
            if (
                scanning_status === 'found' &&
                found_badge?.allow_tracking !== true
            ) {
                scanning_status = 'tracking_blocked';
            }

            // Auto mode: skip the confirm card — add immediately if tracking is allowed.
            if (scanning_status === 'found' && scan_qualify === 'auto') {
                await confirm_add_lead();
            }
        } catch (e) {
            console.error('Failed to load badge info', e);
        }
    } else {
        scanning_status = 'error';
        error_msg = 'Invalid QR code. Please scan an Event Badge.';
    }
}

async function confirm_add_lead(dest: 'scan_next' | 'view_lead' = 'scan_next') {
    if (!found_badge || !found_badge.event_badge_id) {
        console.warn(
            '[leads] Guard failed — event_badge_id missing. found_badge:',
            found_badge
        );
        return;
    }

    scanning_status = 'adding';

    // Resolve who is capturing this lead:
    //   licensed exhibit user → their email (kv.key)
    //   shared passcode       → 'shared_passcode' label (don't store the actual passcode)
    //   Aether user (no kv)   → access_type string ('trusted', 'manager', 'super', etc.)
    const kv = leads_loc.current.auth_exhibit_kv?.[exhibit_id];
    const user_email =
        kv?.type === 'licensed' && kv.key
            ? kv.key
            : kv?.type === 'shared'
              ? 'shared_passcode'
              : $ae_loc.access_type || 'anonymous';

    try {
        const result = await events_func.create_ae_obj__exhibit_tracking({
            api_cfg: $ae_api,
            exhibit_id: exhibit_id,
            event_badge_id: found_badge.event_badge_id,
            external_person_id: user_email,
            group: user_email
        });

        if (result) {
            // Capture the new tracking ID so we can link to it
            new_tracking_id = String(result.event_exhibit_tracking_id || '');
            scanning_status = 'success';
            if (on_lead_added) on_lead_added(found_badge);

            if (dest === 'view_lead' && new_tracking_id) {
                // View Lead: navigate directly to lead detail to fill in notes/qualifiers
                goto(
                    `/events/${page.params.event_id}/leads/exhibit/${exhibit_id}/lead/${new_tracking_id}`
                );
            } else {
                // Scan Next / auto mode: auto-reset after 2 seconds to scan the next person
                setTimeout(reset_scanner, 2000);
            }
        } else {
            // API returned false/null — could be a duplicate of a previously-removed record
            // that isn't in the local IDB cache (e.g. after IDB clear or on a second device).
            // Search the API for a disabled tracking record for this badge before surfacing an error.
            try {
                const disabled_li = await events_func.search__exhibit_tracking({
                    api_cfg: $ae_api,
                    event_id: page.params.event_id,
                    event_exhibit_id: exhibit_id,
                    qry_badge_id: found_badge.event_badge_id,
                    enabled: 'not_enabled',
                    log_lvl: 1
                });
                if (disabled_li.length > 0) {
                    // Found a disabled record — offer to re-activate instead of showing an error
                    existing_tracking_id = String(
                        disabled_li[0].event_exhibit_tracking_id || ''
                    );
                    scanning_status = 'reenable';
                } else {
                    scanning_status = 'error';
                    error_msg =
                        'Failed to add lead. Check your connection and try again.';
                }
            } catch {
                scanning_status = 'error';
                error_msg =
                    'Failed to add lead. Check your connection and try again.';
            }
        }
    } catch {
        scanning_status = 'error';
        error_msg = 'Failed to add lead. They might already be added.';
    }
}

async function confirm_reenable_lead(
    dest: 'scan_next' | 'view_lead' = 'scan_next'
) {
    // Re-activate a lead that was previously removed (enable=false).
    // existing_tracking_id is already set from the map or the API fallback search.
    if (!existing_tracking_id) return;
    scanning_status = 'adding';

    try {
        const result = await events_func.update_ae_obj__exhibit_tracking({
            api_cfg: $ae_api,
            exhibit_id,
            exhibit_tracking_id: existing_tracking_id,
            data: { enable: true }
        });

        if (result) {
            new_tracking_id = existing_tracking_id;
            scanning_status = 'success';
            if (on_lead_added && found_badge) on_lead_added(found_badge);
            if (dest === 'view_lead' && new_tracking_id) {
                goto(
                    `/events/${page.params.event_id}/leads/exhibit/${exhibit_id}/lead/${new_tracking_id}`
                );
            } else {
                setTimeout(reset_scanner, 2000);
            }
        } else {
            scanning_status = 'error';
            error_msg = 'Failed to restore lead. Please try again.';
        }
    } catch {
        scanning_status = 'error';
        error_msg = 'Failed to restore lead. Please try again.';
    }
}

function reset_scanner() {
    scanning_status = 'idle';
    found_badge = null;
    new_tracking_id = '';
    error_msg = '';
    start_qr_scanner = true;
}
</script>

<div
    class="lead-qr-scanner flex min-h-100 w-full flex-col items-center justify-center space-y-4">
    {#if scanning_status === 'idle' || scanning_status === 'scanning'}
        <div
            class="border-surface-500/20 bg-surface-900/10 relative mx-auto aspect-square w-full max-w-sm overflow-hidden rounded-xl border-4 shadow-xl">
            <Element_qr_scanner
                bind:start_qr_scanner
                on_qr_scan_result={handle_qr_scan_result} />
            <div
                class="border-primary-500/50 pointer-events-none absolute inset-0 m-8 animate-pulse rounded-lg border-2 sm:m-12">
            </div>
        </div>
        <p class="text-center text-sm italic opacity-70">
            Point camera at the badge QR code
        </p>
    {:else if scanning_status === 'tracking_blocked'}
        <div
            class="card preset-tonal-warning border-warning-500 animate-in zoom-in w-full max-w-md space-y-4 border-2 p-6 shadow-xl">
            <div class="space-y-2 text-center">
                <ShieldOff size="3em" class="text-warning-500 mx-auto" />
                <h3 class="h3 font-bold">Tracking Opt-Out</h3>
                <p class="text-xl font-bold">
                    {found_badge?.full_name || 'Attendee'}
                </p>
                <p class="text-sm opacity-70">
                    This attendee has opted out of exhibitor lead scanning.
                </p>
            </div>
            <button
                type="button"
                class="btn preset-filled-warning w-full font-bold"
                onclick={reset_scanner}>
                <Camera size="1.2em" />
                Scan Next
            </button>
        </div>
    {:else if scanning_status === 'reenable'}
        <div
            class="card preset-tonal-warning border-warning-500 animate-in zoom-in w-full max-w-md space-y-4 border-2 p-6 shadow-xl">
            <div class="space-y-2 text-center">
                <RotateCcw size="3em" class="text-warning-500 mx-auto" />
                <h3 class="h3 font-bold">Previously Removed</h3>
                <p class="text-xl font-bold">
                    {found_badge?.full_name || 'Attendee'}
                </p>
                <p class="text-sm opacity-70">
                    This lead was removed. Re-activate to restore their record
                    including any saved notes and responses.
                </p>
            </div>

            <!-- Two-button confirm — same pattern as the main confirm card -->
            <div class="grid grid-cols-2 gap-3">
                <button
                    type="button"
                    class="bg-warning-500 flex cursor-pointer flex-col items-center justify-center gap-2 rounded-xl py-5 text-sm font-bold text-white shadow-md transition-all hover:brightness-110 active:brightness-90"
                    onclick={() => confirm_reenable_lead('scan_next')}>
                    <Camera size="1.5em" />
                    Restore &amp; Scan Next
                </button>
                <button
                    type="button"
                    class="bg-secondary-500 flex cursor-pointer flex-col items-center justify-center gap-2 rounded-xl py-5 text-sm font-bold text-white shadow-md transition-all hover:brightness-110 active:brightness-90"
                    onclick={() => confirm_reenable_lead('view_lead')}>
                    <Eye size="1.5em" />
                    Restore &amp; View Lead
                </button>
            </div>

            <button
                type="button"
                class="border-surface-500/40 hover:bg-surface-200-800 flex w-full cursor-pointer items-center justify-center gap-2 rounded-lg border py-3 text-sm font-medium opacity-70 transition-colors"
                onclick={reset_scanner}>
                <X size="1em" />
                Cancel / Scan Again
            </button>
        </div>
    {:else if scanning_status === 'already_added'}
        <div
            class="card preset-tonal-secondary border-secondary-500 animate-in zoom-in w-full max-w-md space-y-4 border-2 p-6 shadow-xl">
            <div class="space-y-2 text-center">
                <CircleCheck size="3em" class="text-secondary-500 mx-auto" />
                <h3 class="h3 font-bold">Already Captured</h3>
                <p class="text-xl font-bold">
                    {found_badge?.full_name || 'Attendee'}
                </p>
                <p class="text-sm opacity-70">
                    This attendee is already in your leads list.
                </p>
            </div>

            <a
                href={`/events/${page.params.event_id}/leads/exhibit/${exhibit_id}/lead/${existing_tracking_id}`}
                class="btn btn-xl preset-filled-secondary w-full py-6 font-bold">
                <Eye size="1.5em" class="mr-2" />
                View Lead Details
            </a>

            <button
                type="button"
                class="btn btn-sm w-full opacity-50"
                onclick={reset_scanner}>
                <Camera size="1em" />
                Scan Next
            </button>
        </div>
    {:else if scanning_status === 'found' || scanning_status === 'adding'}
        <!-- bg-surface-50-900: canonical card face token — near-white (light) / deep slate (dark).
             Explicit rather than preset-tonal-* so primary/surface buttons have guaranteed contrast. -->
        <!-- Buttons use direct Tailwind tokens, not btn/preset-*, because the Skeleton
             preset-filled chain resolves to transparent in this card context. -->
        <div
            class="card bg-surface-50-900 border-primary-500 w-full max-w-md space-y-4 border-2 p-6 shadow-xl">
            <div class="text-center">
                <h3 class="h3 font-bold">
                    {found_badge?.full_name || 'Badge Found'}
                </h3>
                <p class="opacity-70">{found_badge?.affiliations || ''}</p>
            </div>

            {#if scan_qualify === 'auto' || scanning_status === 'adding'}
                <!-- Auto mode or mid-add: no buttons — adding happens automatically / in progress -->
                <div
                    class="flex items-center justify-center gap-3 py-3 opacity-70">
                    <LoaderCircle class="animate-spin" size="1.5em" />
                    <span class="font-bold"
                        >{scan_qualify === 'auto'
                            ? 'Auto-adding...'
                            : 'Adding Lead...'}</span>
                </div>
            {:else}
                <!-- Two-button confirm: staff chooses what to do after adding this lead -->
                <div class="grid grid-cols-2 gap-3">
                    <button
                        type="button"
                        class="bg-primary-500 flex cursor-pointer flex-col items-center justify-center gap-2 rounded-xl py-5 text-sm font-bold text-white shadow-md transition-all hover:brightness-110 active:brightness-90"
                        onclick={() => confirm_add_lead('scan_next')}>
                        <Camera size="1.5em" />
                        Add &amp; Scan Next
                    </button>
                    <button
                        type="button"
                        class="bg-secondary-500 flex cursor-pointer flex-col items-center justify-center gap-2 rounded-xl py-5 text-sm font-bold text-white shadow-md transition-all hover:brightness-110 active:brightness-90"
                        onclick={() => confirm_add_lead('view_lead')}>
                        <Eye size="1.5em" />
                        Add &amp; View Lead
                    </button>
                </div>

                <button
                    type="button"
                    class="border-surface-500/40 hover:bg-surface-200-800 flex w-full cursor-pointer items-center justify-center gap-2 rounded-lg border py-3 text-sm font-medium opacity-70 transition-colors"
                    onclick={reset_scanner}>
                    <X size="1em" />
                    Cancel / Scan Again
                </button>
            {/if}
        </div>
    {:else if scanning_status === 'success'}
        <div
            class="card preset-tonal-success flex w-full max-w-md flex-col items-center space-y-4 overflow-hidden shadow-xl">
            <div class="flex w-full flex-col items-center space-y-4 p-10">
                <CircleCheck
                    size="4em"
                    class="text-success-500 animate-bounce" />
                <div class="text-center">
                    <h3 class="h4 font-bold">Lead Added!</h3>
                    <p class="text-xl font-bold">{found_badge?.full_name}</p>
                </div>
                <!-- In rapid mode: offer a View Details escape hatch while the reset countdown runs -->
                {#if new_tracking_id}
                    <a
                        href={`/events/${page.params.event_id}/leads/exhibit/${exhibit_id}/lead/${new_tracking_id}`}
                        class="btn btn-sm preset-outlined-surface w-full">
                        <Eye size="1em" />
                        View Details
                    </a>
                {/if}
                <p class="text-xs tracking-widest uppercase opacity-50">
                    Scanning next in 2 seconds...
                </p>
            </div>
            <!-- Countdown bar: pure CSS animation depletes over 2s (matching the setTimeout reset delay).
                 Gives the operator a clear visual cue that the scanner is about to reset. -->
            <div class="bg-success-200/40 h-1.5 w-full">
                <div class="bg-success-500 scanner-reset-countdown h-full">
                </div>
            </div>
        </div>
    {:else if scanning_status === 'error'}
        <div
            class="card preset-tonal-error flex w-full max-w-md flex-col items-center space-y-4 p-6">
            <CircleAlert size="3em" class="text-error-500" />
            <p class="text-center font-bold">{error_msg}</p>
            <button
                type="button"
                class="btn btn-sm preset-filled-error"
                onclick={reset_scanner}>
                <RefreshCw size="1em" />
                Try Again
            </button>
        </div>
    {/if}
</div>

<style>
/* Countdown bar for the rapid-mode success card.
       Must match the 2000ms setTimeout in reset_scanner(). */
.scanner-reset-countdown {
    animation: scanner-reset-countdown 2s linear forwards;
}
@keyframes scanner-reset-countdown {
    from {
        width: 100%;
    }
    to {
        width: 0%;
    }
}
</style>
