import type { key_val } from '$lib/stores/ae_stores';
import { post_object } from './api_post_object';
import { patch_object } from './api_patch_object';
import { delete_object } from './api_delete_object';

const JSON_PRETTY_SPACES = 2;

function serialize_json_field_pretty(value: unknown) {
    if (value === null || value === undefined) return value;

    if (typeof value === 'string') {
        try {
            return JSON.stringify(JSON.parse(value), null, JSON_PRETTY_SPACES);
        } catch {
            return value;
        }
    }

    return JSON.stringify(value, null, JSON_PRETTY_SPACES);
}

/**
 * --- POST (CREATE) WRAPPERS ---
 */

interface CreateAeObjV3Params {
    api_cfg: any;
    obj_type: string;
    fields: key_val;
    params?: key_val;
    log_lvl?: number;
}

export async function create_ae_obj({
    api_cfg,
    obj_type,
    fields,
    params = {},
    log_lvl = 0
}: CreateAeObjV3Params) {
    const endpoint = `/v3/crud/${obj_type}/`;

    if (log_lvl) {
        console.log('*** create_ae_obj ***');
        console.log('Endpoint:', endpoint);
        console.log('Fields:', fields);
    }

    // Standard Aether Pattern: Auto-serialize any key ending in _json
    const cleaned_fields = { ...fields };
    for (const key in cleaned_fields) {
        if (key.endsWith('_json') && cleaned_fields[key] !== null) {
            if (log_lvl) console.log(`Auto-serializing field: ${key}`);
            cleaned_fields[key] = serialize_json_field_pretty(
                cleaned_fields[key]
            );
        }
    }

    if (log_lvl) {
        console.log('Cleaned Fields (Final):', cleaned_fields);
    }

    return await post_object({
        api_cfg,
        endpoint,
        params,
        data: cleaned_fields,
        log_lvl
    });
}

interface CreateNestedObjV3Params {
    api_cfg: any;
    parent_type?: string;
    parent_id?: string;
    child_type?: string;
    // Aliases for migration
    for_obj_type?: string;
    for_obj_id?: string;
    obj_type?: string;

    fields: key_val;
    params?: key_val;
    log_lvl?: number;
}

export async function create_nested_obj({
    api_cfg,
    parent_type,
    parent_id,
    child_type,
    for_obj_type,
    for_obj_id,
    obj_type,
    fields,
    params = {},
    log_lvl = 0
}: CreateNestedObjV3Params) {
    const p_type = parent_type || for_obj_type;
    const p_id = parent_id || for_obj_id;
    const c_type = child_type || obj_type;

    const endpoint = `/v3/crud/${p_type}/${p_id}/${c_type}/`;

    if (log_lvl) {
        console.log('*** create_nested_obj ***');
        console.log('Endpoint:', endpoint);
        console.log('Fields:', fields);
    }

    // Standard Aether Pattern: Auto-serialize any key ending in _json
    const cleaned_fields = { ...fields };
    for (const key in cleaned_fields) {
        if (key.endsWith('_json') && cleaned_fields[key] !== null) {
            cleaned_fields[key] = serialize_json_field_pretty(
                cleaned_fields[key]
            );
        }
    }

    return await post_object({
        api_cfg,
        endpoint,
        params,
        data: cleaned_fields,
        log_lvl
    });
}

/**
 * --- PATCH (UPDATE) WRAPPERS ---
 */

interface UpdateAeObjV3Params {
    api_cfg: any;
    obj_type: string;
    obj_id: string;
    fields: key_val;
    params?: key_val;
    log_lvl?: number;
}

export async function update_ae_obj({
    api_cfg,
    obj_type,
    obj_id,
    fields,
    params = {},
    log_lvl = 0
}: UpdateAeObjV3Params) {
    const endpoint = `/v3/crud/${obj_type}/${obj_id}`;

    if (log_lvl) {
        console.log('*** update_ae_obj ***');
        console.log('Endpoint:', endpoint);
        console.log('Fields:', fields);
    }

    // Standard Aether Pattern: Auto-serialize any key ending in _json
    const cleaned_fields = { ...fields };
    for (const key in cleaned_fields) {
        if (key.endsWith('_json') && cleaned_fields[key] !== null) {
            if (log_lvl > 1) console.log(`Auto-serializing field: ${key}`);
            cleaned_fields[key] = serialize_json_field_pretty(
                cleaned_fields[key]
            );
        }
    }

    return await patch_object({
        api_cfg,
        endpoint,
        params,
        data: cleaned_fields,
        log_lvl
    });
}

interface UpdateNestedObjV3Params {
    api_cfg: any;
    parent_type?: string;
    parent_id?: string;
    child_type?: string;
    child_id?: string;
    // Aliases for migration
    for_obj_type?: string;
    for_obj_id?: string;
    obj_type?: string;
    obj_id?: string;

    fields: key_val;
    params?: key_val;
    log_lvl?: number;
}

export async function update_nested_obj({
    api_cfg,
    parent_type,
    parent_id,
    child_type,
    child_id,
    for_obj_type,
    for_obj_id,
    obj_type,
    obj_id,
    fields,
    params = {},
    log_lvl = 0
}: UpdateNestedObjV3Params) {
    const p_type = parent_type || for_obj_type;
    const p_id = parent_id || for_obj_id;
    const c_type = child_type || obj_type;
    const c_id = child_id || obj_id;

    const endpoint = `/v3/crud/${p_type}/${p_id}/${c_type}/${c_id}`;

    if (log_lvl) {
        console.log('*** update_nested_obj ***');
        console.log('Endpoint:', endpoint);
        console.log('Fields:', fields);
    }

    // Standard Aether Pattern: Auto-serialize any key ending in _json
    const cleaned_fields = { ...fields };
    for (const key in cleaned_fields) {
        if (key.endsWith('_json') && cleaned_fields[key] !== null) {
            cleaned_fields[key] = serialize_json_field_pretty(
                cleaned_fields[key]
            );
        }
    }

    return await patch_object({
        api_cfg,
        endpoint,
        params,
        data: cleaned_fields,
        log_lvl
    });
}

/**
 * --- DELETE WRAPPERS ---
 */

interface DeleteAeObjV3Params {
    api_cfg: any;
    obj_type: string;
    obj_id: string;
    method?: 'delete' | 'soft_delete' | 'disable' | 'hide';
    params?: key_val;
    log_lvl?: number;
}

/**
 * Delete a single object by ID (V3)
 * Supports 'delete' (hard), 'soft_delete', 'disable' (enable=false), and 'hide' (hide=true).
 */
export async function delete_ae_obj({
    api_cfg,
    obj_type,
    obj_id,
    method = 'delete',
    params = {},
    log_lvl = 0
}: DeleteAeObjV3Params) {
    const endpoint = `/v3/crud/${obj_type}/${obj_id}`;
    const query_params = { ...params, method };

    if (log_lvl) {
        console.log('*** delete_ae_obj ***');
        console.log('Endpoint:', endpoint);
        console.log('Params:', query_params);
    }

    return await delete_object({
        api_cfg,
        endpoint,
        params: query_params,
        log_lvl
    });
}

interface DeleteNestedAeObjV3Params {
    api_cfg: any;
    parent_type?: string;
    parent_id?: string;
    child_type?: string;
    child_id?: string;
    // Aliases for migration
    for_obj_type?: string;
    for_obj_id?: string;
    obj_type?: string;
    obj_id?: string;

    method?: 'delete' | 'soft_delete' | 'disable' | 'hide';
    params?: key_val;
    log_lvl?: number;
}

/**
 * Delete a single nested object by ID (V3)
 */
export async function delete_nested_ae_obj({
    api_cfg,
    parent_type,
    parent_id,
    child_type,
    child_id,
    for_obj_type,
    for_obj_id,
    obj_type,
    obj_id,
    method = 'delete',
    params = {},
    log_lvl = 0
}: DeleteNestedAeObjV3Params) {
    const p_type = parent_type || for_obj_type;
    const p_id = parent_id || for_obj_id;
    const c_type = child_type || obj_type;
    const c_id = child_id || obj_id;

    const endpoint = `/v3/crud/${p_type}/${p_id}/${c_type}/${c_id}`;
    const query_params = { ...params, method };

    if (log_lvl) {
        console.log('*** delete_nested_ae_obj ***');
        console.log('Endpoint:', endpoint);
        console.log('Params:', query_params);
    }

    return await delete_object({
        api_cfg,
        endpoint,
        params: query_params,
        log_lvl
    });
}
