<?php
/**
 * Hook Manager - Centralized hook registration and management
 *
 * Coordinates all WordPress hook registrations for the Havenlytics plugin.
 * Provides a single point of management for actions, filters, AJAX handlers,
 * and scheduled events to ensure consistent hook implementation.
 *
 * @package     Havenlytics
 * @subpackage  Core
 * @copyright   Copyright (c) 2025, Havenlytics
 * @license     http://opensource.org/licenses/gpl-2.0.php GNU Public License
 * @since       2.0.0
 */

namespace HvnlyNab\Core;

// Prevent direct access to WordPress files
defined( 'ABSPATH' ) || exit;

/**
 * Import required classes for hook functionality
 */
use HvnlyNab\Core\CacheInvalidator;

/**
 * Hook Manager Class
 *
 * Centralized manager for all WordPress hooks and AJAX handlers in the plugin.
 * Organizes hooks by category and provides consistent security and error handling
 * across all hook implementations.
 *
 * Key responsibilities:
 * - Register all plugin hooks in organized categories
 * - Handle AJAX requests with security validation
 * - Manage scheduled events and cron jobs
 * - Coordinate cache invalidation triggers
 * - Provide plugin action links and activation redirects
 *
 * @since 2.0.0
 */
class HookManager {

	/**
	 * Register all plugin hooks
	 *
	 * Main entry point that coordinates registration of all hook categories.
	 * Called during plugin bootstrap to set up all WordPress integrations.
	 *
	 * @return void
	 */
	public function register_hooks() {
		/**
		 * Register activation and plugin action link hooks
		 */
		$this->register_activation_hooks();

		/**
		 * Register AJAX endpoint handlers for admin interfaces
		 */
		$this->register_ajax_hooks();

		/**
		 * Register cache-related hooks for data consistency
		 */
		$this->register_cache_hooks();

		/**
		 * Register localization and textdomain hooks
		 */
		$this->register_localization_hooks();

		/**
		 * Register admin-specific hooks and scripts
		 */
		$this->register_admin_hooks();

		/**
		 * Register scheduled events and cron jobs
		 */
		$this->register_cron_hooks();
	}

	/**
	 * Register activation and plugin action link hooks
	 *
	 * Handles plugin activation redirect and adds custom links to the
	 * plugins list page for quick access to settings and tools.
	 *
	 * @return void
	 */
	private function register_activation_hooks() {
		/**
		 * Handle activation redirect to conditional page based on property count
		 * Priority 1 ensures this runs before other admin_init hooks
		 */
		add_action( 'admin_init', array( $this, 'maybe_redirect_after_activation' ), 1 );

		/**
		 * Add custom action links to plugins page
		 */
		add_filter( 'plugin_action_links_' . HVNLYNAB_BASENAME, array( $this, 'plugin_action_links' ) );
	}

	/**
	 * OLD REDIRECT METHOD - Kept for reference only
	 *
	 * @deprecated Replaced with conditional redirect based on property count
	 */
	/*
	public function maybe_redirect_after_activation() {
		if ( get_option( 'hvnly_activation_redirect', false ) && current_user_can( 'manage_options' ) ) {
			delete_option( 'hvnly_activation_redirect' );
			update_option( 'hvnly_activation_redirect_done', true );

			if ( isset( $_GET['page'] ) && strpos( sanitize_key( wp_unslash( $_GET['page'] ) ), 'hvnly_property_' ) === 0 ) {
				return;
			}

			wp_safe_redirect( admin_url( 'edit.php?post_type=hvnly_property&page=hvnly_property_settings' ) );
			exit;
		}
	}
	*/

	/**
	 *  REDIRECT METHOD - Only redirects ONCE after activation, not on every page load
	 *
	 * Handles post-activation redirect with intelligent routing:
	 * - If no properties exist -> Import Wizard for quick setup (ONCE)
	 * - If properties exist -> Property Builder for configuration (ONCE)
	 *
	 * The redirect ONLY happens when:
	 * 1. The activation flag is set (set during plugin activation)
	 * 2. AND we haven't redirected before (hvnly_activation_redirect_done is false)
	 * 
	 * This ensures users can navigate away from the redirect page normally afterward.
	 *
	 * @return void
	 * @since 2.0.0
	 */
	public function maybe_redirect_after_activation() {
		/**
		 * CRITICAL: Only proceed if ALL these conditions are met:
		 * 1. User is in admin area
		 * 2. User has manage_options capability
		 * 3. Activation flag is set (from plugin activation)
		 * 4. We haven't already performed a redirect before
		 */
		if ( ! is_admin() || ! current_user_can( 'manage_options' ) ) {
			return;
		}

		// Get the activation flag - this is ONLY set during plugin activation
		$has_activation_flag = get_option( 'hvnly_activation_redirect', false );
		
		// Check if we've already redirected once
		$has_redirected_once = get_option( 'hvnly_activation_redirect_done', false );

		/**
		 * IMPORTANT: We ONLY redirect if:
		 * - The activation flag is set (meaning the plugin was just activated)
		 * - AND we haven't redirected before
		 * 
		 * The property count should NOT trigger redirects on its own.
		 * This ensures users only get redirected ONCE after activation.
		 */
		if ( ! $has_activation_flag || $has_redirected_once ) {
			return;
		}

		/**
		 * Verify we're not in an AJAX request
		 */
		if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
			return;
		}

		/**
		 * Prevent redirect if user is already on a Havenlytics plugin page
		 * Using filter_input safely (without deprecated filters)
		 */
		$page = sanitize_key( filter_input( INPUT_GET, 'page', FILTER_UNSAFE_RAW ) );
		if ( ! empty( $page ) ) {
			if ( strpos( $page, 'hvnly_property_' ) === 0 || 'hvnly-property-import' === $page ) {
				// Still clean up the flag to prevent future redirect attempts
				delete_option( 'hvnly_activation_redirect' );
				update_option( 'hvnly_activation_redirect_done', true );
				return;
			}
		}

		/**
		 * Prevent redirect if already viewing the property list
		 */
		$post_type = sanitize_key( filter_input( INPUT_GET, 'post_type', FILTER_UNSAFE_RAW ) );
		if ( ! empty( $post_type ) ) {
			if ( 'hvnly_property' === $post_type ) {
				$page_check = sanitize_key( filter_input( INPUT_GET, 'page', FILTER_UNSAFE_RAW ) );

				if ( empty( $page_check ) ) {
					// Still clean up the flag to prevent future redirect attempts
					delete_option( 'hvnly_activation_redirect' );
					update_option( 'hvnly_activation_redirect_done', true );
					return;
				}
			}
		}

		/**
		 * Now check property count to determine WHERE to redirect,
		 * but NOT WHETHER to redirect. The redirect decision is already made
		 * based on the activation flag above.
		 */
		$property_count  = wp_count_posts( 'hvnly_property' );
		$published_count = isset( $property_count->publish ) ? absint( $property_count->publish ) : 0;

		/**
		 * Determine redirect destination based on property count
		 */
		if ( 0 === $published_count ) {
			// No properties - send to Import Wizard
			$redirect_url = admin_url( 'edit.php?post_type=hvnly_property&page=hvnly-property-import' );
			$redirect_reason = 'no_properties_import_wizard';
		} else {
			// Has properties - send to Property Settings
			$redirect_url = admin_url( 'edit.php?post_type=hvnly_property&page=hvnly_property_settings' );
			$redirect_reason = 'has_properties_settings';
		}

		/**
		 * CRITICAL: Clear the activation flag and mark as done BEFORE redirect
		 * This ensures the redirect only happens once, ever.
		 */
		delete_option( 'hvnly_activation_redirect' );
		update_option( 'hvnly_activation_redirect_done', true );

		/**
		 * Log redirect for debugging (only in debug mode)
		 */
		if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
			$log_message = sprintf(
				'Havenlytics: ONE-TIME activation redirect - Destination: %s, Reason: %s, Property Count: %d',
				esc_url_raw( $redirect_url ),
				sanitize_text_field( $redirect_reason ),
				$published_count
			);
			// phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
			//error_log( $log_message );
		}

		/**
		 * Perform safe redirect
		 */
		wp_safe_redirect( esc_url_raw( $redirect_url ) );
		exit;
	}

	/**
	 * Register AJAX endpoint handlers
	 *
	 * Sets up AJAX endpoints for cache management and settings updates.
	 * All endpoints include security validation and permission checks.
	 *
	 * @return void
	 */
	private function register_ajax_hooks() {
		/**
		 * Cache management AJAX endpoints
		 */
		add_action( 'wp_ajax_hvnly_clear_cache', array( $this, 'handle_cache_ajax' ) );
		add_action( 'wp_ajax_hvnly_get_cache_stats', array( $this, 'handle_cache_ajax' ) );
		add_action( 'wp_ajax_hvnly_update_cache_settings', array( $this, 'handle_cache_settings_ajax' ) );
	}

	/**
	 * Register cache-related hooks
	 *
	 * Sets up cache invalidation triggers when property data changes.
	 * Ensures cached data remains consistent with database content.
	 *
	 * @return void
	 */
	private function register_cache_hooks() {
		/**
		 * Invalidate cache when properties are saved or deleted
		 */
		add_action( 'save_post_hvnly_property', array( CacheInvalidator::class, 'invalidate' ) );
		add_action( 'delete_post', array( CacheInvalidator::class, 'invalidate' ) );
	}

	/**
	 * Register scheduled event hooks
	 *
	 * Sets up daily cache cleanup and other recurring maintenance tasks.
	 * Uses WordPress cron system for scheduled execution.
	 *
	 * @return void
	 */
	private function register_cron_hooks() {
		/**
		 * Schedule daily cache cleanup if not already scheduled
		 */
		if ( ! wp_next_scheduled( 'hvnly_daily_cache_cleanup' ) ) {
			wp_schedule_event( time(), 'daily', 'hvnly_daily_cache_cleanup' );
		}

		/**
		 * Hook the cache cleanup function to the scheduled event
		 */
		add_action( 'hvnly_daily_cache_cleanup', array( CacheManager::class, 'clear_expired_cache' ) );
	}

	/**
	 * Register localization and internationalization hooks
	 *
	 * Sets up script translations and backward compatibility for custom language files.
	 *
	 * @return void
	 */
	private function register_localization_hooks() {
		/**
		 * Register JS translations in admin
		 */
		add_action( 'init', array( $this, 'localization_setup' ) );

		/**
		 * Handle textdomain loading warnings in debug mode
		 */
		add_action( 'doing_it_wrong_trigger_error', array( $this, 'textdomain_notice' ), 10, 3 );
	}

	/**
	 * Register admin-specific hooks
	 *
	 * Sets up hooks that are only needed in the WordPress admin area.
	 * Includes admin scripts, styles, and admin-only functionality.
	 *
	 * @return void
	 */
	private function register_admin_hooks() {
		/**
		 * Only register admin hooks if in admin area
		 */
		if ( ! is_admin() ) {
			return;
		}

		/**
		 * Enqueue admin scripts and styles
		 */
		add_action( 'admin_enqueue_scripts', array( $this, 'admin_scripts' ) );
	}

	/**
	 * Handle cache-related AJAX requests
	 *
	 * Processes AJAX requests for cache management operations.
	 * Includes security validation, permission checks, and proper response handling.
	 *
	 * @return void Sends JSON response and terminates execution
	 */
	public function handle_cache_ajax() {
		/**
		 * Verify nonce for security
		 */
		if ( ! check_ajax_referer( 'hvnly_cache_nonce', 'nonce', false ) ) {
			wp_send_json_error( esc_html__( 'Security verification failed', 'havenlytics' ) );
		}

		/**
		 * Check user permissions
		 */
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error( esc_html__( 'Insufficient permissions', 'havenlytics' ) );
		}

		/**
		 * Get and sanitize the action parameter
		 */
		$action = filter_input( INPUT_POST, 'action', FILTER_SANITIZE_STRING );
		$action = $action ? sanitize_key( $action ) : '';

		/**
		 * Route to appropriate handler based on action
		 */
		switch ( $action ) {
			case 'hvnly_get_cache_stats':
				/**
				 * Retrieve cache statistics and performance metrics
				 */
				$stats       = CacheManager::get_cache_stats();
				$performance = HVNLY_NAB()->engine()->get_performance_metrics();
				wp_send_json_success(
					array(
						'stats'       => $stats,
						'performance' => $performance,
					)
				);
				break;

			case 'hvnly_clear_cache':
				/**
				 * Clear specific cache types or all cache
				 */
				$cache_type = filter_input( INPUT_POST, 'cache_type', FILTER_SANITIZE_STRING );
				$cache_type = $cache_type ? sanitize_key( $cache_type ) : 'all';
				switch ( $cache_type ) {
					case 'search':
						CacheManager::clear_transients_by_pattern( 'search_' );
						break;
					case 'terms':
						CacheManager::clear_transients_by_pattern( 'terms_' );
						break;
					case 'all':
					default:
						CacheManager::clear_all_cache();
						break;
				}
				wp_send_json_success( esc_html__( 'Cache cleared successfully', 'havenlytics' ) );
				break;

			default:
				wp_send_json_error( esc_html__( 'Unknown action', 'havenlytics' ) );
		}
	}

	/**
	 * Handle cache settings update AJAX requests
	 *
	 * Processes AJAX requests to update cache configuration settings.
	 * Validates input and updates both WordPress options and engine configuration.
	 *
	 * @return void Sends JSON response and terminates execution
	 */
	public function handle_cache_settings_ajax() {
		/**
		 * Verify nonce for security
		 */
		if ( ! check_ajax_referer( 'hvnly_cache_nonce', 'nonce', false ) ) {
			wp_send_json_error( esc_html__( 'Security verification failed', 'havenlytics' ) );
		}

		/**
		 * Check user permissions
		 */
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error( esc_html__( 'Insufficient permissions', 'havenlytics' ) );
		}

		/**
		 * Safely get settings from POST data with fallback using filter_input
		 * This is the WordPress.org recommended pattern for handling POST arrays
		 */
		$raw_settings = filter_input( INPUT_POST, 'settings', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY ) ?: array();
		$settings = $this->sanitize_settings_array( $raw_settings );

		/**
		 * Update each setting in WordPress options
		 */
		foreach ( $settings as $key => $value ) {
			$option_name = 'hvnly_' . sanitize_key( $key );
			update_option( $option_name, $value );
		}

		/**
		 * Prepare configuration for engine update
		 */
		$new_config = array(
			'cache_ttl'          => isset( $settings['cache_ttl'] ) ? absint( $settings['cache_ttl'] ) : HOUR_IN_SECONDS * 6,
			'cache_compression'  => isset( $settings['cache_compression'] ) ? (bool) $settings['cache_compression'] : false,
			'enable_performance' => isset( $settings['cache_debug'] ) ? (bool) $settings['cache_debug'] : false,
		);

		/**
		 * Update engine configuration if engine is available
		 */
		if ( HVNLY_NAB()->engine() ) {
			HVNLY_NAB()->engine()->update_config( $new_config );
		}

		wp_send_json_success( esc_html__( 'Settings updated successfully', 'havenlytics' ) );
	}

	/**
	 * Sanitize settings array recursively
	 *
	 * @param array $settings Raw settings array.
	 * @return array Sanitized settings array.
	 */
	private function sanitize_settings_array( array $settings ): array {
		$sanitized = array();

		foreach ( $settings as $key => $value ) {
			$key = sanitize_key( $key );

			if ( is_array( $value ) ) {
				$sanitized[ $key ] = $this->sanitize_settings_array( $value );
			} elseif ( is_numeric( $value ) ) {
				$sanitized[ $key ] = absint( $value );
			} elseif ( is_bool( $value ) ) {
				$sanitized[ $key ] = (bool) $value;
			} else {
				$sanitized[ $key ] = sanitize_text_field( $value );
			}
		}

		return $sanitized;
	}

	/**
	 * Set up plugin localization and translations
	 *
	 * For WordPress.org plugins, load_plugin_textdomain() is no longer needed
	 * because translations are loaded automatically. We preserve JS translations.
	 *
	 * @return void
	 */
	public function localization_setup() {
		/**
		 * Only keep JS translations for admin scripts
		 */
		if ( is_admin() ) {
			wp_set_script_translations( 'havenlytics-app', 'havenlytics', HVNLYNAB_LANG_DIR );
		}
	}

	/**
	 * Add custom action links to plugins page
	 *
	 * Provides quick access to plugin settings, documentation, and tools
	 * directly from the WordPress plugins list page.
	 *
	 * @param array $links Existing plugin action links.
	 * @return array Modified plugin action links.
	 */
	public function plugin_action_links( $links ) {
		/**
		 * Add settings link
		 */
		// $settings_link = sprintf(
		// 	'<a href="%s">%s</a>',
		// 	esc_url( admin_url( 'edit.php?post_type=hvnly_property&page=hvnly_property_settings' ) ),
		// 	esc_html__( 'Settings', 'havenlytics' )
		// );
		// array_unshift( $links, $settings_link );

		/**
		 * Add documentation link (opens in new tab)
		 */
		$docs_link = sprintf(
			'<a href="%s" target="_blank" rel="noopener noreferrer">%s</a>',
			esc_url( 'https://havenlytics.com/documentation/' ),
			esc_html__( 'Docs', 'havenlytics' )
		);
		$links[] = $docs_link;

		/**
		 * Add import wizard link for quick setup (only if no properties exist)
		 * This is just a link, not a redirect - user can click it if they want
		 */
		$property_count  = wp_count_posts( 'hvnly_property' );
		$published_count = isset( $property_count->publish ) ? absint( $property_count->publish ) : 0;

		if ( 0 === $published_count ) {
			$import_link = sprintf(
				'<a href="%s" style="color:#46b450;font-weight:500;">%s</a>',
				esc_url( admin_url( 'edit.php?post_type=hvnly_property&page=hvnly-property-import' ) ),
				esc_html__( 'Import Demo Properties', 'havenlytics' )
			);
			$links[] = $import_link;
		}

		/**
		 * Add cache clearing link for administrators
		 */
		if ( current_user_can( 'manage_options' ) ) {
			$cache_link = sprintf(
				'<a href="%s">%s</a>',
				esc_url( wp_nonce_url( admin_url( 'edit.php?post_type=hvnly_property&page=hvnly_property_cache' ), 'hvnly_clear_cache' ) ),
				esc_html__( 'Clear Cache', 'havenlytics' )
			);
			$links[] = $cache_link;
		}

		return $links;
	}

	/**
	 * Handle textdomain loading warnings
	 *
	 * Suppresses unnecessary textdomain loading warnings in debug mode
	 * to maintain clean error logs while preserving functionality.
	 *
	 * @param bool   $trigger Whether to trigger the error.
	 * @param string $function The function name that triggered the warning.
	 * @param string $message The warning message.
	 * @return bool Whether to trigger the error.
	 */
	public function textdomain_notice( $trigger, $function, $message ) {
		/**
		 * Only modify behavior in debug mode
		 */
		if ( ! defined( 'WP_DEBUG' ) || ! WP_DEBUG ) {
			return $trigger;
		}

		$text_domain = 'havenlytics';

		/**
		 * Suppress warnings about just-in-time textdomain loading for our domain
		 */
		if (
			strpos( $function, '_load_textdomain_just_in_time' ) !== false &&
			strpos( $message, $text_domain ) !== false
		) {
			return false;
		}

		return $trigger;
	}

	/**
	 * Enqueue admin scripts and styles
	 *
	 * Placeholder method for admin asset enqueuing.
	 * Can be extended to add specific admin scripts and styles.
	 *
	 * @return void
	 */
	public function admin_scripts() {
		// Placeholder for admin script enqueuing
		// Can be extended to add specific admin assets
	}
}