import { get } from 'svelte/store';
import { slct } from '$lib/stores/ae_stores';
import type { key_val } from '$lib/stores/ae_stores';
import { api } from '$lib/ae_api/api';

import { db_save_ae_obj_li__ae_obj } from '$lib/ae_core/core__idb_dexie';
import { db_events } from '$lib/ae_events/db_events';
import type { ae_EventSession } from '$lib/types/ae_types';

import { load_ae_obj_li__event_file } from '$lib/ae_events/ae_events__event_file';
import { load_ae_obj_li__event_presentation } from '$lib/ae_events/ae_events__event_presentation';

const ae_promises: key_val = {};

// Updated 2026-01-30: Trace-Ready SWR Pattern with Performance Timing
export async function load_ae_obj_id__event_session({
    api_cfg,
    event_session_id,
    inc_file_li = false,
    inc_all_file_li = false,
    inc_presentation_li = false,
    inc_presenter_li = false,
    inc_file_counts = false,
    enabled = 'enabled',
    hidden = 'not_hidden',
    limit = 100,
    offset = 0,
    try_cache = true,
    log_lvl = 0
}: {
    api_cfg: any;
    event_session_id: string;
    inc_file_li?: boolean;
    inc_all_file_li?: boolean;
    inc_presentation_li?: boolean;
    inc_presenter_li?: boolean;
    // When true, uses v_event_session_w_file_count (backend 'alt' view) which includes
    // file_count / file_count_all. Default false — the base view is cheaper and sufficient
    // for most callers. Use true when the caller needs counts (e.g. session detail page load).
    inc_file_counts?: boolean;
    enabled?: 'enabled' | 'all' | 'not_enabled';
    hidden?: 'hidden' | 'all' | 'not_hidden';
    limit?: number;
    offset?: number;
    try_cache?: boolean;
    log_lvl?: number;
}): Promise<ae_EventSession | null> {
    const view = inc_file_counts ? 'alt' : 'default';
    const start_time = performance.now();
    if (log_lvl) {
        console.log(
            `🔎 [Trace] load_ae_obj_id__event_session: START (id=${event_session_id}, try_cache=${try_cache})`
        );
    }

    // Hierarchy Enforcement: Pulling presenters requires pulling presentations first
    if (inc_presenter_li) inc_presentation_li = true;

    // 1. FAST PATH: Return cached data immediately
    if (try_cache) {
        try {
            const cached = await db_events.session.get(event_session_id);
            if (cached) {
                const elapsed = (performance.now() - start_time).toFixed(2);
                if (log_lvl)
                    console.log(
                        `✅ [Trace] load_ae_obj_id: CACHE HIT at ${elapsed}ms. Returning stale shell for id=${event_session_id}`
                    );

                // Background tasks: refresh parent and warm child caches (non-blocking)
                _refresh_session_id_background({
                    api_cfg,
                    event_session_id,
                    view,
                    try_cache,
                    inc_file_li,
                    inc_all_file_li,
                    inc_presentation_li,
                    inc_presenter_li,
                    enabled,
                    hidden,
                    limit,
                    offset,
                    log_lvl: log_lvl > 1 ? log_lvl : 0
                });

                // In SWR mode, we fire child loads in background to warm IDB for the view's LiveQueries
                _handle_nested_loads(cached, {
                    api_cfg,
                    inc_file_li,
                    inc_all_file_li,
                    inc_presentation_li,
                    inc_presenter_li,
                    enabled,
                    hidden,
                    limit,
                    offset,
                    try_cache,
                    log_lvl: 0
                });

                return cached; // Return immediately without awaiting nested loads
            } else if (log_lvl) {
                console.log(
                    `⏳ [Trace] load_ae_obj_id: CACHE MISS at ${(performance.now() - start_time).toFixed(2)}ms for id=${event_session_id}`
                );
            }
        } catch (e) {
            if (log_lvl)
                console.error(
                    `❌ [Trace] load_ae_obj_id: Cache access error:`,
                    e
                );
        }
    }

    // 2. SLOW PATH: Wait for API
    if (log_lvl)
        console.log(
            `🚀 [Trace] load_ae_obj_id: Proceeding to API path for id=${event_session_id}`
        );
    return await _refresh_session_id_background({
        api_cfg,
        event_session_id,
        view,
        try_cache,
        inc_file_li,
        inc_all_file_li,
        inc_presentation_li,
        inc_presenter_li,
        enabled,
        hidden,
        limit,
        offset,
        log_lvl
    });
}

/**
 * Internal background refresh for a single session
 */
async function _refresh_session_id_background({
    api_cfg,
    event_session_id,
    view,
    try_cache,
    inc_file_li,
    inc_all_file_li,
    inc_presentation_li,
    inc_presenter_li,
    enabled,
    hidden,
    limit,
    offset,
    log_lvl
}: any) {
    const start_time = performance.now();
    if (typeof navigator !== 'undefined' && !navigator.onLine) return null;
    try {
        if (log_lvl)
            console.log(
                `📡 [Trace] _refresh_session_id: API Fetching id=${event_session_id}`
            );
        const result = await api.get_ae_obj({
            api_cfg,
            obj_type: 'event_session',
            obj_id: event_session_id,
            view,
            log_lvl
        });

        if (result) {
            const processed = await process_ae_obj__event_session_props({
                obj_li: [result],
                log_lvl
            });
            const processed_obj = processed[0];
            const elapsed = (performance.now() - start_time).toFixed(2);

            if (log_lvl)
                console.log(
                    `📦 [Trace] _refresh_session_id: Received from API at ${elapsed}ms (id=${processed_obj.id})`
                );

            // PRESERVE AGGREGATE COUNTS: The individual session API view (view=default)
            // does not compute file_count / file_count_all — those come from the list
            // view SQL query. bulkPut replaces the full IDB record, so if we write
            // undefined here we clobber the counts the list search already stored.
            // WHY: SvelteKit link prefetching triggers this path on hover over session
            // links in the search results list, causing the file count badge to blip.
            // FIX: Read the cached counts and keep them if the API didn't return new ones.
            if (try_cache && (processed_obj.file_count_all == null || processed_obj.file_count == null)) {
                try {
                    const cached_id = processed_obj.id || processed_obj.event_session_id;
                    const cached = cached_id ? await db_events.session.get(cached_id) : null;
                    if (cached) {
                        if (processed_obj.file_count_all == null && cached.file_count_all != null)
                            processed_obj.file_count_all = cached.file_count_all;
                        if (processed_obj.file_count == null && cached.file_count != null)
                            processed_obj.file_count = cached.file_count;
                    }
                } catch (_) { /* non-critical — best-effort count preservation */ }
            }

            if (try_cache) {
                await db_save_ae_obj_li__ae_obj({
                    db_instance: db_events,
                    table_name: 'session',
                    obj_li: [processed_obj],
                    properties_to_save,
                    log_lvl
                });
                // CRITICAL FIX (2026-02-26): Yield to microtask queue so Dexie liveQuery observers
                // fire before we return. Without this, component-mounted liveQueries may subscribe
                // to IDB *before* the write completes, causing empty results on cold-start.
                await Promise.resolve();
                if (log_lvl)
                    console.log(
                        `💾 [Trace] _refresh_session_id: Saved to IDB cache.`
                    );
            }
            // CRITICAL FIX (2026-02-26): Preserve parent's try_cache value when loading nested data.
            // Previously set to `false`, which meant presentations/presenters were fetched from API
            // but NEVER written to IndexedDB, causing "refresh twice" bug on cold-start.
            // Now nested loads inherit parent's caching behavior for deterministic first-render.
            return await _handle_nested_loads(processed_obj, {
                api_cfg,
                inc_file_li,
                inc_all_file_li,
                inc_presentation_li,
                inc_presenter_li,
                enabled,
                hidden,
                limit,
                offset,
                try_cache,
                log_lvl
            });
        }
    } catch (e) {
        if (log_lvl)
            console.error(
                `❌ [Trace] _refresh_session_id: API error for id=${event_session_id}:`,
                e
            );
    }
    return null;
}

/**
 * Helper to handle nested collection loads for a session
 */
async function _handle_nested_loads(
    session_obj: any,
    {
        api_cfg,
        inc_file_li,
        inc_all_file_li,
        inc_presentation_li,
        inc_presenter_li,
        enabled,
        hidden,
        limit,
        offset,
        try_cache,
        log_lvl
    }: any
) {
    const start_time = performance.now();
    const current_session_id = session_obj.id || session_obj.event_session_id;
    if (!current_session_id) return session_obj;

    const tasks = [];
    if (inc_file_li) {
        tasks.push(
            load_ae_obj_li__event_file({
                api_cfg,
                for_obj_type: 'event_session',
                for_obj_id: current_session_id,
                enabled,
                // WHY: must include hidden files so the Manage Files UI can show and unhide them.
                // The default 'not_hidden' was causing hidden files to never reach Dexie,
                // making them invisible in the manage list until a manual Refresh.
                hidden: 'all',
                limit: 15,
                try_cache,
                log_lvl
            }).then((res) => (session_obj.event_file_li = res))
        );
    }

    if (inc_presentation_li) {
        tasks.push(
            load_ae_obj_li__event_presentation({
                api_cfg,
                for_obj_type: 'event_session',
                for_obj_id: current_session_id,
                inc_file_li: inc_all_file_li,
                inc_presenter_li,
                enabled,
                hidden,
                limit,
                offset,
                try_cache,
                log_lvl
            }).then((res) => (session_obj.event_presentation_li = res))
        );
    }

    if (tasks.length > 0) {
        await Promise.all(tasks);
        if (log_lvl)
            console.log(
                `🔗 [Trace] _handle_nested_loads: Finished child collections in ${(performance.now() - start_time).toFixed(2)}ms`
            );
    }
    return session_obj;
}

// Updated 2026-01-30: Robust Cache Lookups with Performance Tracing
export async function load_ae_obj_li__event_session({
    api_cfg,
    for_obj_type = 'event',
    for_obj_id,
    inc_file_li = false,
    inc_all_file_li = false,
    inc_presentation_li = false,
    inc_presenter_li = false,
    enabled = 'enabled',
    hidden = 'not_hidden',
    view = 'alt',
    limit = 100,
    offset = 0,
    order_by_li = [
        { priority: 'DESC' },
        { sort: 'DESC' },
        { start_datetime: 'ASC' },
        { name: 'ASC' },
        { updated_on: 'DESC' }
    ],
    try_cache = true,
    log_lvl = 0
}: {
    api_cfg: any;
    for_obj_type?: string;
    for_obj_id: string;
    inc_file_li?: boolean;
    inc_all_file_li?: boolean;
    inc_presentation_li?: boolean;
    inc_presenter_li?: boolean;
    enabled?: 'enabled' | 'all' | 'not_enabled';
    hidden?: 'hidden' | 'all' | 'not_hidden';
    view?: string;
    limit?: number;
    offset?: number;
    order_by_li?: any;
    try_cache?: boolean;
    log_lvl?: number;
}): Promise<ae_EventSession[]> {
    const start_time = performance.now();
    if (log_lvl) {
        console.log(
            `🔎 [Trace] load_ae_obj_li__event_session: START (for=${for_obj_type}:${for_obj_id}, try_cache=${try_cache})`
        );
    }

    // Hierarchy Enforcement: Pulling presenters requires pulling presentations first
    if (inc_presenter_li) inc_presentation_li = true;

    if (try_cache) {
        try {
            // Robust lookup logic
            let query;
            if (for_obj_type === 'event_location')
                query = db_events.session
                    .where('event_location_id')
                    .equals(for_obj_id);
            else if (for_obj_type === 'event')
                query = db_events.session.where('event_id').equals(for_obj_id);
            else query = db_events.session.where('for_id').equals(for_obj_id);

            const cached_li = await query.toArray();

            if (cached_li && cached_li.length > 0) {
                const elapsed = (performance.now() - start_time).toFixed(2);
                if (log_lvl)
                    console.log(
                        `✅ [Trace] load_ae_obj_li: CACHE HIT at ${elapsed}ms (${cached_li.length} items).`
                    );

                // Background refresh (non-blocking)
                _refresh_session_li_background({
                    api_cfg,
                    for_obj_type,
                    for_obj_id,
                    view,
                    // Optimization: Disable nested loads for list members to prevent request storms
                    inc_file_li: false,
                    inc_all_file_li: false,
                    inc_presentation_li: false,
                    inc_presenter_li: false,
                    enabled,
                    hidden,
                    limit,
                    offset,
                    order_by_li,
                    try_cache,
                    log_lvl: log_lvl > 1 ? log_lvl : 0
                });

                return cached_li;
            } else if (log_lvl) {
                console.log(
                    `⏳ [Trace] load_ae_obj_li: CACHE MISS at ${(performance.now() - start_time).toFixed(2)}ms for type=${for_obj_type} id=${for_obj_id}`
                );
            }
        } catch (e) {
            if (log_lvl)
                console.error(
                    `❌ [Trace] load_ae_obj_li: Cache access error:`,
                    e
                );
        }
    }

    return await _refresh_session_li_background({
        api_cfg,
        for_obj_type,
        for_obj_id,
        view,
        inc_file_li,
        inc_all_file_li,
        inc_presentation_li,
        inc_presenter_li,
        enabled,
        hidden,
        limit,
        offset,
        order_by_li,
        try_cache,
        log_lvl
    });
}

async function _refresh_session_li_background({
    api_cfg,
    for_obj_type,
    for_obj_id,
    view,
    inc_file_li,
    inc_all_file_li,
    inc_presentation_li,
    inc_presenter_li,
    enabled,
    hidden,
    limit,
    offset,
    order_by_li,
    try_cache,
    log_lvl
}: any) {
    const start_time = performance.now();
    if (typeof navigator !== 'undefined' && !navigator.onLine) return [];
    try {
        if (log_lvl)
            console.log(
                `📡 [Trace] _refresh_session_li: API Fetching for=${for_obj_type}:${for_obj_id} (view=${view})`
            );
        const result_li = await api.get_ae_obj_li({
            api_cfg,
            obj_type: 'event_session',
            for_obj_type,
            for_obj_id,
            view,
            enabled,
            hidden,
            limit,
            offset,
            order_by_li,
            log_lvl
        });

        if (result_li) {
            const processed = await process_ae_obj__event_session_props({
                obj_li: result_li,
                log_lvl
            });
            const elapsed = (performance.now() - start_time).toFixed(2);
            if (log_lvl)
                console.log(
                    `📦 [Trace] _refresh_session_li: Received ${processed.length} items from API at ${elapsed}ms.`
                );

            if (try_cache) {
                await db_save_ae_obj_li__ae_obj({
                    db_instance: db_events,
                    table_name: 'session',
                    obj_li: processed,
                    properties_to_save,
                    log_lvl
                });
                if (log_lvl)
                    console.log(
                        `💾 [Trace] _refresh_session_li: Saved to IDB cache.`
                    );
            }

            // Fire nested loads for each session only if explicitly requested (usually only for single objects)
            if (inc_file_li || inc_presentation_li) {
                processed.forEach((s) => {
                    _handle_nested_loads(s, {
                        api_cfg,
                        inc_file_li,
                        inc_all_file_li,
                        inc_presentation_li,
                        inc_presenter_li,
                        enabled,
                        hidden,
                        limit,
                        offset,
                        try_cache,
                        log_lvl: 0
                    });
                });
            }

            return processed;
        }
    } catch (e) {
        if (log_lvl)
            console.error(`❌ [Trace] _refresh_session_li: API error:`, e);
    }
    return [];
}

export async function create_ae_obj__event_session({
    api_cfg,
    event_id,
    data_kv,
    try_cache = true,
    log_lvl = 0
}: {
    api_cfg: any;
    event_id?: string;
    data_kv: key_val;
    try_cache?: boolean;
    log_lvl?: number;
}): Promise<ae_EventSession | null> {
    if (!event_id) event_id = get(slct).event_id;
    if (!event_id) {
        console.error('create_ae_obj__event_session: event_id is required');
        return null;
    }
    const result = await api.create_nested_obj({
        api_cfg,
        for_obj_type: 'event',
        for_obj_id: event_id,
        obj_type: 'event_session',
        fields: { ...data_kv },
        log_lvl
    });
    if (result) {
        const processed = await process_ae_obj__event_session_props({
            obj_li: [result],
            log_lvl
        });
        const processed_obj = processed[0];
        if (try_cache) {
            await db_save_ae_obj_li__ae_obj({
                db_instance: db_events,
                table_name: 'session',
                obj_li: [processed_obj],
                properties_to_save,
                log_lvl
            });
        }
        return processed_obj;
    }
    return null;
}

export async function delete_ae_obj_id__event_session({
    api_cfg,
    event_id,
    event_session_id,
    method = 'delete',
    try_cache = true,
    log_lvl = 0
}: {
    api_cfg: any;
    event_id?: string;
    event_session_id: string;
    method?: 'delete' | 'soft_delete' | 'disable' | 'hide';
    try_cache?: boolean;
    log_lvl?: number;
}) {
    if (!event_id) event_id = get(slct).event_id;
    if (!event_id) {
        console.error('delete_ae_obj_id__event_session: event_id is required');
        return null;
    }
    const result = await api.delete_nested_ae_obj({
        api_cfg,
        for_obj_type: 'event',
        for_obj_id: event_id,
        obj_type: 'event_session',
        obj_id: event_session_id,
        method,
        log_lvl
    });
    if (try_cache) await db_events.session.delete(event_session_id);
    return result;
}

export async function update_ae_obj__event_session({
    api_cfg,
    event_id,
    event_session_id,
    data_kv,
    try_cache = true,
    log_lvl = 0
}: {
    api_cfg: any;
    event_id?: string;
    event_session_id: string;
    data_kv: key_val;
    try_cache?: boolean;
    log_lvl?: number;
}): Promise<ae_EventSession | null> {
    if (!event_id) event_id = get(slct).event_id;
    if (!event_id) {
        console.error('update_ae_obj__event_session: event_id is required');
        return null;
    }
    const result = await api.update_nested_obj({
        api_cfg,
        for_obj_type: 'event',
        for_obj_id: event_id,
        obj_type: 'event_session',
        obj_id: event_session_id,
        fields: data_kv,
        log_lvl
    });
    if (result) {
        const processed = await process_ae_obj__event_session_props({
            obj_li: [result],
            log_lvl
        });
        const processed_obj = processed[0];
        if (try_cache) {
            await db_save_ae_obj_li__ae_obj({
                db_instance: db_events,
                table_name: 'session',
                obj_li: [processed_obj],
                properties_to_save,
                log_lvl
            });
        }
        return processed_obj;
    }
    return null;
}

export async function search__event_session({
    api_cfg,
    event_id,
    fulltext_search_qry_str = '',
    ft_presenter_search_qry_str = '',
    ft_presentation_search_qry_str = '',
    like_search_qry_str = '',
    like_presentation_search_qry_str = '',
    like_presenter_search_qry_str = '',
    like_poc_name_qry_str = '',
    location_name = null,
    qry_files = null,
    qry_poc_agree = null,
    qry_poc_kv_json = null,
    qry_start_datetime = null,
    enabled = 'enabled',
    hidden = 'not_hidden',
    view = 'default',
    limit = 50,
    offset = 0,
    order_by_li = [{ sort: 'ASC' }, { start_datetime: 'ASC' }, { name: 'ASC' }],
    try_cache = true,
    log_lvl = 0
}: {
    api_cfg: any;
    event_id: string;
    fulltext_search_qry_str?: string;
    ft_presenter_search_qry_str?: string | null;
    ft_presentation_search_qry_str?: string | null;
    like_search_qry_str?: string;
    like_presentation_search_qry_str?: string;
    like_presenter_search_qry_str?: string;
    like_poc_name_qry_str?: string;
    location_name?: null | string;
    qry_files?: null | boolean;
    qry_poc_agree?: null | boolean;
    qry_poc_kv_json?: null | boolean;
    qry_start_datetime?: string | null;
    enabled?: 'enabled' | 'all' | 'not_enabled';
    hidden?: 'hidden' | 'all' | 'not_hidden';
    view?: string;
    limit?: number;
    offset?: number;
    order_by_li?: any;
    try_cache?: boolean;
    log_lvl?: number;
}): Promise<ae_EventSession[]> {
    const search_query: any = {
        q: '',
        and: [{ field: 'event_id', op: 'eq', value: event_id }]
    };
    if (fulltext_search_qry_str || ft_presenter_search_qry_str || ft_presentation_search_qry_str) {
        const ft: any = {};
        if (fulltext_search_qry_str && fulltext_search_qry_str.length > 2)
            ft['default_qry_str'] = fulltext_search_qry_str;
        if (
            ft_presenter_search_qry_str &&
            ft_presenter_search_qry_str.length > 2
        ) {
            ft['event_presenter_li_qry_str'] = ft_presenter_search_qry_str;
            // These fields only exist in v_event_session_w_file_count (alt view)
            view = 'alt';
        }
        if (
            ft_presentation_search_qry_str &&
            ft_presentation_search_qry_str.length > 2
        ) {
            ft['event_presentation_li_qry_str'] = ft_presentation_search_qry_str;
            // These fields only exist in v_event_session_w_file_count (alt view)
            view = 'alt';
        }
        if (Object.keys(ft).length) search_query.params = { ft_qry: ft };
    }
    if (enabled === 'enabled')
        search_query.and.push({ field: 'enable', op: 'eq', value: 1 });
    else if (enabled === 'not_enabled')
        search_query.and.push({ field: 'enable', op: 'eq', value: 0 });
    if (location_name) {
        search_query.and.push({
            field: 'event_location_name',
            op: 'eq',
            value: location_name
        });
    }

    // qry_files: true = sessions WITH files (file_count_all > 0)
    //            false = sessions WITHOUT files (file_count_all IS NULL)
    // Uses file_count_all which covers files linked to the session AND its
    // presentations/presenters — so a session only shows as "without files"
    // if no one under it has uploaded anything.
    // Requires the 'alt' view (v_event_session_w_file_count) for file_count_all.
    // NULL vs 0: LEFT JOIN returns NULL for sessions with no matching files — not 0.
    if (qry_files === true) {
        view = 'alt';
        search_query.and.push({ field: 'file_count_all', op: 'gt', value: 0 });
    } else if (qry_files === false) {
        view = 'alt';
        search_query.and.push({ field: 'file_count_all', op: 'is_null' });
    }

    const result_li = await api.search_ae_obj({
        api_cfg,
        obj_type: 'event_session',
        search_query,
        order_by_li,
        view,
        limit,
        offset,
        hidden,
        log_lvl
    });

    // Handle V3 API envelope
    let valid_result_li: ae_EventSession[] = [];
    if (Array.isArray(result_li)) {
        valid_result_li = result_li;
    } else if (
        result_li &&
        typeof result_li === 'object' &&
        Array.isArray((result_li as any).data)
    ) {
        valid_result_li = (result_li as any).data;
    }

    if (valid_result_li && valid_result_li.length > 0) {
        const processed = await process_ae_obj__event_session_props({
            obj_li: valid_result_li,
            log_lvl
        });
        if (try_cache) {
            await db_save_ae_obj_li__ae_obj({
                db_instance: db_events,
                table_name: 'session',
                obj_li: processed,
                properties_to_save,
                log_lvl
            });
        }
        return processed;
    }
    return [];
}

export const qry__event_session = search__event_session;

export async function email_sign_in__event_session({
    api_cfg,
    to_email,
    to_name,
    base_url,
    person_id,
    person_passcode,
    event_id,
    event_session_id,
    session_name
}: {
    api_cfg: any;
    to_email: string;
    to_name: string;
    base_url: string;
    person_id: string;
    person_passcode: string;
    event_id: string;
    event_session_id: string;
    session_name: string;
}) {
    const subject = `Pres Mgmt Hub Sign In Link for ${session_name}`;
    // Per-param encodeURIComponent is required for query values — encodeURI() does not
    // encode '+', which URLSearchParams.get() then decodes as a space, breaking email
    // addresses that contain '+' (e.g. test+alias@example.com).
    const sign_in_url = `${base_url}/events/${event_id}/session/${event_session_id}?person_id=${encodeURIComponent(person_id ?? '')}&person_pass=${encodeURIComponent(person_passcode ?? '')}&session_id=${encodeURIComponent(event_session_id ?? '')}`;
    const body_html = `<div>${to_name},<p>Your sign-in link for ${session_name}: <a href="${sign_in_url}">${sign_in_url}</a></p></div>`;
    return await api.send_email({
        api_cfg,
        from_email: 'noreply+presmgmt@oneskyit.com',
        from_name: 'Aether Pres Mgmt',
        to_email,
        subject,
        body_html
    });
}

export const properties_to_save = [
    'id',
    'event_session_id',
    'external_id',
    'code',
    'for_type',
    'for_id',
    'type_code',
    'event_id',
    'event_location_id',
    'poc_person_id',
    'poc_agree',
    'poc_kv_json',
    'name',
    'description',
    'start_datetime',
    'end_datetime',
    'passcode',
    'hide_event_launcher',
    'alert',
    'alert_msg',
    'data_json',
    'ux_mode',
    'enable',
    'hide',
    'priority',
    'sort',
    'group',
    'notes',
    'created_on',
    'updated_on',
    'tmp_sort_1',
    'tmp_sort_2',
    'file_count',
    'file_count_all',
    'internal_use_count',
    'event_file_id_li_json',
    'poc_person_given_name',
    'poc_person_family_name',
    'poc_person_full_name',
    'poc_person_primary_email',
    'poc_person_passcode',
    'event_name',
    'event_location_code',
    'event_location_name',
    'event_presentation_li',
    'event_presentation_li_qry_str',
    'event_presenter_li_qry_str'
];

async function _process_generic_props<T extends Record<string, any>>({
    obj_li,
    obj_type,
    log_lvl = 0,
    specific_processor
}: {
    obj_li: T[];
    obj_type: string;
    log_lvl?: number;
    specific_processor?: (obj: T) => Promise<T> | T;
}): Promise<T[]> {
    if (!obj_li || obj_li.length === 0) return [];
    const processed_obj_li: T[] = [];
    for (const original_obj of obj_li) {
        let processed_obj = { ...original_obj };
        const baseIdKey = `${obj_type}_id`;
        if (processed_obj[baseIdKey])
            (processed_obj as any).id = processed_obj[baseIdKey];

        const group = processed_obj.group ?? '0';
        const priority = processed_obj.priority ? 1 : 0;
        const sort = processed_obj.sort ?? '0';
        const updated =
            processed_obj.updated_on ??
            processed_obj.created_on ??
            new Date(0).toISOString();
        const name = processed_obj.name ?? '';
        (processed_obj as any).tmp_sort_1 =
            `${group}_${priority}_${sort}_${updated}`;
        (processed_obj as any).tmp_sort_2 =
            `${group}_${priority}_${sort}_${name}_${updated}`;
        if (specific_processor)
            processed_obj = await Promise.resolve(
                specific_processor(processed_obj)
            );
        processed_obj_li.push(processed_obj as T);
    }
    return processed_obj_li;
}

export async function process_ae_obj__event_session_props({
    obj_li,
    log_lvl = 0
}: {
    obj_li: any[];
    log_lvl?: number;
}) {
    return _process_generic_props({
        obj_li,
        obj_type: 'event_session',
        log_lvl
    });
}
