<?php

namespace Limb_Chatbot\Includes\Services\Chatbot_Analytics\Calculators;

use Limb_Chatbot\Includes\Services\Chatbot_Analytics\Types\Analytics_Type;

/**
 * Class Calculator_Registry
 *
 * Registry for managing analytics calculators by type.
 * Maps analytics types to their corresponding calculator implementations.
 * Implements the Registry and Factory patterns.
 *
 * @package Limb_Chatbot\Includes\Services\Chatbot_Analytics\Calculators
 * @since 1.0.0
 */
class Calculator_Registry {

	/**
	 * Registered calculators, keyed by type ID.
	 *
	 * @var Analytics_Calculator[]
	 * @since 1.0.0
	 */
	private array $calculators = [];

	/**
	 * Constructor - initializes default calculators.
	 *
	 * @since 1.0.0
	 */
	public function __construct() {
		$this->register_default_calculators();
	}

	/**
	 * Register default analytics calculators.
	 *
	 * @return void
	 * @since 1.0.0
	 */
	private function register_default_calculators(): void {
		// Register built-in calculators
		$this->register( 'conversations', new Conversations_Calculator() );
		$this->register( 'new_visitors', new New_Visitors_Calculator() );
		$this->register( 'returning_visitors', new Returning_Visitors_Calculator() );
		$this->register( 'leads_captured', new Leads_Captured_Calculator() );
	}

	/**
	 * Register a calculator for a specific type ID.
	 *
	 * @param string                $type_id   The analytics type ID
	 * @param Analytics_Calculator $calculator The calculator instance
	 *
	 * @return void
	 * @throws \InvalidArgumentException If type ID already has a calculator
	 * @since 1.0.0
	 */
	public function register( string $type_id, Analytics_Calculator $calculator ): void {
		if ( isset( $this->calculators[ $type_id ] ) ) {
			throw new \InvalidArgumentException(
				sprintf(
					'Calculator for type "%s" is already registered.',
					$type_id
				)
			);
		}

		$this->calculators[ $type_id ] = $calculator;
	}

	/**
	 * Get a calculator for a specific type.
	 *
	 * @param Analytics_Type $type The analytics type
	 *
	 * @return Analytics_Calculator|null The calculator or null if not found
	 * @since 1.0.0
	 */
	public function get( Analytics_Type $type ): ?Analytics_Calculator {
		return $this->calculators[ $type->get_id() ] ?? null;
	}

	/**
	 * Check if a calculator is registered for a type.
	 *
	 * @param Analytics_Type $type The analytics type
	 *
	 * @return bool True if calculator exists
	 * @since 1.0.0
	 */
	public function has( Analytics_Type $type ): bool {
		return isset( $this->calculators[ $type->get_id() ] );
	}

	/**
	 * Get all registered calculators.
	 *
	 * @return Analytics_Calculator[]
	 * @since 1.0.0
	 */
	public function get_all(): array {
		return $this->calculators;
	}
}
