<?php
/**
 * AbstractModule — Base class for every UltraGuard Pro feature module.
 *
 * Provides:
 *   • Constructor injection of Plugin (and therefore every core service).
 *   • Convenience shortcuts: $this->settings, $this->cache, $this->utils.
 *   • License-aware is_enabled() — gates pro-only modules before checking settings.
 *   • requires_pro() — override in pro-only child classes to return true.
 *   • get_table() helper — lazy DB table resolution via DatabaseTablesModule.
 *   • option() / option_enabled() — setting read shortcuts.
 *   • license() — returns the LicenseInfo singleton for inline checks.
 *
 * Lifecycle:
 *   ModuleRegistry calls is_enabled() + manager->is_active($id). If both are
 *   true, boot() is called once. Modules MUST NOT call other module methods
 *   directly — use WordPress actions/filters for cross-module communication.
 *
 * @package UltraguardPro\modules\core
 */

namespace UltraguardPro\modules\core;

use UltraguardPro\Plugin;
use UltraguardPro\contracts\ModuleInterface;
use UltraguardPro\support\LicenseInfo;

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

abstract class AbstractModule implements ModuleInterface {

    /** @var Plugin */
    protected Plugin $plugin;

    /** @var \UltraguardPro\core\CacheManager */
    protected \UltraguardPro\core\CacheManager $cache;

    /** @var \UltraguardPro\modules\settings\Settings */
    protected \UltraguardPro\modules\settings\Settings $settings;

    /** @var \UltraguardPro\core\Utils */
    protected \UltraguardPro\core\Utils $utils;

    /**
     * @param Plugin $plugin  The root plugin singleton.
     */
    public function __construct( Plugin $plugin ) {
        $this->plugin   = $plugin;
        $this->cache    = $plugin->cache;
        $this->settings = $plugin->settings;
        $this->utils    = $plugin->utils;
    }

    // ── Abstract members ──────────────────────────────────────────────────────

    abstract public function get_id(): string;
    abstract public function boot(): void;

    // ── License contract ──────────────────────────────────────────────────────

    /**
     * Override in pro-only child modules to return true.
     *
     * When this returns true, is_enabled() will silently return false for any
     * user who does not hold a Pro license — the module never boots, no error
     * is logged, and the UI shows an upgrade CTA instead of activate/deactivate.
     *
     * @return bool
     */
    protected function requires_pro(): bool {
        return false;
    }

    /**
     * Allow a Pro-only module to boot in preview mode for free users.
     *
     * Preview mode is intended for admin visibility only: pages, cards, and
     * read-only dashboards remain visible, while runtime hooks and paid actions
     * should be gated by the module itself.
     */
    protected function allow_preview_mode(): bool {
        return false;
    }

    /**
     * Whether the module is currently booting in free-user preview mode.
     */
    protected function is_preview_mode(): bool {
        return $this->requires_pro() && ! $this->license()->isPro();
    }

    // ── ModuleInterface: is_enabled() ─────────────────────────────────────────

    /**
     * Two-stage gate:
     *   1. License check — if requires_pro() and user is on free plan → false.
     *   2. Settings check — reads the "{module_id}_enabled" option (default: true).
     *
     * ModuleRegistry calls this before boot(). If false, the module is silently
     * skipped — no hooks registered, no DB queries, no admin menu entries.
     *
     * @return bool
     */
    public function is_enabled(): bool {
        if ( $this->requires_pro() && ! $this->license()->isPro() && ! $this->allow_preview_mode() ) {
            return false;
        }
        return (bool) $this->settings->get_option( $this->get_id() . '_enabled', true );
    }

    // ── Convenience helpers ───────────────────────────────────────────────────

    /**
     * LicenseInfo singleton — use for inline pro-feature gates inside boot().
     *
     * @return LicenseInfo
     */
    protected function license(): LicenseInfo {
        return LicenseInfo::instance();
    }

    /**
     * Lazily retrieve a database table object by its registry key.
     * Returns null if the DatabaseTablesModule is not yet available.
     *
     * @param  string $table_key  e.g. 'scan_results', 'firewall_logs'
     * @return \UltraguardPro\db\BaseTable|null
     */
    protected function get_table( string $table_key ) {
        $db = $this->plugin->modules->get_db_tables();
        return $db ? $db->get_table( $table_key ) : null;
    }

    /**
     * Read a setting value.
     *
     * @param  string $key
     * @param  mixed  $default
     * @return mixed
     */
    protected function option( string $key, $default = null ) {
        return $this->settings->get_option( $key, $default );
    }

    /**
     * Read a boolean setting.
     *
     * @param  string $key
     * @return bool
     */
    protected function option_enabled( string $key ): bool {
        return (bool) $this->option( $key, false );
    }
}
