<?php

namespace Limb_Chatbot\Includes\Factories;

use Limb_Chatbot\Includes\Data_Objects\Action;
use Limb_Chatbot\Includes\Data_Objects\Chatbot;
use Limb_Chatbot\Includes\Services\Chatbot_Analytics\Calculators\Action_Submissions_Calculator;
use Limb_Chatbot\Includes\Services\Chatbot_Analytics\Calculators\Calculator_Registry;
use Limb_Chatbot\Includes\Services\Chatbot_Analytics\Types\Action_Analytics_Type;
use Limb_Chatbot\Includes\Services\Chatbot_Analytics\Types\Analytics_Type_Registry;

/**
 * Class Chatbot_Analytics_Factory
 *
 * Factory class responsible for initializing the analytics type and calculator registries with action-based types.
 * Follows SOLID principles:
 * - Single Responsibility: Only handles analytics type and calculator registration for actions
 * - Open/Closed: Easily extensible for new type sources
 * - Dependency Inversion: Depends on abstractions (Analytics_Type_Registry, Calculator_Registry)
 *
 * @package Limb_Chatbot\Includes\Factories
 * @since 1.0.0
 */
class Chatbot_Analytics_Factory {

	/**
	 * The chatbot instance.
	 *
	 * @var Chatbot
	 * @since 1.0.0
	 */
	private Chatbot $chatbot;

	/**
	 * The analytics type registry.
	 *
	 * @var Analytics_Type_Registry
	 * @since 1.0.0
	 */
	private Analytics_Type_Registry $registry;

	/**
	 * The calculator registry.
	 *
	 * @var Calculator_Registry
	 * @since 1.0.0
	 */
	private Calculator_Registry $calculator_registry;

	/**
	 * Chatbot_Analytics_Factory constructor.
	 *
	 * @param Chatbot                     $chatbot                The chatbot instance
	 * @param Calculator_Registry|null    $calculator_registry    Optional calculator registry (for dependency injection)
	 *
	 * @since 1.0.0
	 */
	public function __construct( Chatbot $chatbot, ?Calculator_Registry $calculator_registry = null ) {
		$this->chatbot                = $chatbot;
		$this->registry               = Analytics_Type_Registry::instance();
		$this->calculator_registry    = $calculator_registry ?? new Calculator_Registry();
		$this->register_action_types_and_calculators();
	}

	/**
	 * Register action-based analytics types and their calculators.
	 * Each active action in the chatbot gets its own analytics type and calculator instance.
	 *
	 * @return void
	 * @since 1.0.0
	 */
	public function register_action_types_and_calculators(): void {
		$action_ids = $this->chatbot->get_parameter( 'action_ids' );

		if ( empty( $action_ids ) || ! is_array( $action_ids ) ) {
			return;
		}

		foreach ( $action_ids as $action_id ) {
			$action = Action::find( $action_id );

			if ( ! ( $action instanceof Action ) ) {
				continue;
			}

			// Create and store action-based analytics type
			$action_type = new Action_Analytics_Type(
				$action->get_name(),
				$action->title,
				$action->name
			);

			$type_id = $action_type->get_id();

			// Only try to register if not already registered (avoid duplicates)
			if ( ! $this->registry->has( $type_id ) ) {
				try {
					$this->registry->register( $action_type );
				} catch ( \InvalidArgumentException $e ) {
					// Type already registered, skip it
					continue;
				}
			}

			// Also register a calculator for this action type
			// Use the action name (type_id) as the key in the calculator registry
			try {
				$this->calculator_registry->register(
					$type_id,
					new Action_Submissions_Calculator()
				);
			} catch ( \InvalidArgumentException $e ) {
				// Calculator already registered for this action, skip it
				continue;
			}
		}
	}

	/**
	 * Get the analytics type registry (useful for testing or direct access).
	 *
	 * @return Analytics_Type_Registry
	 * @since 1.0.0
	 */
	public function get_registry(): Analytics_Type_Registry {
		return $this->registry;
	}

	/**
	 * Get the calculator registry (useful for testing or direct access).
	 *
	 * @return Calculator_Registry
	 * @since 1.0.0
	 */
	public function get_calculator_registry(): Calculator_Registry {
		return $this->calculator_registry;
	}

	/**
	 * Get the chatbot instance.
	 *
	 * @return Chatbot
	 * @since 1.0.0
	 */
	public function get_chatbot(): Chatbot {
		return $this->chatbot;
	}
}
