<?php
/**
 * Costudio_Model_Fallback
 *
 * Shared utilities for AI adapters to detect "deprecated/unknown model" errors
 * from provider APIs and fall back transparently to a known-good default.
 *
 * Used by:
 *  - Costudio_Gemini_Adapter
 *  - Costudio_Claude_Adapter
 *  - Costudio_OpenAI_Adapter
 *
 * The actual fallback (one-shot retry with DEFAULT_MODEL) is implemented
 * inside each adapter — this class just centralizes the detection heuristic
 * and the persistence/logging of fallback events.
 *
 * @package Contentosapp_Studio
 * @since   1.0.0
 */

defined( 'ABSPATH' ) || exit;

class Costudio_Model_Fallback {

	/**
	 * Substrings that strongly indicate a "model unknown / deprecated"
	 * response from any of the supported providers. Lower-case match.
	 */
	private const SIGNALS = [
		'model_not_found',
		'model not found',
		'model is not found',
		'is not found for api',
		'is not supported for',
		'does not exist',
		'has been deprecated',
		'no longer supported',
		'unknown model',
	];

	/**
	 * True if the (HTTP code, error message) pair from a provider response
	 * matches a "deprecated/unknown model" signature.
	 *
	 * HTTP 404 is the canonical "model not found" code across Gemini, Claude
	 * and OpenAI; some providers also surface the same condition as 400 with
	 * a message tag — both paths are covered.
	 */
	public static function is_deprecated_model_error( int $code, string $message ): bool {
		if ( $code === 404 ) {
			return true;
		}

		$lower = strtolower( $message );
		foreach ( self::SIGNALS as $needle ) {
			if ( strpos( $lower, $needle ) !== false ) {
				return true;
			}
		}

		return false;
	}

	/**
	 * Persist a fallback event so we have a paper trail and a hook for a
	 * future admin notice (P2 — not yet implemented).
	 *
	 * @param string $provider 'gemini' | 'claude' | 'openai'
	 * @param string $from     The model that failed.
	 * @param string $to       The DEFAULT_MODEL we fell back to.
	 * @param string $reason   Raw error message from the provider.
	 */
	public static function record( string $provider, string $from, string $to, string $reason ): void {
		$payload = [
			'provider' => $provider,
			'from'     => $from,
			'to'       => $to,
			'reason'   => mb_substr( $reason, 0, 400 ),
			'ts'       => time(),
		];

		update_option( 'costudio_last_model_fallback', $payload, false );

		costudio_log( 'model_fallback.recorded', [
			'provider' => $provider,
			'from'     => $from,
			'to'       => $to,
			'reason'   => $reason,
		], 'warning' );
	}
}
