import { generateInternalServiceToken } from "../utils/internal-service-auth.js";

//#region src/api-client/base-client.ts
/**
* Shared base API client for making HTTP requests
* Used by both CLI and SDK to ensure consistent API communication
*
* This is a thin wrapper around fetch that provides consistent header handling.
* Implementations should construct Authorization headers and pass them via options.
*/
/**
* Makes an HTTP request with consistent header defaults
*
* @param url - The URL to fetch
* @param options - Standard fetch options (headers will be merged with defaults)
* @returns Promise<Response>
*
* @example
* ```typescript
* // With Authorization header
* const response = await apiFetch('https://api.example.com/data', {
*   method: 'POST',
*   headers: {
*     Authorization: 'Bearer your-api-key'
*   },
*   body: JSON.stringify({ data: 'value' })
* });
*
* // Without Authorization
* const response = await apiFetch('https://api.example.com/public', {
*   method: 'GET'
* });
* ```
*/
async function apiFetch(url, options = {}) {
	const headers = {
		"Content-Type": "application/json",
		Accept: "application/json",
		...options.headers || {}
	};
	return fetch(url, {
		...options,
		headers
	});
}
var BaseApiError = class extends Error {
	constructor(message, statusCode, responseBody) {
		super(message);
		this.statusCode = statusCode;
		this.responseBody = responseBody;
		this.name = "BaseApiError";
	}
	get isNotFound() {
		return this.statusCode === 404;
	}
	get isUnauthorized() {
		return this.statusCode === 401;
	}
	get isForbidden() {
		return this.statusCode === 403;
	}
};
var BaseApiClient = class {
	apiUrl;
	tenantId;
	projectId;
	apiKey;
	isCI;
	internalServiceName;
	ref;
	userId;
	userEmail;
	constructor(config) {
		this.apiUrl = config.apiUrl;
		this.tenantId = config.tenantId;
		this.projectId = config.projectId;
		this.apiKey = config.auth.mode === "apiKey" ? config.auth.apiKey : void 0;
		this.isCI = config.auth.mode === "apiKey" ? config.auth.isCI ?? false : false;
		this.internalServiceName = config.auth.mode === "internalService" ? config.auth.internalServiceName : void 0;
		this.ref = config.ref;
		this.userId = config.userId;
		this.userEmail = config.userEmail;
	}
	checkTenantId() {
		if (!this.tenantId) throw new Error("No tenant ID configured. Please run: inkeep init");
		return this.tenantId;
	}
	/**
	* Builds a URL from the base API URL and a path
	* Supports optional ref and pagination query parameters
	*/
	buildUrl(path, params) {
		const normalizedBase = this.apiUrl.replace(/\/$/, "");
		const url = new URL(`${normalizedBase}${path}`);
		if (this.ref !== void 0 && this.ref !== "main") url.searchParams.set("ref", this.ref);
		if (params?.page !== void 0) url.searchParams.set("page", String(params.page));
		if (params?.limit !== void 0) url.searchParams.set("limit", String(params.limit));
		return url.toString();
	}
	/**
	* Gets auth headers for requests
	* Handles both internal service JWT tokens and API key authentication
	*/
	async getAuthHeaders() {
		const tenantId = this.checkTenantId();
		if (this.internalServiceName) return { Authorization: `Bearer ${await generateInternalServiceToken({
			serviceId: this.internalServiceName,
			tenantId,
			projectId: this.projectId,
			userId: this.userId
		})}` };
		if (this.apiKey) {
			if (this.isCI) return { "X-API-Key": this.apiKey };
			return { Authorization: `Bearer ${this.apiKey}` };
		}
		return {};
	}
	/**
	* Wrapper around fetch that automatically includes auth header
	* Uses X-API-Key for CI mode, Authorization Bearer for interactive mode
	* @deprecated Use getAuthHeaders() with apiFetch() instead for more flexibility
	*/
	async authenticatedFetch(url, options = {}) {
		const headers = { ...options.headers || {} };
		if (this.apiKey) if (this.isCI) headers["X-API-Key"] = this.apiKey;
		else headers.Authorization = `Bearer ${this.apiKey}`;
		return apiFetch(url, {
			...options,
			headers
		});
	}
	/**
	* Creates an error instance for failed requests
	* Override in subclasses to return specific error types
	*/
	createError(message, statusCode, responseBody) {
		return new BaseApiError(message, statusCode, responseBody);
	}
	/**
	* Extracts data from a successful response
	* Override in subclasses if the API wraps responses (e.g., { data: ... })
	*/
	async extractResponseData(response) {
		return response.json();
	}
	/**
	* Makes a GET request with authentication
	*/
	async makeGetRequest(path, errorContext) {
		const response = await apiFetch(this.buildUrl(path), {
			method: "GET",
			headers: await this.getAuthHeaders()
		});
		if (!response.ok) {
			const errorBody = await response.text().catch(() => "Unknown error");
			throw this.createError(`${errorContext}: ${response.status} ${response.statusText}`, response.status, errorBody);
		}
		return this.extractResponseData(response);
	}
	/**
	* Makes a POST request with authentication
	*/
	async makePostRequest(path, body, errorContext) {
		const response = await apiFetch(this.buildUrl(path), {
			method: "POST",
			headers: {
				...await this.getAuthHeaders(),
				"Content-Type": "application/json"
			},
			body: JSON.stringify(body)
		});
		if (!response.ok) {
			const errorBody = await response.text().catch(() => "Unknown error");
			throw this.createError(`${errorContext}: ${response.status} ${response.statusText}`, response.status, errorBody);
		}
		return this.extractResponseData(response);
	}
	/**
	* Makes paginated GET requests and collects all results
	*/
	async makePaginatedGetRequest(path, errorContext, pageSize = 100) {
		const allItems = [];
		let currentPage = 1;
		const headers = await this.getAuthHeaders();
		while (true) {
			const response = await apiFetch(this.buildUrl(path, {
				page: currentPage,
				limit: pageSize
			}), {
				method: "GET",
				headers
			});
			if (!response.ok) {
				const errorBody = await response.text().catch(() => "Unknown error");
				throw this.createError(`${errorContext}: ${response.status} ${response.statusText}`, response.status, errorBody);
			}
			const json = await response.json();
			allItems.push(...json.data);
			if (currentPage >= json.pagination.pages) break;
			currentPage++;
		}
		return allItems;
	}
	getTenantId() {
		return this.tenantId;
	}
	getProjectId() {
		return this.projectId;
	}
	getApiUrl() {
		return this.apiUrl;
	}
	getIsCI() {
		return this.isCI;
	}
};

//#endregion
export { BaseApiClient, BaseApiError, apiFetch };