<?php

/**
 * LolaCore — Centralized Error Messages
 *
 * Every user-facing error string lives here. Lola's voice rules apply:
 * first person, no jargon, no emojis, no blame, one next step.
 *
 * Uses static methods (not constants) so WordPress i18n tooling
 * (WP-CLI i18n make-pot) can extract the literal strings.
 *
 * @package LolaCore
 * @license GPL-2.0-or-later
 * @since   1.1.2
 */

declare(strict_types=1);

namespace LolaCore\I18n;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

class ErrorMessages {

	// =========================================================================
	// Category 1 — Connection / Chat UI
	// =========================================================================

	/**
	 * Generic connection failure shown in the chat bubble.
	 */
	public static function connectionFailed(): string {
		return \__( "I couldn't get a response. This is usually a temporary connection issue — try sending your message again. If it keeps happening, check that your AI provider is still connected in Settings → Connectors.", 'lolacore' );
	}

	/**
	 * Tool actions executed successfully but the LLM continuation failed.
	 * Must not mislead the user into thinking the actions failed.
	 */
	public static function actionsCompletedSummaryFailed(): string {
		return \__( "Done — your changes were applied successfully. I had trouble generating a detailed summary, but everything went through. Ask me to verify if you want to double-check.", 'lolacore' );
	}

	// =========================================================================
	// Category 2 — Authentication & Security (REST API)
	// =========================================================================

	/**
	 * Nonce validation failed (session expired).
	 */
	public static function sessionExpired(): string {
		return \__( "Your session has expired. Refresh the page to continue — your conversation history is saved.", 'lolacore' );
	}

	/**
	 * User lacks required capabilities.
	 */
	public static function unauthorized(): string {
		return \__( "I can't verify your login session. This usually happens if you've been logged out of WordPress in another tab. Log back in and refresh this page.", 'lolacore' );
	}

	/**
	 * Missing session_id or message in the request.
	 */
	public static function sessionLost(): string {
		return \__( "I lost track of this conversation. Refresh the page to start a new session — I'll still remember everything from our previous sessions.", 'lolacore' );
	}

	/**
	 * Pending tool confirmation has expired.
	 */
	public static function actionExpired(): string {
		return \__( "That confirmation has expired. For safety, pending actions are only valid for a few minutes. Tell me what you need again and I'll set it up.", 'lolacore' );
	}

	/**
	 * Missing required parameters in a request.
	 */
	public static function missingParameters(): string {
		return \__( "I lost track of this conversation. Refresh the page to start a new session — I'll still remember everything from our previous sessions.", 'lolacore' );
	}

	/**
	 * Confirmation token doesn't match (memory wipe).
	 */
	public static function confirmationInvalid(): string {
		return \__( "That confirmation link is no longer valid. Go back to Settings and try the operation again.", 'lolacore' );
	}

	// =========================================================================
	// Category 3 — AI Provider (WPAIClientAdapter)
	// =========================================================================

	/**
	 * No AI provider configured in WordPress.
	 */
	public static function noProviderConfigured(): string {
		return \__( "I need an AI provider to work. Go to Settings → Connectors and connect one — OpenAI, Anthropic, or any provider available in your WordPress. It takes about 2 minutes.", 'lolacore' );
	}

	/**
	 * Failed to load a model from a provider.
	 *
	 * @param string $reason The underlying exception message.
	 */
	public static function modelLoadFailed( string $reason ): string {
		return \sprintf(
			/* translators: %s: Technical error detail from the AI provider */
			\__( "I couldn't connect to your AI provider. The model you selected isn't responding. Check that your API key is valid and that you haven't hit your provider's usage limits.\n\nDetails: %s", 'lolacore' ),
			$reason
		);
	}

	/**
	 * LLM provider returned an error during standard chat.
	 *
	 * @param string $reason The underlying exception message.
	 */
	public static function providerError( string $reason ): string {
		return self::formatProviderError( $reason );
	}

	/**
	 * Maps provider failures to user-facing copy, with quota/rate-limit detection.
	 *
	 * @param string $reason The underlying exception message.
	 */
	public static function formatProviderError( string $reason ): string {
		if ( self::isProviderQuotaError( $reason ) ) {
			return self::providerQuotaExceeded( $reason );
		}

		return \sprintf(
			/* translators: %s: Technical error detail from the AI provider */
			\__( "Your AI provider returned an error. This is usually temporary — wait a minute and try again. If it persists, check your provider's dashboard for billing or usage issues.\n\nDetails: %s", 'lolacore' ),
			$reason
		);
	}

	/**
	 * Google/Gemini (and similar) quota or rate-limit exhaustion.
	 *
	 * @param string $reason The underlying exception message.
	 */
	public static function providerQuotaExceeded( string $reason ): string {
		$retryHint = '';
		if ( preg_match( '/retry in ([\d.]+)s/i', $reason, $matches ) ) {
			$seconds   = max( 1, (int) ceil( (float) $matches[1] ) );
			$retryHint = \sprintf(
				/* translators: %d: seconds to wait before retrying */
				\__( ' Wait about %d seconds, then try again.', 'lolacore' ),
				$seconds
			);
		}

		$message = \__( "I've hit your AI provider's usage limit for now.", 'lolacore' )
			. $retryHint
			. ' '
			. \__( "On Google's free tier, Gemini Flash models allow about 20 requests per minute. Each message may use more than one request when I route tools or continue after an action. Check your usage at ai.google.dev, enable billing for higher limits, or switch to another provider in Settings → Connectors.", 'lolacore' );

		return $message . "\n\nDetails: " . $reason;
	}

	/**
	 * LLM provider error during escalation (fallback also failed).
	 *
	 * @param string $reason The underlying exception message.
	 */
	public static function providerErrorEscalation( string $reason ): string {
		return self::formatEscalationProviderError( $reason );
	}

	/**
	 * Maps escalation-time provider failures to user-facing copy.
	 *
	 * @param string $reason The underlying exception message.
	 */
	public static function formatEscalationProviderError( string $reason ): string {
		if ( self::isProviderQuotaError( $reason ) ) {
			return self::providerQuotaExceeded( $reason );
		}

		return \sprintf(
			/* translators: %s: Technical error detail from the AI provider */
			\__( "Your AI provider isn't responding, and my fallback attempt also failed. This typically means the provider is down or your API key has an issue. Check your provider's status page or try switching to a different provider in Settings → Connectors.\n\nDetails: %s", 'lolacore' ),
			$reason
		);
	}

	/**
	 * Classifier model couldn't load (intent routing).
	 *
	 * @param string $reason The underlying exception message.
	 */
	public static function classifierFailed( string $reason ): string {
		return \sprintf(
			/* translators: %s: Technical error detail from the AI provider */
			\__( "I'm having trouble processing your request — a required AI component couldn't load. This is usually a temporary provider issue. Try again in a moment.\n\nDetails: %s", 'lolacore' ),
			$reason
		);
	}

	/**
	 * Escalation flow failed.
	 *
	 * @param string $reason The underlying exception message.
	 */
	public static function escalationFailed( string $reason ): string {
		return \sprintf(
			/* translators: %s: Technical error detail */
			\__( "I ran into an issue while trying to expand my toolset for your request. Try rephrasing what you need, or try again in a moment.\n\nDetails: %s", 'lolacore' ),
			$reason
		);
	}

	// =========================================================================
	// Category 4 — Memory / Settings (Import, Export, Maintenance)
	// =========================================================================

	/**
	 * Uploaded file is not valid JSON.
	 */
	public static function invalidJsonPayload(): string {
		return \__( "That file doesn't contain valid data. Make sure you're uploading an export file generated by LolaCore (.json format).", 'lolacore' );
	}

	/**
	 * JSON archive doesn't contain expected data.
	 */
	public static function missingFactsArray(): string {
		return \__( "This file doesn't look like a LolaCore memory export — it's missing the expected data structure. Use a file exported from LolaCore's Settings → Maintenance → Export.", 'lolacore' );
	}

	/**
	 * Archive was exported from a different WordPress site.
	 */
	public static function originMismatch(): string {
		return \__( "This memory export came from a different WordPress site. Importing memories from another site could cause Lola to reference plugins, settings, or content that don't exist here. If you're migrating, export from this site's current state instead.", 'lolacore' );
	}

	/**
	 * Site scan didn't complete.
	 *
	 * @param string $reason The underlying exception message.
	 */
	public static function scanFailed( string $reason ): string {
		return \sprintf(
			/* translators: %s: Technical error detail */
			\__( "The site scan didn't complete. This can happen if your server timed out during a large scan. Try again — if it keeps failing, your hosting may need a higher PHP execution time limit.\n\nDetails: %s", 'lolacore' ),
			$reason
		);
	}

	/**
	 * Could not read an uploaded file.
	 */
	public static function fileReadFailed(): string {
		return \__( "I couldn't read that file. Make sure it's a .json file and that it's not empty or corrupted. Try downloading a fresh export and uploading again.", 'lolacore' );
	}

	/**
	 * No file was included in the upload.
	 */
	public static function noFileProvided(): string {
		return \__( "No file was received. Select a .json export file and try again.", 'lolacore' );
	}

	/**
	 * The uploaded file didn't pass validation.
	 */
	public static function invalidUpload(): string {
		return \__( "That upload doesn't look right. Make sure you're selecting a valid file and try again.", 'lolacore' );
	}

	/**
	 * Memory compact operation failed.
	 *
	 * @param string $reason The underlying exception message.
	 */
	public static function compactFailed( string $reason ): string {
		return \sprintf(
			/* translators: %s: Technical error detail */
			\__( "The memory cleanup didn't complete. This is usually a temporary database issue. Try again — if it persists, check that your database user has permission to optimize tables.\n\nDetails: %s", 'lolacore' ),
			$reason
		);
	}

	/**
	 * Import operation failed with a generic exception.
	 *
	 * @param string $reason The underlying exception message.
	 */
	public static function importFailed( string $reason ): string {
		return \sprintf(
			/* translators: %s: Technical error detail */
			\__( "The memory import didn't complete. This can happen if the file is corrupted or incompatible. Try exporting a fresh copy and importing again.\n\nDetails: %s", 'lolacore' ),
			$reason
		);
	}

	/**
	 * Memory wipe operation failed.
	 *
	 * @param string $reason The underlying exception message.
	 */
	public static function wipeFailed( string $reason ): string {
		return \sprintf(
			/* translators: %s: Technical error detail */
			\__( "The memory wipe didn't complete. This is usually a temporary database issue. Try again in a moment.\n\nDetails: %s", 'lolacore' ),
			$reason
		);
	}

	/**
	 * Feature temporarily disabled during refactoring.
	 */
	public static function temporarilyDisabled(): string {
		return \__( "This feature is temporarily unavailable while we upgrade the underlying system. It will be back soon.", 'lolacore' );
	}

	// =========================================================================
	// Category 5 — Skills
	// =========================================================================

	/**
	 * Attempt to toggle a built-in or addon skill.
	 */
	public static function skillToggleNotAllowed(): string {
		return \__( 'Built-in and addon skills cannot be toggled here. They are controlled by the plugin or addon.', 'lolacore' );
	}

	/**
	 * Attempt to delete a non-DB skill.
	 */
	public static function skillDeleteNotAllowed(): string {
		return \__( 'Only user-created or Lola-generated skills can be deleted from here.', 'lolacore' );
	}

	/**
	 * Skill not found in the registry.
	 */
	public static function skillNotFound(): string {
		return \__( 'Skill not found.', 'lolacore' );
	}

	// =========================================================================
	// Category 6 — Licensing & Addons
	// =========================================================================

	public static function licenseRequired(): string {
		return \__( 'I need a license key to activate this addon. Paste it above and try again.', 'lolacore' );
	}

	public static function licenseServerUnreachable(): string {
		return \__( "I couldn't reach the license server. Check your connection and try again.", 'lolacore' );
	}

	public static function licenseLimitReached(): string {
		return \__( 'This license has reached its activation limit. Deactivate it from the other site first.', 'lolacore' );
	}

	public static function licenseActivationFailed(): string {
		return \__( "I couldn't activate this license. Double-check the key and try again.", 'lolacore' );
	}

	public static function licenseMismatch(): string {
		return \__( "This license key doesn't match this addon. Double-check the key and try again.", 'lolacore' );
	}

	public static function licenseDeactivationFailed(): string {
		return \__( "I couldn't deactivate this license right now. Try again in a few minutes.", 'lolacore' );
	}

	// =========================================================================
	// Server Error Sanitizer
	// =========================================================================

	/**
	 * Wraps a raw server error in user-friendly context.
	 * Prevents technical stack traces from leaking to the frontend.
	 *
	 * @param string $rawError The raw exception or error message.
	 */
	public static function wrapServerError( string $rawError ): string {
		if ( self::isProviderQuotaError( $rawError ) ) {
			return self::providerQuotaExceeded( $rawError );
		}

		if ( self::isTechnicalGarbage( $rawError ) ) {
			return \__( "Something went wrong on my end and I couldn't process that request. Try refreshing the page. If it keeps happening, your hosting provider's error log will have the details.", 'lolacore' );
		}

		return \sprintf(
			/* translators: %s: The specific server error message */
			\__( "Something went wrong on my end. Here's what the server reported: \"%s\". If this doesn't make sense, try refreshing the page — if the problem persists, check your AI provider settings or hosting error log.", 'lolacore' ),
			$rawError
		);
	}

	/**
	 * Detects provider quota, billing, and rate-limit errors.
	 */
	private static function isProviderQuotaError( string $msg ): bool {
		return preg_match(
			'/429|too many requests|quota exceeded|rate.?limit|free_tier|usage limit|billing details/i',
			$msg
		) === 1;
	}

	/**
	 * Detects PHP class names, stack traces, or raw error codes
	 * that should never reach the user.
	 */
	private static function isTechnicalGarbage( string $msg ): bool {
		return preg_match( '/\\\\|Exception|Stack trace|#\d|Fatal error/i', $msg ) === 1;
	}
}
