<?php

namespace Limb_Chatbot\Includes\Services;

use Exception;
use Limb_Chatbot\Includes\Data_Objects\Chat;
use Limb_Chatbot\Includes\Data_Objects\Limit;
use Limb_Chatbot\Includes\Data_Objects\AI_Model;
use Limb_Chatbot\Includes\Data_Objects\Token_Usage;
use Limb_Chatbot\Includes\Interfaces\Usage_Service_Interface;

/**
 * Service class responsible for checking and updating chatbot usage limits.
 *
 * @since 1.0.0
 */
class Chatbot_Usage_Service implements Usage_Service_Interface {

	/**
	 * Checks if a given limit has been exceeded.
	 *
	 * @param  Limit  $limit  The limit to check against.
	 * @param  mixed|null  $message  Optional message context (not currently used).
	 *
	 * @return Limit|null Returns the limit if exceeded, null otherwise.
	 * @throws Exception
	 * @since 1.0.0
	 */
	public function check( Limit $limit, $message = null ) {
		$limit_key = $limit->get_usage_key();
		if ( $this->reset_limits_if_needed( $limit ) ) {
			return null;
		}
		$current_usage = $limit->get_chatbot()->get_parameter( $limit_key );
		if ( $current_usage === null || $current_usage === false ) {
			return null;
		}

		return $current_usage >= $limit->get_value() ? $limit : null;
	}

	/**
	 * Resets the limit if the reset period has elapsed.
	 *
	 * @param  Limit  $limit  The limit to check for reset.
	 *
	 * @return bool True if reset occurred, false otherwise.
	 * @throws Exception
	 * @since 1.0.0
	 */
	private function reset_limits_if_needed( Limit $limit ) {
		$current_time              = current_time( 'timestamp' );
		$last_reset_timestamp_meta = $limit->get_usage_key() . '_last_reset_timestamp';
		$last_reset_timestamp      = $limit->get_chatbot()->get_parameter( $last_reset_timestamp_meta );
		if ( empty( $last_reset_timestamp ) || ( $current_time - $last_reset_timestamp ) >= $limit->get_period() ) {
			$limit->get_chatbot()->update_parameter( $limit->get_usage_key(), 0 );
			$limit->get_chatbot()->update_parameter( $last_reset_timestamp_meta, $current_time );

			return true;
		}

		return false;
	}

	/**
	 * Updates the usage count or cost for a given limit based on token usage and AI model.
	 *
	 * @param  Limit  $limit  The limit to update.
	 * @param  Token_Usage  $usage  Token usage details.
	 * @param  AI_Model  $model  The AI model used for cost calculation.
	 * @param  Chat|null  $chat  Optional chat context.
	 *
	 * @return void
	 * @throws Exception
	 * @since 1.0.0
	 */
	public function update_usage( Limit $limit, Token_Usage $usage, AI_Model $model, ?Chat $chat = null ) {
		$limit_key     = $limit->get_usage_key();
		$current_value = $limit->get_chatbot()->get_parameter( $limit_key );
		if ( $limit->get_unit() == Limit::UNIT_TOKEN ) {
			$total_tokens = $usage->get_input_tokens() + $usage->get_output_tokens();
			$limit->get_chatbot()->update_parameter( $limit_key, $current_value + $total_tokens );
		} elseif ( $limit->get_unit() == Limit::UNIT_COST ) {
			$model_service = ( new AI_Model_Service() );
			$input_cost    = $model_service->get_input_cost( $model, $usage->get_input_tokens() );
			$output_cost   = $model_service->get_output_cost( $model, $usage->get_output_tokens() );
			$total_cost    = $input_cost + $output_cost;
			$limit->get_chatbot()->update_parameter( $limit_key, $current_value + $total_cost );
		}
	}
}