import { marked } from 'marked';

import type { key_val } from '$lib/stores/ae_stores';
import { api } from '$lib/api/api';

import { db_save_ae_obj_li__ae_obj } from '$lib/ae_core/core__idb_dexie';

// Define generic CRUD args
export interface GenericCrudArgs {
    api_cfg: any;
    obj_type: string;
    obj_id?: string;
    for_obj_type?: string;
    for_obj_id?: string;

    db_instance?: any; // Optional DB instance for caching
    db_field_li?: string[]; // Optional list of fields to save in DB

    // Flags to include related core object models
    inc_account_li?: boolean;
    inc_address_li?: boolean;
    inc_contact_li?: boolean;
    inc_person_li?: boolean;
    inc_site_li?: boolean;
    inc_site_domain_li?: boolean;
    inc_user_li?: boolean;

    // Flags to include related other object models
    inc_archive_li?: boolean;
    inc_archive_entry_li?: boolean;
    inc_event_li?: boolean;
    inc_event_session_li?: boolean;
    inc_post_li?: boolean;
    inc_post_comment_li?: boolean;
    inc_journal_li?: boolean;
    inc_journal_entry_li?: boolean;

    inc_obj_type_li?: string[]; // Optional list of object types to include

    data_kv?: key_val;
    enabled?: 'enabled' | 'not_enabled' | 'all';
    hidden?: 'not_hidden' | 'hidden' | 'all';
    method?: string;
    limit?: number;
    offset?: number;
    order_by_li?: Record<string, 'ASC' | 'DESC'> | Record<string, 'ASC' | 'DESC'>[] | null;
    params?: key_val;
    try_cache?: boolean;
    log_lvl?: number;
}

// Generic function: Load single object by ID
export async function load_ae_obj_id(args: GenericCrudArgs): Promise<any> {
    const { api_cfg, obj_type, obj_id, log_lvl = 0 } = args;

    if (!obj_id) {
        if (log_lvl) console.warn('load_ae_obj_id called without obj_id');
        return null;
    }

    if (log_lvl) {
        console.log(`*** load_ae_obj_id() *** obj_type=${obj_type} obj_id=${obj_id}`);
    }

    const result = await api.get_ae_obj_id_crud({
        api_cfg,
        obj_type,
        obj_id,
        params: {},
        log_lvl
    });

    return result;
}

// Generic function: Load list of objects
export async function load_ae_obj_li(args: GenericCrudArgs): Promise<any> {
    const {
        api_cfg,
        obj_type,
        for_obj_type = '',
        for_obj_id,
        inc_obj_type_li,
        enabled = 'enabled',
        hidden = 'not_hidden',
        limit = 99,
        offset = 0,
        order_by_li = {},
        params = {},
        try_cache = true,
        log_lvl = 0
    } = args;

    if (log_lvl) {
        console.log(
            `*** load_ae_obj_li() *** obj_type=${obj_type} for_obj_type=${for_obj_type} for_obj_id=${for_obj_id}`
        );
    }

    const params_json: key_val = {};

    const result = await api.get_ae_obj_li_for_obj_id_crud_v2({
        api_cfg,
        obj_type,
        for_obj_type,
        for_obj_id: for_obj_id ?? '',
        enabled,
        hidden,
        order_by_li,
        limit,
        offset,
        params_json: {},
        params,
        log_lvl
    });

    return result;
}

// Generic function: Create object
export async function create_ae_obj(args: GenericCrudArgs): Promise<any> {
    const { api_cfg, obj_type, data_kv, log_lvl = 0 } = args;

    if (log_lvl) {
        console.log(`*** create_ae_obj() *** obj_type=${obj_type}`, data_kv);
    }

    const result = await api.create_ae_obj_crud({
        api_cfg,
        obj_type,
        fields: data_kv,
        key: api_cfg.api_crud_super_key,
        params: {},
        return_obj: true,
        log_lvl
    });

    return result;
}

// Generic function: Update object
export async function update_ae_obj(args: GenericCrudArgs): Promise<any> {
    const { api_cfg, obj_type, obj_id, data_kv, log_lvl = 0 } = args;

    if (!obj_id) {
        if (log_lvl) console.warn('update_ae_obj called without obj_id');
        return null;
    }

    if (log_lvl) {
        console.log(`*** update_ae_obj() *** obj_type=${obj_type} obj_id=${obj_id}`, data_kv);
    }

    const result = await api.update_ae_obj_id_crud({
        api_cfg,
        obj_type,
        obj_id,
        fields: data_kv,
        key: api_cfg.api_crud_super_key,
        params: {},
        return_obj: true,
        log_lvl
    });

    return result;
}

// Generic function: Delete object
export async function delete_ae_obj_id(args: GenericCrudArgs): Promise<any> {
    const { api_cfg, obj_type, obj_id, method = 'delete', log_lvl = 0 } = args;

    if (!obj_id) {
        if (log_lvl) console.warn('delete_ae_obj_id called without obj_id');
        return null;
    }

    if (log_lvl) {
        console.log(`*** delete_ae_obj_id() *** obj_type=${obj_type} obj_id=${obj_id}`);
    }

    const result = await api.delete_ae_obj_id_crud({
        api_cfg,
        obj_type,
        obj_id,
        key: api_cfg.api_crud_super_key,
        params: {},
        method,
        log_lvl
    });

    return result;
}

// Additional Modules that might be needed for reloads
import { load_ae_obj_id__archive } from '$lib/ae_archives/ae_archives__archive';
import { load_ae_obj_id__archive_content } from '$lib/ae_archives/ae_archives__archive_content';
import { load_ae_obj_id__event } from '$lib/ae_events/ae_events__event';
import { load_ae_obj_id__event_device } from '$lib/ae_events/ae_events__event_device';
import { load_ae_obj_id__event_file } from '$lib/ae_events/ae_events__event_file';
import { load_ae_obj_id__event_location } from '$lib/ae_events/ae_events__event_location';
import { load_ae_obj_id__event_presentation } from '$lib/ae_events/ae_events__event_presentation';
import { load_ae_obj_id__event_presenter } from '$lib/ae_events/ae_events__event_presenter';
import { load_ae_obj_id__event_session } from '$lib/ae_events/ae_events__event_session';
import { load_ae_obj_id__journal } from '$lib/ae_journals/ae_journals__journal';
import { load_ae_obj_id__journal_entry } from '$lib/ae_journals/ae_journals__journal_entry';
import { load_ae_obj_id__post } from '$lib/ae_posts/ae_posts__post';
import { load_ae_obj_id__post_comment } from '$lib/ae_posts/ae_posts__post_comment';
import { load_ae_obj_id__person } from '$lib/ae_core/ae_core__person';

export async function update_ae_obj_id_crud_v2({
    api_cfg,
    object_type,
    object_id,
    object_reload = false,
    field_name,
    new_field_value,
    log_lvl = 0
}: {
    api_cfg: any;
    object_type: string;
    object_id: string;
    object_reload?: boolean;
    field_name: string;
    new_field_value: any;
    log_lvl?: number;
}) {
    if (log_lvl) {
        console.log(
            `*** update_ae_obj_id_crud_v2() *** object_type=${object_type}, object_id=${object_id}, object_reload=${object_reload}, field_name=${field_name}, new_field_value=`,
            new_field_value
        );
    }

    try {
        const results = await api.update_ae_obj_id_crud({
            api_cfg: api_cfg,
            obj_type: object_type,
            obj_id: object_id,
            field_name: field_name,
            field_value: new_field_value,
            key: api_cfg.api_crud_super_key,
            log_lvl: log_lvl
        });

        if (!results) {
            console.log(
                `Not Patched - Field Name: ${field_name} with new Field Value: ${new_field_value}; Account ID: ${api_cfg.account_id}`
            );
            return false;
        }

        console.log(`Patched - Field Name: ${field_name} with new Field Value: ${new_field_value}`);

        if (object_reload) {
            if (log_lvl) console.log(`Reloading the object after patching...`);

            const reload_fns: { [key: string]: (args: any) => Promise<any> } = {
                person: load_ae_obj_id__person,
                archive: load_ae_obj_id__archive,
                archive_content: load_ae_obj_id__archive_content,
                journal: load_ae_obj_id__journal,
                journal_entry: load_ae_obj_id__journal_entry,
                event: load_ae_obj_id__event,
                event_device: load_ae_obj_id__event_device,
                event_file: load_ae_obj_id__event_file,
                event_location: load_ae_obj_id__event_location,
                event_presentation: load_ae_obj_id__event_presentation,
                event_presenter: load_ae_obj_id__event_presenter,
                event_session: load_ae_obj_id__event_session,
                post: load_ae_obj_id__post,
                post_comment: load_ae_obj_id__post_comment
            };

            const reload_fn = reload_fns[object_type];
            if (reload_fn) {
                const id_key = `${object_type}_id`;
                return await reload_fn({ api_cfg, [id_key]: object_id, log_lvl });
            }
        }

        return true;
    } catch (error) {
        console.log('Something went wrong patching the record.', error);
        return false;
    }
}

export async function download_export_li({
    api_cfg,
    get_obj_type,
    for_obj_type,
    for_obj_id,
    exp_alt = null,
    file_type = 'CSV',
    return_file = true,
    filename = 'no_filename.csv',
    auto_download = false,
    limit = 5000,
    params = {},
    log_lvl = 0
}: {
    api_cfg: any;
    get_obj_type: string;
    for_obj_type: string;
    for_obj_id: string;
    exp_alt?: null | string;
    file_type?: string;
    return_file?: boolean;
    filename?: string;
    auto_download?: boolean;
    limit?: number;
    params?: key_val;
    log_lvl?: number;
}) {
    if (log_lvl) console.log('*** download_export_li() ***');

    const endpoint = `/v2/crud/${get_obj_type}/list`;
    params['for_obj_type'] = for_obj_type;
    params['for_obj_id'] = for_obj_id;

    if (file_type === 'CSV' || file_type === 'Excel') {
        params['file_type'] = file_type;
    }
    params['return_file'] = true;
    params['mdl_alt'] = 'out';

    if (exp_alt) {
        params['exp_alt'] = exp_alt;
    }

    const clean_filename = filename.replace(/[^a-zA-Z0-9\[\]-_.]/gi, '_');

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

    const download_result = await api.get_object({
        api_cfg: api_cfg,
        endpoint: endpoint,
        params: params,
        timeout: 90000,
        return_blob: return_file,
        filename: clean_filename,
        auto_download: auto_download,
        task_id: for_obj_id,
        log_lvl: log_lvl
    });

    if (log_lvl) console.log('download_result:', download_result);
    return download_result;
}
