import axios from "axios";
import { configStore, userInfosStore } from "../store/store";
import { BASE_SSO_URL, BASE_URL, BASE_ZDESK_URL, BASE_ZERVA_URL, BASE_ZRMZ_URL, CLOUDFRONT_S3_SSO_KEY, CLOUDFRONT_S3_SSO_URL, DEFAULT_TIMEOUT, RATE_LIMIT_MAX, RATE_LIMIT_WINDOW_MS } from "./constant";
import { getConnectionItem } from "./func";
export class RateLimitError extends Error {
    route;
    constructor(route) {
        super(`Rate limit exceeded: ${RATE_LIMIT_MAX} GET requests/second on "${route}"`);
        this.name = 'RateLimitError';
        this.route = route;
    }
}
// Stores timestamps (ms) of recent calls, per route key
const routeCallTimestamps = new Map();
function buildRouteKey(config) {
    // Use route path only — no params, no query string
    return (config.baseURL ?? '') + (config.url ?? '');
}
function isRateLimited(route) {
    const now = Date.now();
    const cutoff = now - RATE_LIMIT_WINDOW_MS;
    // Get or initialise the timestamps list for this route
    let timestamps = routeCallTimestamps.get(route) ?? [];
    // Evict entries outside the current window
    timestamps = timestamps.filter(t => t > cutoff);
    if (timestamps.length >= RATE_LIMIT_MAX) {
        // Update (already-pruned) list so memory doesn't grow unbounded
        routeCallTimestamps.set(route, timestamps);
        return true;
    }
    timestamps.push(now);
    routeCallTimestamps.set(route, timestamps);
    return false;
}
function attachDedupeInterceptors(instance) {
    // Request interceptor — enforce per-route GET rate limit
    instance.interceptors.request.use((config) => {
        if (config.method?.toUpperCase() !== 'GET')
            return config;
        // Apply rate limit only for get chats endpoint
        const urlPath = config.url?.split('?')[0] || '';
        if (!urlPath.endsWith('/chat'))
            return config;
        const route = buildRouteKey(config);
        if (isRateLimited(route)) {
            return Promise.reject(new RateLimitError(route));
        }
        return config;
    }, (error) => Promise.reject(error));
    return instance;
}
export const apiServiceSso = () => {
    const baseUrl = BASE_SSO_URL();
    return axios.create({
        headers: {
            Authorization: configStore.get('accessToken'),
        },
        baseURL: baseUrl,
        timeout: DEFAULT_TIMEOUT,
    });
};
export const apiService = () => {
    const baseUrl = BASE_URL();
    return attachDedupeInterceptors(axios.create({
        headers: {
            Authorization: configStore.get('accessToken'),
        },
        baseURL: baseUrl,
        timeout: DEFAULT_TIMEOUT,
    }));
};
export const apiServiceZrmz = () => {
    const baseUrl = BASE_ZRMZ_URL();
    return axios.create({
        headers: {
            Authorization: configStore.get('accessToken'),
        },
        baseURL: baseUrl,
        timeout: DEFAULT_TIMEOUT,
    });
};
export const apiServiceZerva = () => {
    const baseUrl = BASE_ZERVA_URL();
    return axios.create({
        headers: {
            Authorization: configStore.get('accessToken'),
        },
        baseURL: baseUrl,
        timeout: DEFAULT_TIMEOUT,
    });
};
export const apiServiceZdesk = (data) => {
    const userInfo = userInfosStore.get(data.connectionId);
    const connectionItem = getConnectionItem();
    const zdeskBusinessId = data?.businessId || (connectionItem?.type === 'zwiz' ? connectionItem?.bot_id : '');
    const baseUrl = BASE_ZDESK_URL();
    return axios.create({
        headers: {
            Authorization: `Bearer ${data?.token || userInfo?.token?.access_token || ''}`,
            ...(zdeskBusinessId && { 'z-business-id': zdeskBusinessId })
        },
        baseURL: baseUrl,
        timeout: DEFAULT_TIMEOUT,
    });
    // TODO: Add refresh token mechanism
};
export const getSignedS3Request = async (params) => {
    const { data, status } = await axios.post(CLOUDFRONT_S3_SSO_URL || '', null, {
        params,
        headers: {
            'x-api-key': CLOUDFRONT_S3_SSO_KEY || '',
        },
    });
    if (status === 200) {
        return data;
    }
    throw new Error('Failed to signed s3');
};
