<?php

namespace FleekDash\Core;

use FleekDash\Interfaces\ModuleInterface;
use FleekDash\Traits\BaseModuleLoggingTrait;
use FleekDash\Traits\BaseModuleOptionsTrait;

// Load debug helpers
if (!function_exists('fleekdash_log_error')) {
    require_once FLEEKDASH_PLUGIN_DIR . 'includes/Core/debug-helpers.php';
}
require_once FLEEKDASH_PLUGIN_DIR . 'includes/Traits/BaseModuleLoggingTrait.php';
require_once FLEEKDASH_PLUGIN_DIR . 'includes/Traits/BaseModuleOptionsTrait.php';

/**
 * Base class for FleekDash modules.
 *
 * Shared wiring and defaults for all plugin modules.
 */
abstract class BaseModule implements ModuleInterface
{
    use BaseModuleLoggingTrait;
    use BaseModuleOptionsTrait;

    /**
     * Module slug / name
     */
    protected string $name;

    /**
     * Module semver
     */
    protected string $version = '1.0.0';

    /**
     * Whether the module finished activation
     */
    protected bool $active = false;

    /**
     * Other modules, plugins, or callables this module requires
     */
    protected array $dependencies = [];

    /**
     * Runtimes where this module may bootstrap
     */
    protected array $contexts = ['frontend', 'admin', 'api'];

    /**
     * Action/filter hooks registered for cleanup
     */
    protected array $hooks = [];

    /**
     * Constructor
     */
    public function __construct()
    {
        $this->name = $this->getName();
        $this->init_base();
    }

    /**
     * Default bootstrap sequence
     */
    protected function init_base()
    {
        // Third-party hook before module setup
        \do_action("fleekdash_before_module_init_{$this->name}", $this);

        // Gate on declared dependencies
        if (!$this->check_dependencies()) {
            return;
        }

        $this->activate();

        // Third-party hook after module setup
        \do_action("fleekdash_after_module_init_{$this->name}", $this);
    }

    /**
     * Module name (child classes may override get_name()).
     */
    public function getName(): string
    {
        if (!$this->name) {
            // Infer module slug from class short name
            $class_name = get_class($this);
            $parts = explode('\\', $class_name);
            $this->name = strtolower(end($parts));
        }
        return $this->name;
    }

    /**
     * Module version string
     */
    public function getVersion()
    {
        return $this->version;
    }

    /**
     * Whether the module is currently active
     */
    public function isActive()
    {
        return $this->active;
    }

    /**
     * Activate: register hooks and fire activation action
     */
    public function activate()
    {
        if (!$this->active) {
            $this->active = true;
            $this->register_hooks();
            \do_action("fleekdash_module_activated_{$this->name}", $this);
        }
    }

    /**
     * Deactivate: remove hooks and fire deactivation action
     */
    public function deactivate()
    {
        if ($this->active) {
            $this->active = false;
            $this->unregister_hooks();
            \do_action("fleekdash_module_deactivated_{$this->name}", $this);
        }
    }

    /**
     * Declared dependency list
     */
    public function getDependencies()
    {
        return $this->dependencies;
    }

    /**
     * Ensure every dependency is available before init
     */
    protected function check_dependencies()
    {
        foreach ($this->dependencies as $dependency) {
            if (!$this->is_dependency_available($dependency)) {
                $this->log_error("Dependency '{$dependency}' not available for module '{$this->name}'");
                return false;
            }
        }
        return true;
    }

    /**
     * Whether a single dependency is satisfied
     */
    protected function is_dependency_available(string $dependency): bool
    {
        // FleekDash module dependency
        $module_manager = ModuleManager::getInstance();
        return $module_manager->isModuleLoaded($dependency)
            || \is_plugin_active($dependency)
            || function_exists($dependency)
            || class_exists($dependency);
    }

    /**
     * Register WordPress hooks (override in child classes)
     */
    protected function register_hooks()
    {
        // Default: no-op
    }

    /**
     * Remove hooks tracked in $this->hooks
     */
    protected function unregister_hooks()
    {
        foreach ($this->hooks as $hook) {
            \remove_action($hook['tag'], $hook['callback'], $hook['priority']);
        }
        $this->hooks = [];
    }

    /**
     * add_action with bookkeeping for unregister_hooks()
     */
    protected function add_action(string $tag, callable|array $callback, int $priority = 10, int $accepted_args = 1): void
    {
        \add_action($tag, $callback, $priority, $accepted_args);
        $this->hooks[] = [
            'type' => 'action',
            'tag' => $tag,
            'callback' => $callback,
            'priority' => $priority,
            'accepted_args' => $accepted_args
        ];
    }

    /**
     * add_filter with bookkeeping for unregister_hooks()
     */
    protected function add_filter(string $tag, callable|array $callback, int $priority = 10, int $accepted_args = 1): void
    {
        \add_filter($tag, $callback, $priority, $accepted_args);
        $this->hooks[] = [
            'type' => 'filter',
            'tag' => $tag,
            'callback' => $callback,
            'priority' => $priority,
            'accepted_args' => $accepted_args
        ];
    }

    /**
     * Contexts this module supports
     */
    public function get_contexts()
    {
        return $this->contexts;
    }

    /**
     * Whether the module should load for a given context key
     */
    public function should_load_in_context(string $context): bool
    {
        return in_array($context, $this->contexts, true);
    }

}
