import type { key_val } from '$lib/stores/ae_stores';
import { get_object } from './api_get_object';

// Refactored 2025-11-13 to use a lookup map for endpoints.
const objTypeToEndpointMap: Record<string, string> = {
    account: '/crud/account/list',
    address: '/crud/address/list',
    archive: '/crud/archive/list',
    archive_content: '/crud/archive/content/list',
    activity_log: '/crud/activity_log/list',
    contact: '/crud/contact/list',
    data_store: '/crud/data_store/list',
    event: '/crud/event/list',
    event_abstract: '/crud/event/abstract/list',
    event_badge: '/crud/event/badge/list',
    event_badge_template: '/crud/event/badge/template/list',
    event_device: '/crud/event/device/list',
    event_exhibit: '/crud/event/exhibit/list',
    event_exhibit_tracking: '/crud/event/exhibit/tracking/list',
    event_file: '/crud/event/file/list',
    event_location: '/crud/event/location/list',
    event_person: '/crud/event/person/list',
    event_presentation: '/crud/event/presentation/list',
    event_presenter: '/crud/event/presenter/list',
    event_session: '/crud/event/session/list',
    event_track: '/crud/event/track/list',
    grant: '/crud/grant/list',
    hosted_file: '/crud/hosted_file/list',
    journal: '/crud/journal/list',
    journal_entry: '/crud/journal/entry/list',
    order: '/crud/order/list',
    order_line: '/crud/order/line/list',
    page: '/crud/page/list',
    person: '/crud/person/list',
    post: '/crud/post/list',
    post_comment: '/crud/post/comment/list',
    site: '/crud/site/list',
    sponsorship_cfg: '/crud/sponsorship/cfg/list',
    sponsorship: '/crud/sponsorship/list',
    // user: '/crud/user/list',
    'lu-country_subdivision': '/crud/lu/country_subdivision/list',
    'lu-country': '/crud/lu/country/list',
    'lu-time_zone': '/crud/lu/time_zone/list'
};

function getEndpointForObjType(obj_type: string, for_obj_type?: string): string {
    if (obj_type === 'lu' && for_obj_type) {
        const key = `lu-${for_obj_type}`;
        const endpoint = objTypeToEndpointMap[key];
        if (endpoint) return endpoint;
    }

    const endpoint = objTypeToEndpointMap[obj_type];
    if (endpoint) return endpoint;

    throw new Error(`Unknown object type: ${obj_type}`);
}

type OrderBy = { [key: string]: 'ASC' | 'DESC' };

interface GetAeObjLiForObjIdCrudV2Params {
    api_cfg: any; // Consider defining a specific type for api_cfg
    obj_type: string;
    for_obj_type: string;
    for_obj_id?: string;
    use_alt_tbl?: boolean | string;
    use_alt_mdl?: boolean | string;
    use_alt_exp?: boolean | string;
    inc?: key_val;
    enabled?: 'all' | 'enabled' | 'not_enabled';
    hidden?: 'all' | 'hidden' | 'not_hidden';
    order_by_li?: OrderBy | OrderBy[] | null;
    limit?: number;
    offset?: number;
    headers?: Record<string, string>;
    params_json?: any;
    params?: key_val;
    log_lvl?: number;
}

export async function get_ae_obj_li_for_obj_id_crud_v2({
    api_cfg,
    obj_type,
    for_obj_type,
    for_obj_id,
    use_alt_tbl = false,
    use_alt_mdl = false,
    use_alt_exp = false,
    enabled = 'enabled',
    hidden = 'not_hidden',
    order_by_li = null,
    limit = 999999,
    offset = 0,
    headers = {},
    params_json = null,
    params = {},
    log_lvl = 0
}: GetAeObjLiForObjIdCrudV2Params) {
    if (log_lvl) {
        console.log('*** get_ae_obj_li_for_obj_id_crud_v2() ***');
    }

    try {
        const endpoint = `/v2${getEndpointForObjType(obj_type, for_obj_type)}`;
        if (log_lvl) {
            console.log('Endpoint:', endpoint);
        }

        // We need to remove a few parameters from the params object that are not allowed.
        delete params['qry__enabled'];
        delete params['qry__hidden'];
        delete params['qry__limit'];
        delete params['qry__offset'];

        if (for_obj_type) params['for_obj_type'] = for_obj_type;
        if (for_obj_id) params['for_obj_id'] = for_obj_id;

        if (use_alt_tbl === true) params['tbl_alt'] = 'alt';
        if (use_alt_mdl === true) params['mdl_alt'] = 'alt';
        if (use_alt_exp === true) params['exp_alt'] = 'alt';

        const allowed_enabled_list = ['all', 'enabled', 'not_enabled'];
        if (allowed_enabled_list.includes(enabled)) {
            params['enabled'] = enabled;
        }

        const allowed_hidden_list = ['all', 'hidden', 'not_hidden'];
        if (allowed_hidden_list.includes(hidden)) {
            params['hidden'] = hidden;
        }

        // NOTE: The order_by_li variable is in the "headers" because URL GET params do not handle complex objects very well.
        if (order_by_li) {
            headers['order_by_li'] = JSON.stringify(order_by_li);
        }

        if (limit > 0) params['limit'] = limit;
        if (offset > 0) params['offset'] = offset;

        if (params_json) {
            // NOTE: "jp" stands for "JSON Params". This is a JSON object that needs to be safely converted to a string for the params.
            // Max characters for a GET request is ~2000. This is a limitation of the browser.
            const json_params_str = encodeURIComponent(JSON.stringify(params_json));
            if (json_params_str.length > 2083) {
                // Using console.error instead of throwing an error to avoid crashing the app for a known limitation.
                console.error(
                    `The JSON object is too large to be used as a GET parameter. Max length is 2083 characters. Length = ${json_params_str.length}`
                );
                return false;
            }
            params['jp'] = json_params_str;
        }

        if (log_lvl) {
            console.log('Params:', params);
        }

        const object_li_get_promise = await get_object({
            api_cfg: api_cfg,
            endpoint: endpoint,
            headers: headers,
            params: params,
            log_lvl: log_lvl
        });

        if (log_lvl > 1) {
            console.log(object_li_get_promise);
        }

        return object_li_get_promise;
    } catch (error) {
        console.error('Error in get_ae_obj_li_for_obj_id_crud_v2:', error);
        return false; // Or handle the error as appropriate
    }
}
