/**
 * Transak API utilities — shared across rFlows and rCart.
 *
 * Uses the Secure Widget URL API (mandatory since 2025):
 *   1. Get a Partner Access Token via refresh-token endpoint (cached 7 days)
 *   2. Call the gateway session endpoint with widget params
 *   3. Return the widgetUrl containing a single-use sessionId
 *
 * Environment: TRANSAK_ENV controls staging vs production.
 * API keys are split: TRANSAK_API_KEY_STAGING / TRANSAK_API_KEY_PRODUCTION
 * (falls back to legacy TRANSAK_API_KEY if per-env keys aren't set).
 */

export type TransakEnv = 'STAGING' | 'PRODUCTION';

// Both token refresh and session creation go through the gateway
const GATEWAY_URLS = {
	STAGING: 'https://api-gateway-stg.transak.com',
	PRODUCTION: 'https://api-gateway.transak.com',
} as const;

// Fallback: legacy partner API (if gateway token refresh fails)
const API_URLS = {
	STAGING: 'https://api-stg.transak.com',
	PRODUCTION: 'https://api.transak.com',
} as const;

// Cached access token (valid for 7 days)
let _cachedToken: { token: string; expiresAt: number; env: TransakEnv } | null = null;

/** Get the current Transak environment */
export function getTransakEnv(): TransakEnv {
	return (process.env.TRANSAK_ENV as TransakEnv) || 'STAGING';
}

/** Get the API key for the current Transak environment */
export function getTransakApiKey(): string {
	const env = getTransakEnv();
	return (env === 'PRODUCTION'
		? process.env.TRANSAK_API_KEY_PRODUCTION
		: process.env.TRANSAK_API_KEY_STAGING
	) || process.env.TRANSAK_API_KEY || '';
}

/** Get the API secret for the current Transak environment */
export function getTransakApiSecret(): string {
	const env = getTransakEnv();
	return (env === 'PRODUCTION'
		? process.env.TRANSAK_WEBHOOK_SECRET_PRODUCTION
		: process.env.TRANSAK_WEBHOOK_SECRET_STAGING
	) || process.env.TRANSAK_WEBHOOK_SECRET || '';
}

/** Get the webhook secret for the current Transak environment */
export function getTransakWebhookSecret(): string {
	return getTransakApiSecret();
}

/** Extract root domain from a hostname (e.g. "demo.rspace.online" → "rspace.online") */
export function extractRootDomain(host: string): string {
	const parts = host.replace(/:\d+$/, '').split('.');
	return parts.length > 2 ? parts.slice(-2).join('.') : parts.join('.');
}

/**
 * Get a Partner Access Token (cached for 7 days).
 * Calls the refresh-token endpoint only when the cached token has expired.
 */
async function getAccessToken(): Promise<string> {
	const env = getTransakEnv();
	const now = Math.floor(Date.now() / 1000);

	if (_cachedToken && _cachedToken.env === env && _cachedToken.expiresAt > now + 60) {
		return _cachedToken.token;
	}

	const apiKey = getTransakApiKey();
	const apiSecret = getTransakApiSecret();
	if (!apiKey || !apiSecret) throw new Error('Transak API key or secret not configured');

	const body = JSON.stringify({ apiKey });
	const headers = { 'Content-Type': 'application/json', 'api-secret': apiSecret };

	// Try gateway first (required for production session tokens), then legacy API
	const urls = [
		`${GATEWAY_URLS[env]}/partners/api/v2/refresh-token`,
		`${API_URLS[env]}/partners/api/v2/refresh-token`,
	];

	let lastError = '';
	for (const url of urls) {
		try {
			const res = await fetch(url, { method: 'POST', headers, body });
			if (!res.ok) {
				lastError = `${url}: ${res.status} ${await res.text()}`;
				console.warn(`[transak] Token refresh failed at ${url}: ${res.status}`);
				continue;
			}
			const data = await res.json() as { data: { accessToken: string; expiresAt: number } };
			_cachedToken = {
				token: data.data.accessToken,
				expiresAt: data.data.expiresAt,
				env,
			};
			console.log(`[transak] Access token refreshed from ${url} (env=${env}, expires=${new Date(data.data.expiresAt * 1000).toISOString()})`);
			return _cachedToken.token;
		} catch (err) {
			lastError = `${url}: ${err}`;
			console.warn(`[transak] Token refresh error at ${url}:`, err);
		}
	}

	throw new Error(`Transak refresh-token failed on all endpoints: ${lastError}`);
}

/**
 * Create a Secure Widget URL via the Transak gateway session API.
 * Returns a URL with a single-use sessionId (valid for 5 minutes).
 */
export async function createSecureWidgetUrl(
	widgetParams: Record<string, unknown>,
): Promise<string> {
	const env = getTransakEnv();
	const accessToken = await getAccessToken();
	const gatewayUrl = GATEWAY_URLS[env];

	const res = await fetch(`${gatewayUrl}/api/v2/auth/session`, {
		method: 'POST',
		headers: {
			'Content-Type': 'application/json',
			'access-token': accessToken,
		},
		body: JSON.stringify({ widgetParams }),
	});

	if (!res.ok) {
		const err = await res.text();
		console.error(`[transak] Gateway session failed (${res.status}):`, err);
		// Fall back to direct URL construction if gateway fails (e.g. IP not whitelisted)
		console.warn('[transak] Falling back to direct widget URL');
		return createTransakWidgetUrl(widgetParams as Record<string, string>);
	}

	const data = await res.json() as { data: { widgetUrl: string } };
	return data.data.widgetUrl;
}

/** Legacy: build widget URL from query parameters (fallback only) */
export function createTransakWidgetUrl(params: Record<string, string>): string {
	const env = getTransakEnv();
	const base = env === 'PRODUCTION'
		? 'https://global.transak.com'
		: 'https://global-stg.transak.com';

	const url = new URL(base);
	for (const [key, value] of Object.entries(params)) {
		if (value != null && value !== '') {
			url.searchParams.set(key, String(value));
		}
	}

	return url.toString();
}
