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

import { db_save_ae_obj_li__ae_obj } from '$lib/ae_core/core__idb_dexie';
import { db_core } from '$lib/ae_core/db_core';
import type { ae_Site, ae_SiteDomain } from '$lib/types/ae_types';

const ae_promises: key_val = {};

/**
 * --- SITE CRUD ---
 */

// Legacy version
// export async function lookup_site_domain({
//     api_cfg,
//     fqdn,
//     view = 'default',
//     log_lvl = 0
// }: {
//     api_cfg: any;
//     fqdn: string;
//     view?: string;
//     log_lvl?: number;
// }): Promise<ae_SiteDomain | null> {
//     if (log_lvl) {
//         console.log(`*** lookup_site_domain() *** fqdn=${fqdn}`);
//     }

//     try {
//         // We use get_ae_obj_id_crud because we are looking up by a unique field (fqdn) rather than ID.
//         // This is the older method that uses the /crud/site/domain/:id endpoint.
//         const result = await api.get_ae_obj_id_crud({
//             api_cfg,
//             no_account_id: true,
//             obj_type: 'site_domain',
//             obj_id: fqdn,
//             use_alt_table: true,
//             use_alt_base: true,
//             log_lvl
//         });

//         if (result) {
//             // Standardize and save to cache
//             const processed_obj_li = await process_ae_obj__site_domain_props({
//                 obj_li: [result],
//                 log_lvl
//             });
//             await db_save_ae_obj_li__ae_obj({
//                 db_instance: db_core,
//                 table_name: 'site_domain',
//                 obj_li: processed_obj_li,
//                 properties_to_save: properties_to_save__site_domain,
//                 log_lvl
//             });
//             return result;
//         }
//     } catch (error: any) {
//         console.log('Site domain lookup failed (API Error).', error);
//     }

//     if (log_lvl) console.log('Attempting to load site domain from local cache...');
//     const cached = await db_core.site_domain.where('fqdn').equals(fqdn).first();

//     if (cached) {
//         return cached as any;
//     }

//     // CRITICAL FALLBACK: If both API and Cache fail, return a "Ghost" site domain object
//     // to prevent the 403 error from blocking the UI. Page components will handle empty data.
//     console.error('AE_SITE_CRITICAL: Site domain lookup failed API and CACHE. Returning ghost object.');
//     return {
//         id: 'ghost',
//         id_random: 'ghost',
//         site_domain_id: 'ghost',
//         site_domain_id_random: 'ghost',
//         site_id: 'ghost',
//         site_id_random: 'ghost',
//         account_id: 'ghost',
//         account_id_random: 'ghost',
//         account_code: 'ghost',
//         account_name: 'Ghost Account (Offline)',
//         fqdn: fqdn,
//         enable: '1',
//         header_image_path: '',
//         style_href: '',
//         google_tracking_id: '',
//         access_code_kv_json: {},
//         cfg_json: {},
//         access_key: '',
//         site_domain_access_key: ''
//     } as any;
// }

// Updated 2026-01-26 (Cache-First Optimization)
export async function lookup_site_domain({
    api_cfg,
    fqdn,
    view = 'default',
    log_lvl = 0,
    access_key
}: {
    api_cfg: any;
    fqdn: string;
    view?: string;
    log_lvl?: number;
    access_key?: string;
}): Promise<ae_SiteDomain | null> {
    if (log_lvl) {
        console.log(`*** lookup_site_domain() *** fqdn=${fqdn} (Cache-First)`);
    }

    // 1. FAST PATH: Check local cache first.
    // Skip when access_key is provided — the key must be validated server-side.
    // A stale cached entry with a previously-valid key must not grant access if the
    // URL key has changed or been revoked.
    if (!access_key) {
        try {
            const cached = await db_core.site_domain.where('fqdn').equals(fqdn).first();
            if (cached) {
                if (log_lvl)
                    console.log(
                        'BOOTSTRAP: Cache hit. Returning cached site domain immediately.'
                    );

                // Trigger background refresh to keep cache fresh, but don't await it
                _refresh_site_domain_background({
                    api_cfg,
                    fqdn,
                    view,
                    log_lvl: 0,
                    access_key
                });

                return cached as ae_SiteDomain;
            }
        } catch (err) {
            console.warn('BOOTSTRAP: Cache read failed.', err);
        }
    }

    // 2. SLOW PATH: Wait for API if cache is empty
    return await _refresh_site_domain_background({
        api_cfg,
        fqdn,
        view,
        log_lvl,
        access_key
    });
}

/**
 * Internal helper to perform the actual API fetch and cache update
 */
async function _refresh_site_domain_background({
    api_cfg,
    fqdn,
    view,
    log_lvl,
    access_key
}: any) {
    try {
        const guest_api_cfg = { ...api_cfg };
        guest_api_cfg.headers = { ...api_cfg.headers };

        const auth_props = [
            'x-account-id',
            'Authorization',
            'authorization',
            'jwt',
            'JWT'
        ];

        auth_props.forEach((prop) => {
            delete guest_api_cfg.headers[prop];
            delete guest_api_cfg.headers[prop.toLowerCase()];
            delete guest_api_cfg.headers[prop.replaceAll('-', '_')];
        });
        delete guest_api_cfg.jwt;
        delete guest_api_cfg.account_id;

        const search_query: any = {
            and: [{ field: 'fqdn', op: 'eq', value: fqdn }]
        };

        // If the caller provided an access_key (from the URL), include it
        // so the server can match restricted domains. Omit empty/falsy keys.
        if (access_key) {
            search_query.and.push({
                field: 'access_key',
                op: 'eq',
                value: access_key
            });
        }

        const result_li = await api.search_ae_obj({
            api_cfg: guest_api_cfg,
            obj_type: 'site_domain',
            search_query,
            view,
            enabled: 'enabled',
            hidden: 'all',
            limit: 1,
            log_lvl
        });

        if (result_li && result_li.length > 0) {
            const result = result_li[0];
            const processed_obj_li = await process_ae_obj__site_domain_props({
                obj_li: [result],
                log_lvl
            });
            await db_save_ae_obj_li__ae_obj({
                db_instance: db_core,
                table_name: 'site_domain',
                obj_li: processed_obj_li,
                properties_to_save: properties_to_save__site_domain,
                log_lvl
            });

            // WHY: The fast-path returns stale Dexie cache, then this background refresh
            // runs after the page renders. Push any fields that may have been missing from
            // the stale cache (e.g. account_name, cfg_json) back into $ae_loc so the UI
            // reflects the correct values without requiring a second full page reload.
            const loc_patch: Record<string, unknown> = {};

            if (result.cfg_json) {
                const current_cfg = get(ae_loc).site_cfg_json;
                if (JSON.stringify(current_cfg) !== JSON.stringify(result.cfg_json)) {
                    loc_patch.site_cfg_json = result.cfg_json;
                }
            }

            if (result.account_name) {
                const current_name = get(ae_loc).account_name;
                // Only overwrite the default placeholder — don't stomp a real value.
                if (!current_name || current_name === 'Account Name Not Set' || current_name === 'Ghost Account') {
                    loc_patch.account_name = result.account_name;
                }
            }

            if (result.account_code) {
                const current_code = get(ae_loc).account_code;
                if (!current_code || current_code === 'not_set' || current_code === 'ghost') {
                    loc_patch.account_code = result.account_code;
                }
            }

            if (Object.keys(loc_patch).length > 0) {
                ae_loc.update((loc) => ({ ...loc, ...loc_patch }));
            }

            return result;
        }
    } catch (error: any) {
        if (log_lvl) console.log('Site domain refresh V3 failed.', error);
    }
    return null;
}

export async function load_ae_obj_id__site({
    api_cfg,
    site_id,
    view = 'default',
    params = {},
    try_cache = true,
    log_lvl = 0
}: {
    api_cfg: any;
    site_id: string;
    view?: string;
    params?: key_val;
    try_cache?: boolean;
    log_lvl?: number;
}): Promise<ae_Site | null> {
    if (log_lvl) {
        console.log(`*** load_ae_obj_id__site() *** site_id=${site_id}`);
    }

    ae_promises.load__site_obj = await api
        .get_ae_obj({
            api_cfg,
            obj_type: 'site',
            obj_id: site_id,
            view,
            params,
            log_lvl
        })
        .then(async function (site_obj_get_result) {
            if (site_obj_get_result) {
                if (try_cache) {
                    const processed_obj_li = await process_ae_obj__site_props({
                        obj_li: [site_obj_get_result],
                        log_lvl: log_lvl
                    });
                    await db_save_ae_obj_li__ae_obj({
                        db_instance: db_core,
                        table_name: 'site',
                        obj_li: processed_obj_li,
                        properties_to_save: properties_to_save__site,
                        log_lvl: log_lvl
                    });
                }
                return site_obj_get_result;
            } else {
                return null;
            }
        });

    return ae_promises.load__site_obj;
}

// Updated 2026-01-06
export async function load_ae_obj_li__site({
    api_cfg,
    for_obj_type = 'account',
    for_obj_id,
    enabled = 'enabled',
    hidden = 'not_hidden',
    view = 'default',
    limit = 99,
    offset = 0,
    order_by_li = {
        priority: 'DESC',
        sort: 'DESC',
        name: 'ASC',
        updated_on: 'DESC',
        created_on: 'DESC'
    },
    params = {},
    try_cache = true,
    log_lvl = 0
}: {
    api_cfg: any;
    for_obj_type?: string;
    for_obj_id: string;
    enabled?: 'enabled' | 'all' | 'not_enabled';
    hidden?: 'hidden' | 'all' | 'not_hidden';
    view?: string;
    limit?: number;
    offset?: number;
    order_by_li?: Record<string, 'ASC' | 'DESC'>;
    params?: key_val;
    try_cache?: boolean;
    log_lvl?: number;
}): Promise<ae_Site[]> {
    if (log_lvl) {
        console.log(`*** load_ae_obj_li__site() *** for_obj_id=${for_obj_id}`);
    }

    ae_promises.load__site_obj_li = await api
        .get_ae_obj_li({
            api_cfg,
            obj_type: 'site',
            for_obj_type,
            for_obj_id,
            enabled,
            hidden,
            view,
            limit,
            offset,
            order_by_li,
            log_lvl
        })
        .then(async function (site_obj_li_get_result) {
            if (site_obj_li_get_result) {
                if (try_cache) {
                    const processed_obj_li = await process_ae_obj__site_props({
                        obj_li: site_obj_li_get_result,
                        log_lvl: log_lvl
                    });
                    await db_save_ae_obj_li__ae_obj({
                        db_instance: db_core,
                        table_name: 'site',
                        obj_li: processed_obj_li,
                        properties_to_save: properties_to_save__site,
                        log_lvl: log_lvl
                    });
                }
                return site_obj_li_get_result;
            } else {
                return [];
            }
        });

    return ae_promises.load__site_obj_li;
}

// Updated 2026-01-06
export async function create_ae_obj__site({
    api_cfg,
    account_id,
    data_kv,
    params = {},
    try_cache = true,
    log_lvl = 0
}: {
    api_cfg: any;
    account_id: string;
    data_kv: key_val;
    params?: key_val;
    try_cache?: boolean;
    log_lvl?: number;
}): Promise<ae_Site | null> {
    const result = await api.create_ae_obj({
        api_cfg,
        obj_type: 'site',
        fields: {
            account_id_random: account_id,
            ...data_kv
        },
        params,
        log_lvl
    });

    if (result && try_cache) {
        const processed_obj_li = await process_ae_obj__site_props({
            obj_li: [result],
            log_lvl: log_lvl
        });
        await db_save_ae_obj_li__ae_obj({
            db_instance: db_core,
            table_name: 'site',
            obj_li: processed_obj_li,
            properties_to_save: properties_to_save__site,
            log_lvl: log_lvl
        });
    }

    return result;
}

// Updated 2026-01-06
export async function update_ae_obj__site({
    api_cfg,
    site_id,
    data_kv,
    params = {},
    try_cache = true,
    log_lvl = 0
}: {
    api_cfg: any;
    site_id: string;
    data_kv: key_val;
    params?: key_val;
    try_cache?: boolean;
    log_lvl?: number;
}): Promise<ae_Site | null> {
    const result = await api.update_ae_obj({
        api_cfg,
        obj_type: 'site',
        obj_id: site_id,
        fields: data_kv,
        params,
        log_lvl
    });

    if (result && try_cache) {
        const processed_obj_li = await process_ae_obj__site_props({
            obj_li: [result],
            log_lvl: log_lvl
        });
        await db_save_ae_obj_li__ae_obj({
            db_instance: db_core,
            table_name: 'site',
            obj_li: processed_obj_li,
            properties_to_save: properties_to_save__site,
            log_lvl: log_lvl
        });
    }

    return result;
}

// Updated 2026-01-06
export async function delete_ae_obj_id__site({
    api_cfg,
    site_id,
    method = 'delete',
    params = {},
    try_cache = true,
    log_lvl = 0
}: {
    api_cfg: any;
    site_id: string;
    method?: 'delete' | 'soft_delete' | 'disable' | 'hide';
    params?: key_val;
    try_cache?: boolean;
    log_lvl?: number;
}) {
    const result = await api.delete_ae_obj({
        api_cfg,
        obj_type: 'site',
        obj_id: site_id,
        method,
        params,
        log_lvl
    });

    if (try_cache) {
        await db_core.site.delete(site_id);
    }

    return result;
}

/**
 * --- SITE DOMAIN CRUD ---
 */

// Updated 2026-01-06
export async function load_ae_obj_li__site_domain({
    api_cfg,
    site_id,
    enabled = 'enabled',
    hidden = 'not_hidden',
    view = 'default',
    limit = 99,
    offset = 0,
    order_by_li = { domain: 'ASC' },
    params = {},
    try_cache = true,
    log_lvl = 0
}: {
    api_cfg: any;
    site_id: string;
    enabled?: 'enabled' | 'all' | 'not_enabled';
    hidden?: 'hidden' | 'all' | 'not_hidden';
    view?: string;
    limit?: number;
    offset?: number;
    order_by_li?: Record<string, 'ASC' | 'DESC'>;
    params?: key_val;
    try_cache?: boolean;
    log_lvl?: number;
}): Promise<ae_SiteDomain[]> {
    ae_promises.load__site_domain_li = await api
        .get_nested_obj_li({
            api_cfg,
            parent_type: 'site',
            parent_id: site_id,
            child_type: 'site_domain',
            enabled,
            hidden,
            view,
            limit,
            offset,
            order_by_li,
            log_lvl
        })
        .then(async function (domain_li) {
            if (domain_li) {
                if (try_cache) {
                    const processed_obj_li =
                        await process_ae_obj__site_domain_props({
                            obj_li: domain_li,
                            site_id,
                            log_lvl
                        });
                    await db_save_ae_obj_li__ae_obj({
                        db_instance: db_core,
                        table_name: 'site_domain',
                        obj_li: processed_obj_li,
                        properties_to_save: properties_to_save__site_domain,
                        log_lvl
                    });
                }
                return domain_li;
            } else {
                return [];
            }
        });

    return ae_promises.load__site_domain_li;
}

// Updated 2026-01-06
export async function create_ae_obj__site_domain({
    api_cfg,
    site_id,
    data_kv,
    params = {},
    try_cache = true,
    log_lvl = 0
}: {
    api_cfg: any;
    site_id: string;
    data_kv: key_val;
    params?: key_val;
    try_cache?: boolean;
    log_lvl?: number;
}): Promise<ae_SiteDomain | null> {
    const result = await api.create_nested_obj({
        api_cfg,
        parent_type: 'site',
        parent_id: site_id,
        child_type: 'site_domain',
        fields: data_kv,
        params,
        log_lvl
    });

    if (result && try_cache) {
        const processed_obj_li = await process_ae_obj__site_domain_props({
            obj_li: [result],
            site_id,
            log_lvl
        });
        await db_save_ae_obj_li__ae_obj({
            db_instance: db_core,
            table_name: 'site_domain',
            obj_li: processed_obj_li,
            properties_to_save: properties_to_save__site_domain,
            log_lvl
        });
    }

    return result;
}

// Updated 2026-01-06
export async function update_ae_obj__site_domain({
    api_cfg,
    site_id,
    site_domain_id,
    data_kv,
    params = {},
    try_cache = true,
    log_lvl = 0
}: {
    api_cfg: any;
    site_id: string;
    site_domain_id: string;
    data_kv: key_val;
    params?: key_val;
    try_cache?: boolean;
    log_lvl?: number;
}): Promise<ae_SiteDomain | null> {
    const result = await api.update_nested_obj({
        api_cfg,
        parent_type: 'site',
        parent_id: site_id,
        child_type: 'site_domain',
        child_id: site_domain_id,
        fields: data_kv,
        params,
        log_lvl
    });

    if (result && try_cache) {
        const processed_obj_li = await process_ae_obj__site_domain_props({
            obj_li: [result],
            site_id,
            log_lvl
        });
        await db_save_ae_obj_li__ae_obj({
            db_instance: db_core,
            table_name: 'site_domain',
            obj_li: processed_obj_li,
            properties_to_save: properties_to_save__site_domain,
            log_lvl
        });
    }

    return result;
}

// Updated 2026-01-06
export async function delete_ae_obj_id__site_domain({
    api_cfg,
    site_id,
    site_domain_id,
    method = 'delete',
    params = {},
    try_cache = true,
    log_lvl = 0
}: {
    api_cfg: any;
    site_id: string;
    site_domain_id: string;
    method?: 'delete' | 'soft_delete' | 'disable' | 'hide';
    params?: key_val;
    try_cache?: boolean;
    log_lvl?: number;
}) {
    const result = await api.delete_nested_ae_obj({
        api_cfg,
        parent_type: 'site',
        parent_id: site_id,
        child_type: 'site_domain',
        child_id: site_domain_id,
        method,
        params,
        log_lvl
    });

    if (try_cache) {
        await db_core.site_domain.delete(site_domain_id);
    }

    return result;
}

const properties_to_save__site = [
    'id',
    'site_id',
    'site_id_random',
    'account_id',
    'account_id_random',
    'code',
    'name',
    'description',
    'restrict_access',
    'access_key',
    'access_code_kv_json',
    'logo_path',
    'logo_bg_color',
    'title',
    'tagline',
    'style_href',
    'google_tracking_id',
    'cfg_json',
    'enable',
    'enable_from',
    'enable_to',
    'hide',
    'priority',
    'sort',
    'group',
    'notes',
    'created_on',
    'updated_on',
    'tmp_sort_1',
    'tmp_sort_2'
];

const properties_to_save__site_domain = [
    'id',
    'site_domain_id',
    'site_domain_id_random',
    'site_id',
    'site_id_random',
    'account_id',
    'account_id_random',
    'account_code',
    'account_name',
    'fqdn',
    'access_key',
    'site_domain_access_key',
    'enable',
    'enable_from',
    'enable_to',
    'hide',
    'priority',
    'sort',
    'group',
    'notes',
    'header_image_path',
    'style_href',
    'google_tracking_id',
    'access_code_kv_json',
    'cfg_json',
    'created_on',
    'updated_on',
    'tmp_sort_1',
    'tmp_sort_2'
];

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 };

        for (const key in processed_obj) {
            if (key.endsWith('_random')) {
                const newKey = key.slice(0, -7);
                (processed_obj as any)[newKey] = processed_obj[key];
            }
        }
        const randomIdKey = `${obj_type}_id_random`;
        if (processed_obj[randomIdKey]) {
            (processed_obj as any).id = processed_obj[randomIdKey];
        }

        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;
        const name = processed_obj.name ?? processed_obj.fqdn ?? '';

        (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__site_props({
    obj_li,
    log_lvl = 0
}: {
    obj_li: any[];
    log_lvl?: number;
}) {
    return _process_generic_props({
        obj_li,
        obj_type: 'site',
        log_lvl
    });
}

export async function process_ae_obj__site_domain_props({
    obj_li,
    site_id,
    log_lvl = 0
}: {
    obj_li: any[];
    site_id?: string;
    log_lvl?: number;
}) {
    return _process_generic_props({
        obj_li,
        obj_type: 'site_domain',
        log_lvl,
        specific_processor: (obj) => {
            if (site_id && !obj.site_id) {
                obj.site_id = site_id;
            }
            return obj;
        }
    });
}
