<?php
/**
 * Footer layout registry.
 *
 * @package Kutby
 * @since   2.7.0
 */

declare(strict_types=1);

namespace Kutby\Footer\Services;

use Kutby\Footer\Contracts\FooterLayoutInterface;

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

/**
 * Class FooterRegistry
 */
final class FooterRegistry {

	/**
	 * @var array<string, class-string<FooterLayoutInterface>>
	 */
	private array $layouts = array();

	/**
	 * @var self|null
	 */
	private static ?self $instance = null;

	/**
	 * @return self
	 */
	public static function instance(): self {
		if ( null === self::$instance ) {
			self::$instance = new self();
		}
		return self::$instance;
	}

	/**
	 * @param string                              $id    Layout id.
	 * @param class-string<FooterLayoutInterface> $class Class.
	 * @return void
	 */
	public function add( string $id, string $class ): void {
		$this->layouts[ sanitize_key( $id ) ] = $class;
	}

	/**
	 * @param string $id Id.
	 * @return bool
	 */
	public function has( string $id ): bool {
		return isset( $this->layouts[ sanitize_key( $id ) ] );
	}

	/**
	 * @param string $id Id.
	 * @return class-string<FooterLayoutInterface>|null
	 */
	public function get_class( string $id ): ?string {
		$id = sanitize_key( $id );
		return $this->layouts[ $id ] ?? null;
	}

	/**
	 * @return array<string, class-string<FooterLayoutInterface>>
	 */
	public function all(): array {
		return $this->layouts;
	}

	/**
	 * @return array<string, string>
	 */
	public function labels(): array {
		$out = array();
		foreach ( $this->layouts as $id => $class ) {
			if ( ! is_subclass_of( $class, FooterLayoutInterface::class ) ) {
				continue;
			}
			/** @var FooterLayoutInterface $instance */
			$instance   = new $class();
			$out[ $id ] = $instance->label();
		}
		return $out;
	}

	/**
	 * @param string $id Id.
	 * @return FooterLayoutInterface|null
	 */
	public function make( string $id ): ?FooterLayoutInterface {
		$class = $this->get_class( $id );
		if ( null === $class || ! is_subclass_of( $class, FooterLayoutInterface::class ) ) {
			return null;
		}
		return new $class();
	}
}
