<?php
/**
 * Reward types factory for creating reward type instances.
 *
 * @package Awesomemotive\Rewardswp\Factories
 * @since 1.0.0
 */

namespace Awesomemotive\Rewardswp\Factories;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

use Awesomemotive\Rewardswp\Abstracts\AbstractRewardType;
use Awesomemotive\Rewardswp\Interfaces\RewardTypeInterface;
use DI\Container;
use Exception;
use function Awesomemotive\Rewardswp\Helpers\str_snake_to_pascal_case;

class RewardTypesFactory {
	/**
	 * Dependency injection container.
	 *
	 * @since 1.0.0
	 *
	 * @var Container
	 */
	private Container $container;

	public function __construct( Container $container ) {
		$this->container = $container;
	}

	/**
	 * Retrieves an instance of a RewardType object based on its name or class name.
	 *
	 * @since 1.0.0
	 *
	 * @param string|RewardTypeInterface $name_or_class    The snake_case name of the reward type or the class name.
	 * @return RewardTypeInterface|AbstractRewardType|null The RewardType object instance, or null if not found.
	 */
	function get_reward_type( $name_or_class ): ?RewardTypeInterface {
		try {
			// Check if it is the class name, if so, return right away.
			if ( class_exists( $name_or_class ) && is_subclass_of( $name_or_class, RewardTypeInterface::class ) ) {
				return $this->container->get( $name_or_class );
			}

			// Define namespaces to search for reward types.
			$namespaces = [
				'Awesomemotive\\Rewardswp\\RewardTypes',
				'Awesomemotive\\Rewardswp\\Pro\\RewardTypes',
			];

			$class_name = empty( $name_or_class )
				? 'UnknownRewardType'
				: sprintf( '%sRewardType', str_snake_to_pascal_case( $name_or_class ) );

			foreach ( $namespaces as $namespace ) {
				$full_class_name = sprintf( '%s\\%s', $namespace, $class_name );

				if ( class_exists( $full_class_name ) && is_subclass_of( $full_class_name, RewardTypeInterface::class ) ) {
					return $this->container->get( $full_class_name );
				}
			}

			return null;
		} catch ( Exception $exception ) {
			return null;
		}
	}

	/**
	 * Get all registered reward types as an associative array [key => instance].
	 *
	 * @since 1.0.0
	 *
	 * @return array<string, RewardTypeInterface> Array of reward type instances keyed by their type.
	 */
	public function get_all_reward_types(): array {
		$reward_types = [];

		try {
			// Get registered reward types from container.
			$reward_types_classes = $this->container->get( 'reward_types_classes' );

			foreach ( $reward_types_classes as $reward_type_class ) {
				$reward_type = $this->get_reward_type( $reward_type_class );

				if ( ! is_null( $reward_type ) ) {
					$reward_types[ $reward_type->get_type() ] = $reward_type;
				}
			}
		} catch ( Exception $exception ) {
			// Return empty array if reward_types_classes not found.
			return [];
		}

		return $reward_types;
	}
}
