<?php
/**
 * AI Provider Pricing Matrix
 *
 * USD per 1,000,000 tokens for current production models (input, output).
 * Used by UsageTracker to derive an approximate dollar cost from real
 * usage counts returned by each provider.
 *
 * Numbers are best-effort snapshots; providers update prices unannounced.
 * Override via the `aipt_api_pricing` filter for site-specific overrides.
 *
 * @package AIPT\Api\Constants
 * @since   2.6.0
 */

namespace AIPT\Api\Constants;

class ApiPricing {

	/**
	 * Per-model pricing in USD per 1,000,000 tokens: [input, output].
	 *
	 * Keys use the `provider/model` form so OpenRouter models that include
	 * a slash already inside the model identifier still resolve uniquely.
	 */
	private const PRICING = array(

		'openai/gpt-5.5'            => array( 5.00, 30.00 ),
		'openai/gpt-5.5-pro'        => array( 30.00, 180.00 ),
		'openai/gpt-5.4'            => array( 2.50, 15.00 ),
		'openai/gpt-5.4-mini'       => array( 0.75, 4.50 ),
		'openai/gpt-5.4-nano'       => array( 0.20, 1.25 ),
		'openai/gpt-4.1'            => array( 2.00, 8.00 ),
		'openai/gpt-4.1-mini'       => array( 0.40, 1.60 ),
		'openai/gpt-4.1-nano'       => array( 0.10, 0.40 ),
		'openai/gpt-5'              => array( 1.25, 10.00 ),
		'openai/gpt-5-mini'         => array( 0.25, 2.00 ),
		'openai/gpt-5-nano'         => array( 0.05, 0.40 ),
		'openai/gpt-4o'             => array( 2.50, 10.00 ),
		'openai/gpt-4o-mini'        => array( 0.15, 0.60 ),
		'openai/o3'                 => array( 2.00, 8.00 ),
		'openai/o3-pro'             => array( 20.00, 80.00 ),
		'openai/o3-mini'            => array( 1.10, 4.40 ),
		'openai/o4-mini'            => array( 1.10, 4.40 ),

		'claude/claude-opus-4-8'    => array( 5.00, 25.00 ),
		'claude/claude-opus-4-7'    => array( 5.00, 25.00 ),
		'claude/claude-opus-4-6'    => array( 5.00, 25.00 ),
		'claude/claude-sonnet-4-6'  => array( 3.00, 15.00 ),
		'claude/claude-opus-4-5'    => array( 5.00, 25.00 ),
		'claude/claude-sonnet-4-5'  => array( 3.00, 15.00 ),
		'claude/claude-haiku-4-5'   => array( 1.00, 5.00 ),
		'claude/claude-opus-4-1'    => array( 15.00, 75.00 ),
		'claude/claude-opus-4'      => array( 15.00, 75.00 ),
		'claude/claude-sonnet-4'    => array( 3.00, 15.00 ),
		'claude/claude-haiku-4'     => array( 0.80, 4.00 ),
		'claude/claude-3-5-sonnet'  => array( 3.00, 15.00 ),
		'claude/claude-3-5-haiku'   => array( 1.00, 5.00 ),

		'gemini/gemini-3.5-flash'       => array( 1.50, 9.00 ),
		'gemini/gemini-3.1-pro-preview' => array( 2.00, 12.00 ),
		'gemini/gemini-3.1-flash-lite'  => array( 0.25, 1.50 ),
		'gemini/gemini-3-flash-preview' => array( 0.50, 3.00 ),
		'gemini/gemini-2.5-pro'         => array( 1.25, 10.00 ),
		'gemini/gemini-2.5-flash'       => array( 0.30, 2.50 ),
		'gemini/gemini-2.5-flash-lite'  => array( 0.10, 0.40 ),
		'gemini/gemini-2.0-flash'       => array( 0.10, 0.40 ),
		'gemini/gemini-2.0-flash-lite'  => array( 0.075, 0.30 ),
		'gemini/gemini-1.5-pro'         => array( 1.25, 5.00 ),
		'gemini/gemini-1.5-flash'       => array( 0.075, 0.30 ),
	);

	/**
	 * Conservative fallback pricing per provider when no exact model match
	 * is found. Picks the upper-mid tier so estimates skew slightly high
	 * rather than misleadingly low.
	 *
	 * @var array<string, array{float, float}>
	 */
	private const FALLBACK_PRICING = array(
		'openai'     => array( 2.50, 10.00 ),
		'claude'     => array( 3.00, 15.00 ),
		'gemini'     => array( 1.25, 10.00 ),
		'openrouter' => array( 3.00, 10.00 ),
	);

	/**
	 * Calculate the estimated cost of an API call in USD micros (USD × 1,000,000).
	 *
	 * Micros provide 6-decimal precision: a 1200-token call to gpt-5-nano at
	 * $0.05/1M input is $0.00006 = 60 micros, which integer cents (rounded up
	 * to 1¢) would have inflated by ~170×. Modern usage dashboards (AWS Cost
	 * Explorer, OpenAI billing) all store cost in fractional-cent units for
	 * this exact reason.
	 *
	 * @param string $provider      Provider id.
	 * @param string $model         Model id.
	 * @param int    $input_tokens  Prompt tokens.
	 * @param int    $output_tokens Completion tokens.
	 * @return int Estimated cost in USD micros (USD × 1,000,000), rounded to nearest.
	 */
	public static function calculate_cost_micros( string $provider, string $model, int $input_tokens, int $output_tokens ): int {
		if ( $input_tokens <= 0 && $output_tokens <= 0 ) {
			return 0;
		}

		$pricing = \AIPT\Core\Services\PricingFeedManager::instance()->resolve( $provider, $model );

		$input_micros  = $input_tokens * $pricing[0];
		$output_micros = $output_tokens * $pricing[1];

		return max( 0, (int) round( $input_micros + $output_micros ) );
	}

	/**
	 * Last-resort hardcoded baseline used by PricingFeedManager when the
	 * remote snapshot is unavailable. Exposed so the manager doesn't reach
	 * into a private constant via reflection.
	 *
	 * @return array<string, array{float, float}>
	 */
	public static function get_baseline_table(): array {
		return self::PRICING;
	}

	/**
	 * Provider-level fallback rates for cases where the model id is unknown
	 * to both the remote feed and the baseline table.
	 *
	 * @param string $provider Provider id.
	 * @return array{float, float}
	 */
	public static function get_provider_fallback( string $provider ): array {
		$provider = strtolower( trim( $provider ) );
		if ( isset( self::FALLBACK_PRICING[ $provider ] ) ) {
			return self::FALLBACK_PRICING[ $provider ];
		}
		return self::FALLBACK_PRICING['openai'];
	}
}
