<script lang="ts">
interface Props {
    // /** @type {import('./$types').PageData} */
    data: any;
    event_session_id: string;
    lq__event_session_obj: any;
    lq__auth__event_presenter_obj: any;
}

let {
    data,
    event_session_id,
    lq__event_session_obj,
    lq__auth__event_presenter_obj
}: Props = $props();

import { onMount } from 'svelte';
import { goto } from '$app/navigation';

import {
    ae_snip,
    ae_loc,
    ae_sess,
    ae_api,
    ae_trig,
    slct,
    slct_trigger
} from '$lib/stores/ae_stores';
import {
    events_sess,
    events_slct,
    events_trigger,
    events_trig_kv
} from '$lib/stores/ae_events_stores';
import { events_auth_loc } from '$lib/stores/ae_events_stores__auth.svelte';
import { db_events, type Presenter, type Session } from '$lib/ae_events/db_events';
import { api } from '$lib/ae_api/api';
import { LogIn, X } from '@lucide/svelte';
onMount(() => {
    console.log('Browser environment detected.');

    console.log(
        `lq__auth__event_presenter_obj = `,
        $lq__auth__event_presenter_obj
    );

    let url_person_id = data.url.searchParams.get('person_id');
    // URLSearchParams.get() decodes '+' as a space per the x-www-form-urlencoded spec.
    // Email addresses legitimately contain '+'. Restore it so that DB lookups and
    // auth__kv keys match the stored value. Covers manually-crafted URLs where + was
    // not percent-encoded; new emailed links use %2B and decode correctly without this.
    if (url_person_id && url_person_id.includes('@')) {
        url_person_id = url_person_id.replace(/ /g, '+');
    }
    let url_person_pass = data.url.searchParams.get('person_pass');
    let url_presentation_id = data.url.searchParams.get('presentation_id');
    let url_presenter_id = data.url.searchParams.get('presenter_id');
    let url_session_id = data.url.searchParams.get('session_id');

    // Gate on having a sign-in target (presenter or session) — person_id is optional.
    // WHY: email-only presenters (no Person record) have no separate person_id to put
    // in the URL. expand_auth_for_person resolves their identity via presenter_id_hint.
    // For session POC links, person_id is always present (it's poc_person_id).
    if (url_presenter_id || url_session_id) {
        // person_id is absent for email-only presenter links — fall back to presenter_id.
        // POC links always include person_id, so this branch is only hit for presenters.
        if (!url_person_id) url_person_id = url_presenter_id ?? url_session_id;
        console.log(
            `ae_events_pres_mgmt session [slug] +page.svelte: event_session_id=${$events_slct.event_session_id}; person_id=${url_person_id}; person_pass=${url_person_pass}; presentation_id=${url_presentation_id}; presenter_id=${url_presenter_id}`
        );

        // Using temporary session values first.
        $events_sess.auth__entered_key = url_person_id;
        $events_sess.auth__entered_passcode = url_person_pass;

        $events_sess.auth__person.id = url_person_id;
        $events_sess.auth__person.presentation_id = url_presentation_id;
        $events_sess.auth__person.presenter_id = url_presenter_id;
        $events_sess.auth__person.session_id = url_session_id; // For POC or LCI Champions for sessions. Do not set for a presenter!

        $events_sess.auth__kv.person[url_person_id] = true;
        if (url_session_id) $events_sess.auth__kv.session[url_session_id] = true; // For POC or LCI Champions for sessions. Do not set for a presenter!
        if (url_presentation_id) $events_sess.auth__kv.presentation[url_presentation_id] = true;
        if (url_presenter_id) $events_sess.auth__kv.presenter[url_presenter_id] = true;

        // We need to set the selected presentation and presenter objects based on the respective IDs.
        if (url_session_id) {
            $events_slct.auth__event_session_id = url_session_id;
        }
        if (url_presentation_id && url_presenter_id) {
            $events_slct.auth__event_presentation_id = url_presentation_id;
            $events_slct.auth__event_presenter_id = url_presenter_id;
        }

        if (url_presenter_id) {
            presenter_sign_in();
        }

        if (url_session_id) {
            session_sign_in();
        }

        console.log('Remove the sign in fields from the URL.');
        data.url.searchParams.delete('person_id');
        data.url.searchParams.delete('person_pass');
        data.url.searchParams.delete('presentation_id');
        data.url.searchParams.delete('presenter_id');
        data.url.searchParams.delete('session_id');

        let new_url = data.url.toString();
        console.log(new_url);

        // We need to set browser history and force all load functions to rerun.
        goto(new_url, { replaceState: true, invalidateAll: true });
    }
});

// Grants auth for every presenter record and POC session this person holds in the event.
// WHY: a single sign-in link grants auth for one presenter_id/session_id. This function
// queries Dexie (fast, warm cache) AND the API (reliable, cold cache) in parallel to
// pre-populate auth__kv for ALL of the person's roles at this event in one shot.
//
// person_id: the identity value from the sign-in URL. May be a Person string ID (when a
//   Person record exists, e.g. linked from iMIS) or an email address (common for LCI
//   presenters not in iMIS). Email is detected via '@'.
//
// presenter_id_hint: the event_presenter_id from the sign-in URL. Used to look up the
//   signing presenter's email directly from Dexie, which is then added to the email
//   cross-session search. This means cross-session auth works even when person_id is a
//   string ID (not an email) — we don't have to depend on person_id being an email to
//   find other records for the same person.
//
// auth__kv.presenter is keyed by BOTH event_presenter_id AND email so presenter_is_authed
// checks work across sessions without needing the exact ID.
async function expand_auth_for_person(person_id: string, event_id: string, presenter_id_hint: string | null = null) {
    try {
        const is_email = person_id.includes('@');
        const presenter_field = is_email ? 'email' : 'person_id';

        const [dexie_presenters, dexie_sessions, api_presenters, api_sessions] = await Promise.all([
            db_events.presenter
                .where(presenter_field).equals(person_id)
                .filter(p => p.event_id === event_id)
                .toArray(),
            // POC sessions always link via poc_person_id (a real Person string ID).
            // Skip when signing in with email — email won't match poc_person_id.
            is_email ? Promise.resolve([] as Session[]) : db_events.session
                .where('poc_person_id').equals(person_id)
                .filter(s => s.event_id === event_id)
                .toArray(),
            api.search_ae_obj({
                api_cfg: $ae_api,
                obj_type: 'event_presenter',
                search_query: { and: [
                    { field: 'event_id', op: 'eq', value: event_id },
                    { field: presenter_field, op: 'eq', value: person_id }
                ]},
                limit: 200
            }).catch(() => null),
            is_email ? Promise.resolve(null) : api.search_ae_obj({
                api_cfg: $ae_api,
                obj_type: 'event_session',
                search_query: { and: [
                    { field: 'event_id', op: 'eq', value: event_id },
                    { field: 'poc_person_id', op: 'eq', value: person_id }
                ]},
                limit: 200
            }).catch(() => null)
        ]);

        // Merge Dexie + API results, deduplicated by presenter ID
        const api_presenter_li: Presenter[] = Array.isArray(api_presenters) ? (api_presenters as Presenter[]) : [];
        const api_session_li: Session[] = Array.isArray(api_sessions) ? (api_sessions as Session[]) : [];
        const presenter_kv: Record<string, Presenter> = {};
        for (const p of [...dexie_presenters, ...api_presenter_li]) {
            if (p.event_presenter_id) presenter_kv[p.event_presenter_id] = p;
        }
        const session_kv: Record<string, Session> = {};
        for (const s of [...dexie_sessions, ...api_session_li]) {
            if (s.event_session_id) session_kv[s.event_session_id] = s;
        }

        // Email cross-session pass: find all presenter records that share an email with
        // any record found above, plus the signing presenter's own email (from
        // presenter_id_hint). This covers two cases:
        //   • person_id is a string ID: found records have emails, use those to find
        //     additional email-only records (person_id = null) for the same person.
        //   • person_id is an email: initial search already found by email, but the hint
        //     lookup adds the signing presenter's email if it's not the same value.
        // Emails that were the original search term (is_email) are skipped to avoid
        // re-querying what we just fetched.
        // Build the set of emails to search using a plain object for deduplication
        // (consistent with presenter_kv / session_kv patterns above).
        const emails_to_search_kv: Record<string, true> = {};
        for (const p of Object.values(presenter_kv)) {
            if (p.email && (!is_email || p.email !== person_id)) {
                emails_to_search_kv[p.email] = true;
            }
        }

        // Look up the signing presenter by presenter_id_hint to get their email from Dexie.
        // WHY: the presenter record in IDB has the canonical email; we don't need to depend
        // on person_id being an email address to do the cross-session lookup.
        if (presenter_id_hint) {
            const hint_presenter = await db_events.presenter
                .where('event_presenter_id').equals(presenter_id_hint)
                .first();
            if (hint_presenter?.email && (!is_email || hint_presenter.email !== person_id)) {
                emails_to_search_kv[hint_presenter.email] = true;
            }
        }

        if (Object.keys(emails_to_search_kv).length > 0) {
            const email_results = await Promise.all(
                Object.keys(emails_to_search_kv).map(async (email) => {
                    const [extra_dexie, extra_api] = await Promise.all([
                        db_events.presenter
                            .where('email').equals(email)
                            .filter(p => p.event_id === event_id)
                            .toArray(),
                        api.search_ae_obj({
                            api_cfg: $ae_api,
                            obj_type: 'event_presenter',
                            search_query: { and: [
                                { field: 'event_id', op: 'eq', value: event_id },
                                { field: 'email', op: 'eq', value: email }
                            ]},
                            limit: 200
                        }).catch(() => null)
                    ]);
                    return [
                        ...extra_dexie,
                        ...(Array.isArray(extra_api) ? extra_api as Presenter[] : [])
                    ];
                })
            );
            for (const group of email_results) {
                for (const p of group) {
                    if (p.event_presenter_id && !presenter_kv[p.event_presenter_id]) {
                        presenter_kv[p.event_presenter_id] = p;
                    }
                }
            }
        }

        for (const p of Object.values(presenter_kv)) {
            events_auth_loc.current.auth__kv.presenter[p.event_presenter_id] = true;
            // Also key by email — presenter_is_authed checks this so any record sharing
            // the same email auto-unlocks without needing the exact presenter ID.
            if (p.email) events_auth_loc.current.auth__kv.presenter[p.email] = true;
            if (p.event_presentation_id) events_auth_loc.current.auth__kv.presentation[p.event_presentation_id] = true;
            // 'read' — truthy, signals read-only session access for presenters
            if (p.event_session_id) events_auth_loc.current.auth__kv.session[p.event_session_id] = 'read';
        }
        for (const s of Object.values(session_kv)) {
            events_auth_loc.current.auth__kv.session[s.event_session_id] = true;
        }

        console.log(`expand_auth_for_person: ${Object.keys(presenter_kv).length} presenter(s), ${Object.keys(session_kv).length} POC session(s) auto-granted`);
    } catch (e) {
        console.warn('expand_auth_for_person: lookup failed', e);
    }
}

// For session point of contact (moderator, chair, LCI Champions).
function session_sign_in() {
    console.log('Session sign in with URL values');

    $ae_loc.access_type = 'public'; // Just below trusted access used by staff.
    // $ae_loc.administrator_access = false;
    // $ae_loc.trusted_access = false;
    $ae_loc.public_access = true;
    $ae_loc.authenticated_access = true;

    events_auth_loc.current.auth__person.id = $events_sess.auth__person.id; // person_id
    events_auth_loc.current.auth__person.person_id = $events_sess.auth__person.id;
    events_auth_loc.current.auth__person.entered_key = $events_sess.auth__entered_key; // need to verify entered_key...

    events_auth_loc.current.auth__kv.person[$events_sess.auth__person.person_id] = true;
    events_auth_loc.current.auth__kv.session[$events_sess.auth__person.session_id] = true;
    // Only write these if non-null — a POC link has no presentation_id/presenter_id in the
    // URL, and writing auth__kv[null] would set a junk 'null' string key.
    if ($events_sess.auth__person.presentation_id) {
        events_auth_loc.current.auth__kv.presentation[$events_sess.auth__person.presentation_id] = false; // false = POC has no presentation-level access
    }
    if ($events_sess.auth__person.presenter_id) {
        events_auth_loc.current.auth__kv.presenter[$events_sess.auth__person.presenter_id] = false; // false = POC is not a presenter
    }

    // Setting again here... just because for now.
    // $events_slct.event_presentation_id = $events_sess.auth__person.presentation_id;
    // $events_slct.event_presenter_id = $events_sess.auth__person.presenter_id;

    void expand_auth_for_person($events_sess.auth__person.id, data.params.event_id);
}

// For presenters within a session presentation.
function presenter_sign_in() {
    console.log('Presenter sign in with URL values');

    console.log(event_session_id);

    $ae_loc.access_type = 'authenticated'; // Just below public access used for the session POC.
    // $ae_loc.administrator_access = false;
    // $ae_loc.trusted_access = false;
    $ae_loc.public_access = false;
    $ae_loc.authenticated_access = true;

    $ae_loc.person_id = $events_sess.auth__person.id;

    events_auth_loc.current.auth__person.id = $events_sess.auth__person.id; // person_id
    events_auth_loc.current.auth__person.person_id = $events_sess.auth__person.id;
    // events_auth_loc.current.auth__person.entered_key = $events_sess.auth__entered_key; // also person_id in this case
    // $lq__auth__event_presenter_obj.full_name
    // events_auth_loc.current.auth__person.email = 'test@example.com';
    // events_auth_loc.current.auth__person.full_name = 'Test Person';
    events_auth_loc.current.auth__person.presenter_id =
        $events_sess.auth__person.presenter_id;

    events_auth_loc.current.auth__kv.person[$events_sess.auth__person.person_id] = true;
    // events_auth_loc.current.auth__kv.session[$events_sess.auth__person.session_id] = 'read'; // Set to 'read' for presenters.
    events_auth_loc.current.auth__kv.session[event_session_id] = 'read'; // Set to 'read' for presenters.
    events_auth_loc.current.auth__kv.presentation[
        $events_sess.auth__person.presentation_id
    ] = true; // true implies read/write access
    events_auth_loc.current.auth__kv.presenter[$events_sess.auth__person.presenter_id] =
        true; // true implies read/write access

    // Setting again here... just because for now.
    // $events_slct.auth__event_presentation_id = $events_sess.auth__person.presentation_id;
    // $events_slct.auth__event_presenter_id = $events_sess.auth__person.presenter_id;

    events_auth_loc.current.auth__person.presentation_id =
        $events_sess.auth__person.presentation_id;
    events_auth_loc.current.auth__person.presenter_id =
        $events_sess.auth__person.presenter_id;

    void expand_auth_for_person($events_sess.auth__person.id, data.params.event_id, $events_sess.auth__person.presenter_id);
}

function sign_out() {
    $ae_loc.authenticated_access = false;
    $ae_loc.access_type = 'anonymous';

    events_auth_loc.current.auth__person = {
        id: null,
        email: null,
        full_name: null,
        entered_key: null,
        person_id: null,
        presenter_id: null,
        presentation_id: null,
        session_id: null
    };
    events_auth_loc.current.auth__kv = {
        event: {},
        exhibit: {},
        location: {},
        session: {},
        presentation: {},
        presenter: {},
        person: {}
    };

    $events_sess.auth__person.presenter_id = null;
    // $events_sess.auth__person.presentation_id = null;
    $events_sess.auth__person.session_id = null;
}
</script>

<span>
    {#if events_auth_loc.current.auth__person?.id}
        <button
            type="button"
            class="btn btn-sm preset-tonal-warning"
            onclick={() => {
                sign_out();
                alert('You have been signed out.');
            }}>
            <X size="1em" class="mx-1 inline" />
            Sign Out
            {$lq__auth__event_presenter_obj?.given_name
                ? `- ${$lq__auth__event_presenter_obj?.given_name}`
                : ''}
        </button>
    {:else if $events_sess.auth__person.presenter_id || $events_sess.auth__person.session_id}
        <div
            class="m-2 space-y-2 rounded-md border border-gray-200 p-2 text-center">
            <div class="text-sm text-gray-500">
                Use the link that was sent to your email address to sign in or
                enter your key and passcode to sign in.
            </div>
            <div>
                <input
                    type="text"
                    class="input max-w-36"
                    placeholder="Key"
                    value={$events_sess.auth__entered_key ?? ''}
                    oninput={(e) =>
                        ($events_sess.auth__entered_key = (
                            e.target as HTMLInputElement
                        ).value)} />
                <input
                    type="text"
                    class="input max-w-36"
                    placeholder="Passcode"
                    value={$events_sess.auth__entered_passcode ?? ''}
                    oninput={(e) =>
                        ($events_sess.auth__entered_passcode = (
                            e.target as HTMLInputElement
                        ).value)} />
                <button
                    type="button"
                    class="btn btn-md preset-tonal-primary border-primary-500 border"
                    onclick={() => {
                        console.log('Sign in with URL values');

                        if ($events_sess.auth__person.presenter_id) {
                            presenter_sign_in();
                        } else if ($events_sess.auth__person.session_id) {
                            session_sign_in();
                        }

                        // This needs to be moved to a function!

                        // $events_loc.auth__person.id = $events_sess.auth__entered_key; // person_id
                        // $events_loc.auth__person.entered_key = $events_sess.auth__entered_key; // also person_id in this case
                        // $events_loc.auth__person.email = 'test@example.com';
                        // $events_loc.auth__person.full_name = 'Test Person';

                        // $events_loc.auth__kv.person[$events_sess.entered_key] = true;
                        // $events_loc.auth__kv.session[$events_slct.event_session_id] = true;
                        // $events_loc.auth__kv.presentation[$events_sess.auth__person.presentation_id] = true;
                        // $events_loc.auth__kv.presenter[$events_sess.auth__person.presenter_id] = true;

                        // Setting again here... just because for now.
                        // $events_slct.event_presentation_id = $events_sess.auth__person.presentation_id;
                        // $events_slct.event_presenter_id = $events_sess.auth__person.presenter_id;
                    }}>
                    <LogIn size="1em" class="mx-1 inline" />
                    Sign In
                </button>
            </div>

            <div class="text-sm text-gray-500">
                For: session: {$events_sess.auth__person.session_id}
                presentation: {$events_sess.auth__person.presentation_id}
                presenter: {$events_sess.auth__person.presenter_id}
                <br />

                <!-- {$lq__event_presentation_obj?.name ? `Name: "${$lq__event_presentation_obj.name}"` : '-- not set --'} -->
            </div>

            <!-- {#if $events_loc.auth__person?.id}
        <button type="button"
            class="btn btn-sm variant-soft-warning"
            >
            <span class="fas fa-times mx-1"></span>
            Sign Out
        </button>
    {/if} -->
        </div>
    {/if}
</span>
