<?php
namespace TeknoTok\AiTranslator\Utils;

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

/**
 * Converts provider and gateway errors into customer-safe plugin messages.
 */
class ErrorSanitizer {
	/**
	 * Customer-safe quota/license limit message.
	 *
	 * @return string Message.
	 */
	public static function limit_message() {
		return self::translate( 'Translation is paused because the translation quota or license limit was reached. Please check your TeknoTok license status, then click Resume Translation and Continue Now.' );
	}

	/**
	 * Customer-safe quota exhausted message.
	 *
	 * @return string Message.
	 */
	public static function quota_exceeded_message() {
		return self::translate( 'Your AI translation word quota is finished. Existing translations still work, but new translations are paused until your quota renews or you add more words.' );
	}

	/**
	 * Customer-safe generic translation failure message.
	 *
	 * @return string Message.
	 */
	public static function generic_message() {
		return self::translate( 'Translation failed temporarily. Please try again. If the problem continues, contact TeknoTok support.' );
	}

	/**
	 * Sanitize one provider-facing message for customer display.
	 *
	 * @param string $message Raw message.
	 * @return string Customer-safe message.
	 */
	public static function sanitize_message( $message ) {
		$message = trim( (string) $message );
		if ( '' === $message ) {
			return self::generic_message();
		}

		if ( self::is_existing_generic_message( $message ) ) {
			return self::generic_message();
		}

		if ( self::is_limit_message( $message ) ) {
			if ( false !== strpos( strtolower( $message ), 'word quota' ) || false !== strpos( strtolower( $message ), 'words_remaining' ) ) {
				return self::quota_exceeded_message();
			}
			return self::limit_message();
		}

		if ( self::is_provider_message( $message ) ) {
			return self::generic_message();
		}

		return $message;
	}

	/**
	 * Sanitize multiline log output before it is shown inside plugin UI.
	 *
	 * @param string $logs Raw log content.
	 * @return string Customer-safe log content.
	 */
	public static function sanitize_log_output( $logs ) {
		$logs = (string) $logs;
		if ( '' === trim( $logs ) ) {
			return '';
		}

		$lines = explode( "\n", $logs );
		$visible_lines = array();
		$last_message = null;

		foreach ( $lines as $index => $line ) {
			$line = self::sanitize_log_line( $line );
			if ( '' === trim( $line ) ) {
				continue;
			}

			$message = preg_replace( '/^\[[^\]]+\]\s+\[[^\]]+\]:\s*/', '', $line );
			if ( $message === $last_message ) {
				continue;
			}

			$visible_lines[] = $line;
			$last_message = $message;
		}

		return implode( "\n", $visible_lines );
	}

	/**
	 * Determine whether a message is a quota/license/provider-limit failure.
	 *
	 * @param string $message Raw message.
	 * @return bool True if it is a limit message.
	 */
	public static function is_limit_message( $message ) {
		$message = strtolower( (string) $message );

		return (
			false !== strpos( $message, 'platform.openai.com/docs/guides/error-codes/api-errors' )
			|| false !== strpos( $message, 'billing details' )
			|| false !== strpos( $message, 'current quota' )
			|| false !== strpos( $message, 'quota exceeded' )
			|| ( false !== strpos( $message, 'quota' ) && false !== strpos( $message, 'finished' ) )
			|| ( false !== strpos( $message, 'quota' ) && false !== strpos( $message, 'exhausted' ) )
			|| ( false !== strpos( $message, 'quota' ) && false !== strpos( $message, 'exceeded' ) )
			|| ( false !== strpos( $message, 'limit' ) && false !== strpos( $message, 'exceeded' ) )
			|| ( false !== strpos( $message, 'word' ) && false !== strpos( $message, 'limit' ) )
			|| ( false !== strpos( $message, 'word quota' ) && false !== strpos( $message, 'paused until' ) )
			|| false !== strpos( $message, 'add more words' )
			|| false !== strpos( $message, 'license' )
		);
	}

	/**
	 * Determine whether a message exposes provider/gateway internals.
	 *
	 * @param string $message Raw message.
	 * @return bool True if the message should be hidden from customers.
	 */
	private static function is_provider_message( $message ) {
		$message = strtolower( (string) $message );

		return (
			false !== strpos( $message, 'openai' )
			|| false !== strpos( $message, 'platform.openai.com' )
			|| false !== strpos( $message, 'gateway error' )
			|| false !== strpos( $message, 'api request failed' )
			|| false !== strpos( $message, 'request failed' )
			|| false !== strpos( $message, 'translation request failed' )
			|| false !== strpos( $message, 'from gateway' )
			|| false !== strpos( $message, 'valid translation' )
			|| false !== strpos( $message, 'wp_remote' )
			|| false !== strpos( $message, 'curl error' )
			|| false !== strpos( $message, 'timed out' )
			|| false !== strpos( $message, 'timeout' )
		);
	}

	/**
	 * Detect earlier customer-safe generic messages, including prefixed log lines.
	 *
	 * @param string $message Message.
	 * @return bool True when it is the existing generic message.
	 */
	private static function is_existing_generic_message( $message ) {
		$message = strtolower( (string) $message );

		return (
			false !== strpos( $message, 'translation failed temporarily' )
			&& false !== strpos( $message, 'teknotok support' )
		);
	}

	/**
	 * Sanitize a single log line while preserving timestamp/level prefixes.
	 *
	 * @param string $line Raw log line.
	 * @return string Customer-safe log line.
	 */
	private static function sanitize_log_line( $line ) {
		if ( preg_match( '/^(\[[^\]]+\]\s+\[[^\]]+\]:\s*)(.*)$/', $line, $matches ) ) {
			$message = self::sanitize_message( $matches[2] );
			if ( self::is_technical_cascade_log( $matches[2], $message ) ) {
				return '';
			}

			return $matches[1] . self::display_log_message( $message );
		}

		$message = self::sanitize_message( $line );
		if ( self::is_technical_cascade_log( $line, $message ) ) {
			return '';
		}

		return self::display_log_message( $message );
	}

	/**
	 * Check whether a log line is a technical duplicate from the same failure cascade.
	 *
	 * @param string $raw_message  Raw log message.
	 * @param string $safe_message Safe customer message.
	 * @return bool True when the line should be hidden in customer-visible logs.
	 */
	private static function is_technical_cascade_log( $raw_message, $safe_message ) {
		if ( self::generic_message() !== $safe_message ) {
			return false;
		}

		$raw_message = strtolower( (string) $raw_message );

		return (
			false !== strpos( $raw_message, 'queue worker exception' )
			|| false !== strpos( $raw_message, 'failed string translation batch' )
			|| false !== strpos( $raw_message, 'request failed' )
			|| false !== strpos( $raw_message, 'attempt ' )
		);
	}

	/**
	 * Convert safe messages into cleaner log-panel wording.
	 *
	 * @param string $message Safe message.
	 * @return string Display message.
	 */
	private static function display_log_message( $message ) {
		if ( self::generic_message() === $message ) {
			return self::translate( 'Translation service was temporarily unavailable. Retry failed jobs after the service is available.' );
		}

		return $message;
	}

	/**
	 * Translate a static message when WordPress i18n is available.
	 *
	 * @param string $message English message.
	 * @return string Translated message.
	 */
	private static function translate( $message ) {
		if ( function_exists( '__' ) ) {
			return __( $message, 'teknotok-ai-translator' );
		}

		return $message;
	}
}
