<?php
/**
 * Abstract module base
 *
 * Standard loader contract: {@see init()} is idempotent and only runs
 * {@see registerHooks()} when the module is enabled. Subclasses put all
 * add_action / add_filter / remove_* calls in registerHooks().
 *
 * Module classes live under per-module PHP namespaces (e.g. AdminMenuOrganizer)
 * declared in each module's meta.json and loaded by ModuleManager — not via the
 * core PSR-4 autoloader mapped to src/. Core code uses WP_PowerSuite\* namespaces.
 *
 * @package WP_PowerSuite\Core
 * @since 1.0.0
 */

namespace WP_PowerSuite\Core;

use WP_PowerSuite\Core\Contracts\DataLocationsInterface;
use WP_PowerSuite\Core\Contracts\ModuleInterface;
use WP_PowerSuite\Core\Contracts\ModuleSettingsRepository;

abstract class AbstractModule implements ModuleInterface {

	private bool $initialized = false;

	private ?OptionStore $option_store = null;

	private ?ModuleSettingsRepository $module_settings = null;

	/**
	 * Whether init() has completed successfully (hooks registered or intentionally skipped).
	 */
	final public function isInitialized(): bool {
		return $this->initialized;
	}

	final public function isEnabled(): bool {
		return OptionStoreModuleSettingsRepository::isModuleEnabled( $this->getId() );
	}

	public function getDependencies(): array {
		return [];
	}

	/**
	 * Idempotent bootstrap: enabled check, duplicate guard, then hook registration.
	 */
	final public function init(): void {
		if ( $this->initialized ) {
			return;
		}

		if ( $this instanceof DataLocationsInterface ) {
			DataRegistry::registerModuleDataLocations( $this->getId(), $this->getDataLocations() );
		}

		if ( ! $this->isEnabled() ) {
			return;
		}

		$this->initialized = true;
		$this->registerHooks();
	}

	/**
	 * Register WordPress hooks (runs only when enabled, once per request).
	 */
	abstract protected function registerHooks(): void;

	/**
	 * Shared OptionStore for module lifecycle (enable/disable, enabled list).
	 *
	 * Prefer {@see moduleSettings()} for reading or saving module settings.
	 */
	protected function optionStore(): OptionStore {
		if ( $this->option_store === null ) {
			$this->option_store = OptionStore::getInstance();
		}

		return $this->option_store;
	}

	/**
	 * Typed settings accessor for this module (Phase 1 repository facade).
	 */
	protected function moduleSettings(): ModuleSettingsRepository {
		if ( $this->module_settings === null ) {
			$this->module_settings = OptionStoreModuleSettingsRepository::forModule( $this->getId() );
		}

		return $this->module_settings;
	}

	/**
	 * Admin menu hook for PowerSuite submenus (site vs network admin).
	 */
	protected function adminMenuHook(): string {
		return NetworkScope::adminMenuHook();
	}

	/**
	 * Capability required to manage this module's admin screens.
	 */
	protected function adminCapability(): string {
		return NetworkScope::adminCapability();
	}

	/**
	 * Whether the current user may manage this module's admin screens.
	 */
	protected function canManagePlugin(): bool {
		return NetworkScope::canManagePlugin();
	}

	/**
	 * Register a submenu under the PowerSuite top-level menu.
	 *
	 * @param string   $page_title  Page title.
	 * @param string   $menu_title  Menu title.
	 * @param string   $menu_slug   Menu slug.
	 * @param callable $callback    Render callback.
	 */
	protected function registerPowerSuiteSubmenu( string $page_title, string $menu_title, string $menu_slug, callable $callback ): void {
		add_submenu_page(
			'powersuite',
			$page_title,
			$menu_title,
			$this->adminCapability(),
			$menu_slug,
			$callback
		);
	}
}
