import axios, {} from "axios";
class ApiClientService {
    instance;
    tokenProvider;
    constructor(config) {
        this.instance = axios.create({
            baseURL: config?.baseURL ?? "",
            timeout: config?.timeout ?? 15000,
            headers: {
                "Content-Type": "application/json",
                ...config?.headers,
            },
        });
        this.setupInterceptors();
    }
    setupInterceptors() {
        // Request interceptor para inyectar el token automáticamente
        this.instance.interceptors.request.use((config) => {
            const token = this.tokenProvider?.();
            if (token && config.headers) {
                // Manejo compatible con diferentes versiones de axios
                if ("set" in config.headers &&
                    typeof config.headers.set === "function") {
                    config.headers.set("Authorization", `Bearer ${token}`);
                }
                else {
                    const headers = config.headers;
                    headers.Authorization = `Bearer ${token}`;
                }
            }
            return config;
        }, (error) => {
            return Promise.reject(error);
        });
        // Response interceptor para manejo de errores (opcional, puede extenderse)
        this.instance.interceptors.response.use((response) => response, (error) => {
            return Promise.reject(error);
        });
    }
    /**
     * Establece el proveedor de token que se usará en todas las peticiones
     * @param provider Función que retorna el token de autorización
     */
    setTokenProvider(provider) {
        this.tokenProvider = provider;
    }
    /**
     * Limpia el proveedor de token
     */
    clearTokenProvider() {
        this.tokenProvider = undefined;
    }
    /**
     * Actualiza la configuración por defecto del cliente
     */
    updateDefaults(config) {
        if (config.baseURL) {
            this.instance.defaults.baseURL = config.baseURL;
        }
        if (config.timeout) {
            this.instance.defaults.timeout = config.timeout;
        }
        if (config.headers) {
            // Actualizar headers comunes de forma segura
            Object.assign(this.instance.defaults.headers.common || {}, config.headers);
        }
    }
    async axiosRequest({ method, url, headers, body, params, }) {
        return await this.instance({
            method,
            headers,
            url,
            data: body,
            params,
        });
    }
    /**
     * Realiza una petición GET
     */
    async get(options) {
        const { url, params, headers } = options;
        const response = await this.axiosRequest({
            method: "GET",
            url,
            params,
            headers,
        });
        return response.data;
    }
    /**
     * Realiza una petición POST
     */
    async post(options) {
        const { url, body, headers } = options;
        const response = await this.axiosRequest({
            method: "POST",
            url,
            headers,
            body,
        });
        return response.data;
    }
    /**
     * Realiza una petición PUT
     */
    async put(options) {
        const { url, body, headers } = options;
        const response = await this.axiosRequest({
            method: "PUT",
            url,
            headers,
            body,
        });
        return response.data;
    }
    /**
     * Realiza una petición DELETE
     */
    async del(options) {
        const { url, headers } = options;
        const response = await this.axiosRequest({
            method: "DELETE",
            url,
            headers,
        });
        return response.data;
    }
    /**
     * Obtiene un archivo como Blob
     */
    async getFile(options) {
        const { url, headers = {} } = options;
        const response = await this.instance.get(url, {
            responseType: "blob",
            headers,
        });
        return {
            data: response.data,
            headers: response.headers,
        };
    }
    /**
     * Obtiene un archivo y retorna su URL como objeto
     */
    async getFileAsUrl(options) {
        const { data } = await this.getFile(options);
        const blob = new Blob([data], { type: data.type });
        return URL.createObjectURL(blob);
    }
    /**
     * Abre un archivo en una nueva ventana
     */
    async openFile(options) {
        const { data } = await this.getFile(options);
        const urlData = URL.createObjectURL(data);
        window.open(urlData);
    }
    /**
     * Descarga un archivo
     */
    async downloadFile(options) {
        const { data, headers: dataHeaders } = await this.getFile(options);
        const contentDisposition = dataHeaders["content-disposition"] || dataHeaders["Content-Disposition"];
        const fileName = contentDisposition
            ?.split("filename=")[1]
            ?.split(";")[0]
            .replaceAll('"', "");
        const blob = new Blob([data], { type: data.type });
        const link = document.createElement("a");
        link.href = window.URL.createObjectURL(blob);
        link.setAttribute("download", fileName || "");
        document.body.appendChild(link);
        link.click();
        link.parentNode?.removeChild(link);
    }
    /**
     * Sube uno o más archivos usando FormData
     */
    async uploadFile(options) {
        const { url, files, headers } = options;
        const formData = new FormData();
        const { paramName = "file", ...newHeaders } = headers || {};
        const fileArray = Array.from(files);
        for (const file of fileArray) {
            formData.append(paramName, file, file.name);
        }
        const response = await this.instance.post(url, formData, {
            headers: newHeaders,
        });
        return response.data;
    }
}
// Instancia compartida del cliente
const sharedClient = new ApiClientService();
/**
 * Cliente de API compartido con todas las funciones de HTTP
 */
export const apiClient = sharedClient;
/**
 * Crea una nueva instancia del cliente de API
 */
export const createApiClient = (config) => {
    return new ApiClientService(config);
};
/**
 * Establece el proveedor de token global para el cliente compartido
 */
export const setApiClientTokenProvider = (provider) => {
    sharedClient.setTokenProvider(provider);
};
/**
 * Limpia el proveedor de token global
 */
export const clearApiClientTokenProvider = () => {
    sharedClient.clearTokenProvider();
};
