<?php

/**
 * Base Module
 *
 * Abstract base class for feature modules.
 *
 * @package ProRank\SEO\Modules
 * @since   0.1.0
 */

declare(strict_types=1);

namespace ProRank\SEO\Modules;

use ProRank\SEO\Contracts\ModuleInterface;
use ProRank\SEO\Plugin;

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


/**
 * BaseModule abstract class
 *
 * Provides common functionality for feature modules
 */


abstract class BaseModule implements ModuleInterface {
    
    /**
     * Module slug
     *
     * @var string
     */
    protected string $slug;
    
    /**
     * Module name
     *
     * @var string
     */
    protected string $name;
    
    /**
     * Module description
     *
     * @var string
     */
    protected string $description;
    
    /**
     * Required feature tier
     *
     * @var string
     */
    protected string $feature_tier = 'free';
    
    /**
     * Parent module slug
     *
     * @var string|null
     */
    protected ?string $parent_slug = null;
    
    /**
     * Get module slug
     *
     * @return string
     */
    public function get_slug(): string {
        return $this->slug ?? '';
    }
    
    /**
     * Get module name
     *
     * @return string
     */
    public function get_name(): string {
        // Check if property exists
        if (!isset($this->name)) {
            return '';
        }
        return $this->name;
    }
    
    /**
     * Get module description
     *
     * @return string
     */
    public function get_description(): string {
        // Check if property exists
        if (!isset($this->description)) {
            return '';
        }
        return $this->description;
    }
    
    /**
     * Get module ID (implementation of ModuleInterface)
     *
     * @return string
     */
    public function id(): string {
        return $this->slug;
    }
    
    /**
     * Get required tier (implementation of ModuleInterface)
     *
     * @return string
     */
    public function tier_required(): string {
        return $this->feature_tier;
    }
    
    /**
     * Get settings group (implementation of ModuleInterface)
     *
     * @return string
     */
    public function settings_group(): string {
        return $this->parent_slug ?? 'general';
    }
    
    /**
     * Get required feature tier
     *
     * @return string
     */
    public function get_feature_tier(): string {
        return $this->feature_tier ?? 'free';
    }
    
    /**
     * Get parent module slug
     *
     * @return string|null
     */
    public function get_parent_slug(): ?string {
        return $this->parent_slug;
    }
    
    /**
     * Initialize module
     *
     * @return void
     */
    public function init(): void {
        // Base initialization - can be overridden by child classes
        $this->init_hooks();
    }
    
    /**
     * Check if module is enabled
     *
     * @return bool
     */
    public function is_enabled(): bool {
        $plugin = Plugin::get_instance();

        if ($plugin->is_initialized()) {
            try {
                $module_manager = $plugin->modules();
                if ($module_manager->has_module($this->slug)) {
                    return $module_manager->is_module_enabled($this->slug);
                }

                // If this module slug is not directly registered, still respect its
                // parent group toggle (prevents child runtime hooks when group is OFF).
                if (!empty($this->parent_slug) && $module_manager->has_module($this->parent_slug)) {
                    return $module_manager->is_module_enabled($this->parent_slug);
                }
            } catch (\RuntimeException $e) {
                // Fall back to tier-based check below.
            }

            return $this->feature_tier === 'free';
        }

        // Safe fallback before full plugin bootstrap.
        if ($this->parent_slug === 'performance') {
            return false;
        }

        return $this->feature_tier === 'free';
    }
    
    /**
     * Get module settings
     *
     * For performance modules, reads from the appropriate unified settings option:
     * - prorank_cache_settings: Browser cache, JS/CSS optimization, preload, hints
     * - prorank_asset_optimization_settings: Critical CSS, Unused CSS, INP, fonts
     * - prorank_image_optimization_settings: Image optimization
     * - prorank_database_settings: Database optimization
     *
     * @param string $key     Setting key
     * @param mixed  $default Default value
     * @return mixed
     */
    protected function get_setting(string $key, $default = null) {
        // Performance modules use unified settings options
        if ($this->parent_slug === 'performance') {
            return $this->get_performance_setting($key, $default);
        }

        // Other modules use the old plugin settings approach
        $plugin = Plugin::get_instance();

        try {
            $settings = $plugin->settings();
            $module_key = $this->slug . '_' . $key;
            return $settings->get($module_key, $default);
        } catch (\RuntimeException $e) {
            return $default;
        }
    }

    /**
     * Public wrapper for module settings access.
     *
     * @param string $key Setting key
     * @param mixed  $default Default value
     * @return mixed
     */
    public function get_setting_value(string $key, $default = null) {
        return $this->get_setting($key, $default);
    }

    /**
     * Get performance-related setting from unified options
     *
     * @param string $key Setting key
     * @param mixed $default Default value
     * @return mixed
     */
    protected function get_performance_setting(string $key, $default = null) {
        // Try SettingsManager first
        try {
            $plugin = Plugin::get_instance();
            if ($plugin->is_initialized()) {
                $val = $plugin->settings()->get('performance', $key, null);
                if ($val !== null) {
                    return $this->normalize_setting_value($val, $default);
                }
                
                $val = $plugin->settings()->get('modules', $key, null);
                if ($val !== null) {
                    return $this->normalize_setting_value($val, $default);
                }
                
                $val = $plugin->settings()->get('database_optimization', $key, null);
                if ($val !== null) {
                    return $this->normalize_setting_value($val, $default);
                }

                $val = $plugin->settings()->get('image_optimization', $key, null);
                if ($val !== null) {
                    return $this->normalize_setting_value($val, $default);
                }
            }
        } catch (\Exception $e) {}

        static $cache_settings = null;
        static $asset_settings = null;
        static $image_settings = null;
        static $database_settings = null;

        // Cache-related settings (browser cache, JS/CSS, preload, hints)
        $cache_keys = [
            'browser_cache_enabled', 'browser_cache_images', 'browser_cache_css',
            'browser_cache_js', 'browser_cache_fonts', 'browser_cache_html',
            'js_defer', 'js_delay', 'js_exclude', 'js_combine',
            'css_minify', 'css_combine', 'css_async', 'css_exclude',
            'preload_enabled', 'preload_mode', 'preload_schedule',
            'link_preload_enabled', 'link_preload_delay',
            'prefetch_enabled', 'prefetch_eagerness', 'prefetch_query_strings',
            'prerender_enabled', 'prerender_mode', 'prerender_eagerness',
            'prerender_urls', 'prerender_auto_detect', 'max_prerender_urls',
            'speculation_exclude_patterns', 'enable_logged_in',
            'override_core', 'link_fallback',
            'dns_prefetch_enabled', 'dns_prefetch_hosts',
            'font_preload_enabled', 'font_preload_urls',
            'cache_enabled', 'cache_lifetime', 'cache_exclude_urls',
            'cdn_provider', 'cloudflare_zone_id', 'cloudflare_api_token',
            'bunny_pullzone_id', 'bunny_api_key',
        ];

        // Asset optimization settings
        $asset_keys = [
            'critical_css_enabled', 'critical_css_mode', 'critical_css_manual', 'critical_css_target',
            'unused_css_enabled', 'unused_css_collect', 'unused_css_safelist', 'unused_css_use_cloud',
            'js_minify_enabled', 'js_minify_inline', 'js_advanced_enabled', 'js_advanced_rules',
            'minify_html', 'remove_html_comments',
            'partytown_enabled', 'partytown_auto_detect', 'partytown_categories',
            'inp_optimizer_enabled', 'inp_optimizer_monitoring', 'inp_optimizer_auto_optimize', 'inp_optimizer_sample_rate',
            'lcp_optimizer_enabled', 'lcp_fetchpriority_enabled', 'lcp_preload_lcp',
            'lcp_optimize_first_image', 'lcp_remove_above_fold_lazy', 'lcp_learning_mode',
            'host_google_fonts_locally', 'font_display_swap', 'font_subsetting_enabled',
            'video_optimize_youtube', 'video_optimize_vimeo',
        ];

        // Image optimization settings
        $image_keys = [
            'optimization_method',
            'webp_enabled',
            'webp_quality',
            'avif_enabled',
            'avif_quality',
            'jxl_enabled',
            'jxl_quality',
            'jpegli_enabled',
            'jpeg_quality',
            'png_quality',
            'png_pipeline',
            'smart_compression',
            'compression_type',
            'optimize_on_upload',
            'background_mode',
            'backup_originals',
            'optimize_original_source',
            'lazyload_images',
            'lazyload_iframes',
            'lazyload_videos',
            'lazyload_threshold',
            'cdn_enabled',
            'cdn_url',
            'cloud_provider',
            'cloud_opt_in',
            'cloud_opt_in_at',
            'exclude_paths',
            'exclude_sizes',
            'exclude_patterns',
            'delivery_method',
            'enable_picture_element',
            'custom_media_folders',
            'png_to_jpeg',
            'cmyk_to_rgb',
            'remove_exif',
            'optimize_pdf',
            'generate_retina',
            'no_ai_training',
            'add_noai_to_alt',
        ];

        // Database settings
        $database_keys = [
            'auto_cleanup_enabled', 'cleanup_schedule', 'cleanup_items',
            'revision_limit', 'trash_days', 'opcache_enabled', 'memory_optimization',
            'heartbeat_control', 'heartbeat_frequency', 'admin_ajax_optimization',
        ];

        // Determine which option to read from
        if (in_array($key, $cache_keys, true)) {
            if ($cache_settings === null) {
                $cache_settings = get_option('prorank_cache_settings', []);
            }
            $value = $cache_settings[$key] ?? $default;
            return $this->normalize_setting_value($value, $default);
        }

        if (in_array($key, $asset_keys, true)) {
            if ($asset_settings === null) {
                $asset_settings = get_option('prorank_asset_optimization_settings', []);
            }
            $value = $asset_settings[$key] ?? $default;
            return $this->normalize_setting_value($value, $default);
        }

        if (in_array($key, $image_keys, true)) {
            if ($image_settings === null) {
                $image_settings = get_option('prorank_image_optimization_settings', []);
            }
            $value = $image_settings[$key] ?? $default;
            return $this->normalize_setting_value($value, $default);
        }

        if (in_array($key, $database_keys, true)) {
            if ($database_settings === null) {
                $database_settings = get_option('prorank_database_settings', []);
            }
            $value = $database_settings[$key] ?? $default;
            return $this->normalize_setting_value($value, $default);
        }

        // Fallback: check all options
        if ($cache_settings === null) {
            $cache_settings = get_option('prorank_cache_settings', []);
        }
        if (isset($cache_settings[$key])) {
            return $this->normalize_setting_value($cache_settings[$key], $default);
        }

        if ($asset_settings === null) {
            $asset_settings = get_option('prorank_asset_optimization_settings', []);
        }
        if (isset($asset_settings[$key])) {
            return $this->normalize_setting_value($asset_settings[$key], $default);
        }

        return $default;
    }

    /**
     * Normalize setting value based on default type.
     *
     * @param mixed $value
     * @param mixed $default
     * @return mixed
     */
    protected function normalize_setting_value($value, $default = null) {
        if (!is_bool($default)) {
            return $value;
        }

        $normalized = $this->normalize_boolean_setting($value);
        return $normalized === null ? $default : $normalized;
    }

    /**
     * Convert common bool-like values to a strict boolean.
     *
     * @param mixed $value
     * @return bool|null
     */
    protected function normalize_boolean_setting($value): ?bool {
        if (is_bool($value)) {
            return $value;
        }

        if (is_int($value) || is_float($value)) {
            return ((int) $value) !== 0;
        }

        if (is_string($value)) {
            $normalized = strtolower(trim($value));
            if ($normalized === '') {
                return false;
            }

            if (in_array($normalized, ['1', 'true', 'yes', 'on', 'enabled'], true)) {
                return true;
            }

            if (in_array($normalized, ['0', 'false', 'no', 'off', 'disabled'], true)) {
                return false;
            }
        }

        return null;
    }
    
    /**
     * Update module setting
     *
     * @param string $key   Setting key
     * @param mixed  $value New value
     * @return bool
     */
    protected function update_setting(string $key, $value): bool {
        $plugin = Plugin::get_instance();
        
        try {
            $settings = $plugin->settings();
            $module_key = $this->slug . '_' . $key;
            return $settings->update($module_key, $value);
        } catch (\RuntimeException $e) {
            return false;
        }
    }
    
    /**
     * Register module settings
     *
     * Called during module registration to define settings schema
     *
     * @return void
     */
    protected function register_settings(): void {
        // Override in child classes to register module-specific settings
    }
    
    /**
     * Get the plugin instance
     *
     * @return Plugin
     */
    protected function plugin(): Plugin {
        return Plugin::get_instance();
    }
}
