import axios from 'axios';
import https from 'node:https';
import { buildAuthHeaders } from './auth.js';
import { logger } from '../utils/logger.js';
export class ApiError extends Error {
    status;
    response;
    constructor(message, status, response) {
        super(message);
        this.status = status;
        this.response = response;
        this.name = 'ApiError';
    }
}
/**
 * Построение полного URL для SimpleOne Table API
 * Базовый путь: /rest/v1/table/
 */
function buildApiUrl(baseUrl) {
    if (baseUrl.includes('/rest/v1/table')) {
        return baseUrl.endsWith('/') ? baseUrl : baseUrl + '/';
    }
    const path = '/rest/v1/table/';
    return baseUrl.endsWith('/')
        ? baseUrl + path
        : baseUrl + path;
}
/**
 * HTTP-клиент для SimpleOne REST API
 */
export class SimpleOneClient {
    client;
    baseUrl;
    constructor(config) {
        this.baseUrl = buildApiUrl(config.baseUrl);
        this.client = axios.create({
            baseURL: this.baseUrl,
            timeout: config.timeout ?? 30000,
            headers: {
                'Content-Type': 'application/json',
                'Accept': 'application/json',
                ...buildAuthHeaders(config)
            },
            httpsAgent: new https.Agent({
                rejectUnauthorized: false
            })
        });
    }
    /**
     * Построение URL для ресурса
     */
    buildResourceUrl(tableName, id) {
        const table = tableName.startsWith('/') ? tableName.slice(1) : tableName;
        if (id) {
            return `${table}/${id}`;
        }
        return table;
    }
    /**
     * Формирование query строки с правильным кодированием для SimpleOne
     */
    buildQueryString(params) {
        if (!params || Object.keys(params).length === 0)
            return '';
        // Для SimpleOne важно кодировать только специальные символы, но не ^ и =
        return '?' + Object.entries(params).map(([key, value]) => {
            // Кодируем ключ и значение, но сохраняем ^ и = для условий
            const encodedValue = value
                .split('')
                .map(char => {
                if (char === '^' || char === '=') {
                    return char; // Сохраняем операторы
                }
                return encodeURIComponent(char);
            })
                .join('');
            return `${encodeURIComponent(key)}=${encodedValue}`;
        }).join('&');
    }
    /**
     * GET запрос с прямым формированием URL
     */
    async get(endpoint, params) {
        const queryString = this.buildQueryString(params);
        const fullUrl = `${this.baseUrl}${endpoint}${queryString}`;
        logger.trace('GET запрос', { endpoint, params, url: fullUrl });
        try {
            const response = await this.client.get(fullUrl, {
                // Передаём baseURL явно, чтобы axios не добавлял его повторно
                baseURL: undefined
            });
            logger.trace('GET ответ', { endpoint, status: response.status });
            return response.data;
        }
        catch (error) {
            const axiosError = error;
            logger.error('GET запрос не удался', { endpoint, error: axiosError.message });
            throw error;
        }
    }
    /**
     * POST запрос
     */
    async post(endpoint, data) {
        logger.trace('POST запрос', { endpoint, data });
        try {
            const response = await this.client.post(endpoint, data);
            logger.trace('POST ответ', { endpoint, status: response.status });
            return response.data;
        }
        catch (error) {
            const axiosError = error;
            logger.error('POST запрос не удался', { endpoint, error: axiosError.message });
            throw error;
        }
    }
    /**
     * PATCH запрос (частичное обновление)
     */
    async patch(endpoint, data) {
        logger.trace('PATCH запрос', { endpoint, data });
        try {
            const response = await this.client.patch(endpoint, data);
            logger.trace('PATCH ответ', { endpoint, status: response.status });
            return response.data;
        }
        catch (error) {
            const axiosError = error;
            logger.error('PATCH запрос не удался', { endpoint, error: axiosError.message });
            throw error;
        }
    }
    /**
     * PUT запрос (полное обновление)
     */
    async put(endpoint, data) {
        logger.trace('PUT запрос', { endpoint, data });
        try {
            const response = await this.client.put(endpoint, data);
            logger.trace('PUT ответ', { endpoint, status: response.status });
            return response.data;
        }
        catch (error) {
            const axiosError = error;
            logger.error('PUT запрос не удался', { endpoint, error: axiosError.message });
            throw error;
        }
    }
    /**
     * DELETE запрос
     */
    async delete(endpoint) {
        logger.trace('DELETE запрос', { endpoint });
        try {
            const response = await this.client.delete(endpoint);
            logger.trace('DELETE ответ', { endpoint, status: response.status });
            return response.data;
        }
        catch (error) {
            const axiosError = error;
            logger.error('DELETE запрос не удался', { endpoint, error: axiosError.message });
            throw error;
        }
    }
    /**
     * Чтение ресурса (список или по ID)
     */
    async readResource(tableName, id, params) {
        const url = this.buildResourceUrl(tableName, id);
        const urlParams = {};
        if (params?.query) {
            urlParams.sysparm_query = params.query;
        }
        if (params?.limit !== undefined) {
            urlParams.sysparm_limit = params.limit.toString();
        }
        if (params?.page !== undefined) {
            urlParams.sysparm_page = params.page.toString();
        }
        if (params?.no_count !== undefined) {
            urlParams.sysparm_no_count = params.no_count ? 'true' : 'false';
        }
        if (params?.display_value) {
            urlParams.sysparm_display_value = params.display_value;
        }
        if (params?.exclude_reference_link !== undefined) {
            urlParams.sysparm_exclude_reference_link = params.exclude_reference_link ? '1' : '0';
        }
        if (params?.fields) {
            urlParams.sysparm_fields = params.fields;
        }
        if (params?.view) {
            urlParams.sysparm_view = params.view;
        }
        return this.get(url, urlParams);
    }
    /**
     * Создание ресурса
     */
    async createResource(tableName, data, params) {
        const url = this.buildResourceUrl(tableName);
        const urlParams = {};
        if (params?.display_value) {
            urlParams.sysparm_display_value = params.display_value;
        }
        if (params?.exclude_reference_link !== undefined) {
            urlParams.sysparm_exclude_reference_link = params.exclude_reference_link ? '1' : '0';
        }
        if (params?.fields) {
            urlParams.sysparm_fields = params.fields;
        }
        if (params?.view) {
            urlParams.sysparm_view = params.view;
        }
        const queryString = this.buildQueryString(urlParams);
        const fullUrl = url + queryString;
        return this.post(fullUrl, data);
    }
    /**
     * Обновление ресурса (частичное, PATCH)
     */
    async updateResource(tableName, id, data, params) {
        const url = this.buildResourceUrl(tableName, id);
        const urlParams = {};
        if (params?.display_value) {
            urlParams.sysparm_display_value = params.display_value;
        }
        if (params?.exclude_reference_link !== undefined) {
            urlParams.sysparm_exclude_reference_link = params.exclude_reference_link ? '1' : '0';
        }
        if (params?.fields) {
            urlParams.sysparm_fields = params.fields;
        }
        if (params?.view) {
            urlParams.sysparm_view = params.view;
        }
        const queryString = this.buildQueryString(urlParams);
        const fullUrl = url + queryString;
        return this.patch(fullUrl, data);
    }
    /**
     * Обновление ресурса (полное, PUT)
     */
    async putResource(tableName, id, data, params) {
        const url = this.buildResourceUrl(tableName, id);
        const urlParams = {};
        if (params?.display_value) {
            urlParams.sysparm_display_value = params.display_value;
        }
        if (params?.exclude_reference_link !== undefined) {
            urlParams.sysparm_exclude_reference_link = params.exclude_reference_link ? '1' : '0';
        }
        if (params?.fields) {
            urlParams.sysparm_fields = params.fields;
        }
        if (params?.view) {
            urlParams.sysparm_view = params.view;
        }
        const queryString = this.buildQueryString(urlParams);
        const fullUrl = url + queryString;
        return this.put(fullUrl, data);
    }
    /**
     * Удаление ресурса
     */
    async deleteResource(tableName, id) {
        const url = this.buildResourceUrl(tableName, id);
        await this.delete(url);
    }
}
//# sourceMappingURL=client.js.map