/**
 * Limits Controller
 * API endpoints for viewing usage limits
 */

import { BaseController } from '../baseController';
import { RouteContext } from '../../types/route-context';
import { checkUsageAndBalance, isCloudflareGatewayLimitsEnabled } from '../../../services/rate-limit';
import { CloudflareAccountService } from '../../../services/cloudflare/CloudflareAccountService';
import { UserService } from '../../../database/services/UserService';
import { createLogger } from '../../../logger';

export class LimitsController extends BaseController {
	static logger = createLogger('LimitsController');

	/**
	 * GET /api/limits/usage
	 * Get current usage and limits for the authenticated user
	 */
	static async getUsage(
		request: Request,
		env: Env,
		_ctx: ExecutionContext,
		context: RouteContext,
	): Promise<Response> {
		const user = context.user;
		if (!user) {
			return LimitsController.createErrorResponse('Authentication required', 401);
		}

		try {
			// Token is read from the HttpOnly cookie inside checkUsageAndBalance.
			const accountService = new CloudflareAccountService(env);
			const userService = new UserService(env);
			const [usageResult, selectedGateway, aiGatewayPref] = await Promise.all([
				checkUsageAndBalance(env, user.id, request),
				accountService.getSelectedGatewayWithAccount(user.id),
				userService.getAiGatewayPreference(user.id),
			]);
			// A gateway is "configured" for usage purposes only when one is connected
			// AND the user has the AI Gateway toggle enabled; otherwise platform limits
			// apply. The raw connection state is surfaced separately for the toggle UI.
			const aiGatewayConnected = !!selectedGateway;
			const hasCfConfigured = aiGatewayConnected && aiGatewayPref.enabled;

			const window = usageResult.windowKind ?? 'rolling';
			const unlimited = !Number.isFinite(usageResult.limit);
			const used = unlimited ? 0 : usageResult.limit - usageResult.remaining;
			// Omit `config.limit` when unlimited: a finite `maxValue` is part of
			// the client contract, but `Infinity` serialises to `null` in JSON
			// and would give clients a misleading `maxValue: null` with
			// `unlimited: false` semantics everywhere else.
			const response = LimitsController.createSuccessResponse({
				cloudflareConnectEnabled: isCloudflareGatewayLimitsEnabled(env),
				config: {
					...(unlimited ? {} : {
						limit: {
							type: 'credits' as const,
							window,
							maxValue: usageResult.limit,
							enabled: true,
							periodSeconds: usageResult.periodSeconds,
							resetAt: usageResult.resetAt,
						},
					}),
					unlimited,
				},
				usage: {
					credits: {
						[window]: used,
					},
				},
				limitCheck: {
					withinLimits: usageResult.withinLimits,
					exceededLimits: usageResult.withinLimits ? [] : [{
						type: 'credits',
						window,
						current: used,
						max: usageResult.limit,
						percentUsed: Number.isFinite(usageResult.limit) && usageResult.limit > 0
							? (used / usageResult.limit) * 100
							: 0,
					}],
					message: usageResult.withinLimits ? 'Within limits' : 'Limit exceeded',
				},
				hasUserToken: usageResult.hasUserToken,
				hasCloudflareConfigured: hasCfConfigured,
				aiGatewayConnected,
				aiGatewayEnabled: aiGatewayPref.enabled,
				aiGatewayPreferenceExplicit: aiGatewayPref.isExplicit,
				cloudflareCredits: usageResult.balance !== null ? {
					credits: usageResult.balance,
					currency: 'USD',
					...(selectedGateway ? {
						accountId: selectedGateway.account.accountId,
						gatewayName: selectedGateway.gateway.gatewayName,
						accountName: selectedGateway.account.accountName,
					} : {}),
				} : null,
			});
			if (usageResult.refreshedCookie) {
				response.headers.append('Set-Cookie', usageResult.refreshedCookie);
			}
			return response;
		} catch (error) {
			this.logger.error('Error getting usage', error);
			return LimitsController.createErrorResponse(
				error instanceof Error ? error.message : 'Failed to get usage',
				500,
			);
		}
	}
}
