import { browser } from '$app/environment';
import { ae_auth_error } from '$lib/stores/ae_stores';
import type { key_val } from '$lib/stores/ae_stores';

/**
 * Performs a DELETE request to the Aether API.
 * Refactored 2026-01-08 to use standard fetch with timeout, custom fetch injection,
 * standardized kebab-case headers, and robust V3 response handling.
 */
export const delete_object = async function delete_object({
    api_cfg = null,
    endpoint = '',
    headers = {},
    params = {},
    data = {},
    timeout = 20000,
    return_meta = false,
    log_lvl = 0,
    retry_count = 5
}: {
    api_cfg: any;
    endpoint: string;
    headers?: any;
    params?: any;
    data?: any;
    timeout?: number;
    return_meta?: boolean;
    log_lvl?: number;
    retry_count?: number;
}) {
    if (log_lvl) {
        console.log(`*** delete_object() *** Endpoint: ${endpoint}`);
        console.log('Params:', params);
        if (log_lvl > 1) {
            console.log('Data:', data);
            console.log(`Base URL: ${api_cfg?.['base_url']}`);
        }
    }

    if (!api_cfg) {
        console.error('No API Config was provided. Returning false.');
        return false;
    }

    // Construct the URL with query parameters
    const url = new URL(endpoint, api_cfg['base_url']);
    if (params) {
        Object.keys(params).forEach((key) =>
            url.searchParams.append(key, params[key])
        );
    }

    // Clean and merge headers without mutating the original api_cfg
    const headers_cleaned: key_val = {};
    const merged_headers = { ...api_cfg['headers'], ...headers };

    // Handle "Bootstrap Paradox" for unauthenticated requests
    if (merged_headers.hasOwnProperty('x-no-account-id')) {
        delete merged_headers['x-account-id'];
        if (merged_headers['x-no-account-id'] === null) {
            merged_headers['x-no-account-id'] = 'Nothing to See Here';
        }
    }

    for (const prop in merged_headers) {
        const prop_cleaned = prop.replaceAll('_', '-');
        let value = merged_headers[prop];
        if (value === null || value === undefined) continue;

        if (typeof value !== 'string') {
            value = JSON.stringify(value);
        }
        headers_cleaned[prop_cleaned] = value;
    }

    // Auto-inject Authorization header if JWT is present but header is missing
    const jwt =
        headers_cleaned['jwt'] || headers_cleaned['JWT'] || api_cfg['jwt'];
    if (
        jwt &&
        !headers_cleaned['Authorization'] &&
        !headers_cleaned['authorization']
    ) {
        headers_cleaned['Authorization'] = `Bearer ${jwt}`;
    }

    headers_cleaned['Content-Type'] = 'application/json';

    if (log_lvl > 1) {
        console.log('Final cleaned headers:', headers_cleaned);
    }

    let fetch_method: any = fetch;
    if (api_cfg.fetch) {
        if (log_lvl > 1) {
            console.log('Using custom fetch function from api_cfg!!!');
        }
        fetch_method = api_cfg.fetch;
    }

    for (let attempt = 1; attempt <= retry_count; attempt++) {
        // Keep timeout handle at attempt scope so catch can always clear it.
        let timeoutId: ReturnType<typeof setTimeout> | null = null;
        try {
            const controller = new AbortController();
            // AbortError alone is ambiguous. Track helper-timeout aborts so
            // caller/navigation aborts can still fail fast with no retry.
            let did_timeout_abort = false;
            timeoutId = setTimeout(() => {
                did_timeout_abort = true;
                console.error(
                    `API DELETE request timed out after ${timeout}ms.`
                );
                controller.abort();
            }, timeout);

            const fetchOptions: RequestInit = {
                method: 'DELETE',
                headers: headers_cleaned,
                body:
                    Object.keys(data).length > 0
                        ? JSON.stringify(data)
                        : undefined,
                signal: controller.signal
            };

            const response = await fetch_method(
                url.toString(),
                fetchOptions
            ).catch(function (error: any) {
                if (
                    error?.name === 'AbortError' ||
                    error?.name === 'TypeError' ||
                    error?.message?.includes('aborted')
                ) {
                    if (log_lvl > 1) {
                        console.log(
                            'API DELETE: Request aborted or browser-terminated.',
                            error
                        );
                    }
                    return error;
                }

                console.log(
                    'API DELETE Object *fetch* request was aborted or failed in an unexpected way.',
                    error
                );
                return error;
            });
            if (timeoutId) clearTimeout(timeoutId);

            // Error object was returned from fetch catch block; decide retry class.
            if (
                response instanceof Error ||
                (response &&
                    (response.name === 'AbortError' ||
                        response.name === 'TypeError'))
            ) {
                if (response.name === 'AbortError') {
                    if (did_timeout_abort) {
                        throw new Error(
                            `Timeout abort (attempt ${attempt}/${retry_count}) after ${timeout}ms`
                        );
                    }
                    return false;
                }

                throw new Error(
                    `Network error (attempt ${attempt}): ${response.message}`
                );
            }

            if (!response) {
                throw new Error(
                    `HTTP fetch request was aborted or failed in an unexpected way! URL = ${url.toString()}`
                );
            }

            if (log_lvl) {
                console.log(
                    `Response: status=${response.status} attempt=${attempt}`
                );
            }

            if (!response.ok) {
                if (response.status === 404) {
                    console.warn('404 Not Found. Returning null.');
                    return null;
                }

                const errorBody = await response.text();
                console.error(
                    `HTTP error! status: ${response.status}`,
                    errorBody
                );

                // Fail fast on client/auth/validation failures.
                if (
                    response.status === 400 ||
                    response.status === 401 ||
                    response.status === 403 ||
                    response.status === 422
                ) {
                    if (response.status === 401 || response.status === 403) {
                        console.warn(
                            `AUTH DIAGNOSTICS (DELETE): Headers sent for ${endpoint}:`,
                            {
                                has_api_key: !!headers_cleaned['x-aether-api-key'],
                                has_account_id: !!headers_cleaned['x-account-id']
                            }
                        );
                        // Signal the root layout to show the session-expired banner.
                        if (browser) ae_auth_error.set({ type: 'expired', ts: Date.now() });
                    }
                    return false;
                }

                throw new Error(
                    `HTTP error! status: ${response.status} - ${errorBody}`
                );
            }

            const json = await response.json();

            if (log_lvl > 1) {
                console.log('Response JSON:', json);
            }

            // Return the response data or metadata
            // Robustly handle V3 response envelopes
            return return_meta
                ? json
                : json.data !== undefined
                  ? json.data
                  : json;
        } catch (error) {
            // Ensure per-attempt timeout is always cleared on failure.
            if (timeoutId) clearTimeout(timeoutId);
            console.error(`API DELETE error on attempt ${attempt}:`, error);

            if (attempt === retry_count) {
                console.error('Max retry attempts reached. Returning false.');
                return false;
            }

            // Backoff before retrying. Caps at 8s to match GET/POST/PATCH policy.
            const delay_ms = Math.min(2000 * attempt, 8000);
            console.log(
                `API DELETE: Retrying in ${delay_ms}ms... (attempt ${attempt}/${retry_count})`
            );
            await new Promise<void>((resolve) => setTimeout(resolve, delay_ms));
        }
    }
};
