<?php

/**
 * PluginHandler — Domain handler for WordPress plugin management actions.
 *
 * Owns: audit_plugins, manage_plugins, update_plugin, search_plugins
 *
 * Note: diagnose_seo and audit_security are complex diagnostic tools that
 * reference many site-wide concerns. They are intentionally left in
 * ActionExecutor for future extraction into a dedicated DiagnosticsHandler
 * in Phase 4.
 *
 * @package LolaCore\Actions\Handlers
 * @license GPL-2.0-or-later
 */

declare( strict_types=1 );

namespace LolaCore\Actions\Handlers;

use LolaCore\Actions\Contracts\ActionHandlerInterface;

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

class PluginHandler implements ActionHandlerInterface {

	public function getSupportedActions(): array {
		return array( 'audit_plugins', 'toggle_plugin', 'update_plugin', 'search_plugins', 'install_plugin', 'bulk_update_plugins' );
	}

	public function handle( string $actionId, array $params, bool $dryRun ): array {
		return match ( $actionId ) {
			'audit_plugins'  => $this->auditPlugins( $params ),
			'toggle_plugin'  => $this->managePlugins( $params, $dryRun ),
			'update_plugin'  => $this->updatePlugin( $params, $dryRun ),
			'search_plugins'      => $this->searchPlugins( $params ),
			'install_plugin'      => $this->installPlugin( $params, $dryRun ),
			'bulk_update_plugins' => $this->bulkUpdatePlugins( $params, $dryRun ),
			default               => throw new \Exception( esc_html( "PluginHandler: unknown action '{$actionId}'." ) ),
		};
	}

	private function ensurePluginApiLoaded(): void {
		if ( ! function_exists( 'get_plugins' ) ) {
			require_once ABSPATH . 'wp-admin/includes/plugin.php';
		}
	}

	private function auditPlugins( array $params ): array {
		$this->ensurePluginApiLoaded();

		// Force fresh data.
		wp_clean_plugins_cache();
		delete_site_transient( 'update_plugins' );
		wp_update_plugins();

		$all_plugins = get_plugins();
		$active      = get_option( 'active_plugins', array() );
		$updates     = get_site_transient( 'update_plugins' );

		$result = array();
		foreach ( $all_plugins as $file => $data ) {
			$result[] = array(
				'slug'        => dirname( $file ),
				'name'        => $data['Name'],
				'version'     => $data['Version'],
				'is_active'   => in_array( $file, $active, true ),
				'has_update'  => isset( $updates->response[ $file ] ),
				'new_version' => isset( $updates->response[ $file ] ) ? $updates->response[ $file ]->new_version : null,
			);
		}
		return array( 'plugins' => $result );
	}

	private function managePlugins( array $params, bool $dryRun ): array {
		$action = $params['action'] ?? '';
		$slug   = $params['slug'] ?? '';

		if ( ! in_array( $action, array( 'activate', 'deactivate', 'delete' ), true ) ) {
			throw new \Exception( "Invalid action. Use 'activate', 'deactivate', or 'delete'." );
		}
		if ( empty( $slug ) ) {
			throw new \Exception( 'Plugin slug is required.' );
		}

		$this->ensurePluginApiLoaded();
		$all_plugins = get_plugins();
		$plugin_file = null;
		foreach ( $all_plugins as $file => $data ) {
			if ( dirname( $file ) === $slug || $file === $slug ) {
				$plugin_file = $file;
				break;
			}
		}
		if ( ! $plugin_file ) {
			// phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
			throw new \Exception( "Plugin with slug '{$slug}' not found." );
		}

		$is_active   = is_plugin_active( $plugin_file );
		$plugin_name = $all_plugins[ $plugin_file ]['Name'] ?? $slug;

		if ( $dryRun ) {
			return array(
				'action'      => "Will {$action} plugin",
				'slug'        => $slug,
				'plugin_name' => $plugin_name,
				'is_active'   => $is_active,
			);
		}

		if ( $action === 'activate' ) {
			$result = activate_plugin( $plugin_file );
			if ( is_wp_error( $result ) ) {
				throw new \Exception( esc_html( $result->get_error_message() ) );
			}
			return array( 'success' => true, 'message' => "Plugin '{$plugin_name}' activated." );
		}

		if ( $action === 'deactivate' ) {
			deactivate_plugins( $plugin_file );
			return array( 'success' => true, 'message' => "Plugin '{$plugin_name}' deactivated." );
		}

		// delete — only allowed on inactive plugins.
		if ( $is_active ) {
			throw new \Exception( "Cannot delete an active plugin. Deactivate it first." );
		}
		if ( ! function_exists( 'delete_plugins' ) ) {
			require_once ABSPATH . 'wp-admin/includes/plugin.php';
		}
		$result = delete_plugins( array( $plugin_file ) );
		if ( is_wp_error( $result ) ) {
			throw new \Exception( esc_html( $result->get_error_message() ) );
		}
		return array( 'success' => true, 'message' => "Plugin '{$plugin_name}' deleted." );
	}

	private function updatePlugin( array $params, bool $dryRun ): array {
		$slug = $params['slug'] ?? '';
		if ( empty( $slug ) ) {
			throw new \Exception( 'Plugin slug is required.' );
		}

		$this->ensurePluginApiLoaded();
		$all_plugins = get_plugins();
		$plugin_file = null;
		foreach ( $all_plugins as $file => $data ) {
			if ( dirname( $file ) === $slug || $file === $slug ) {
				$plugin_file = $file;
				break;
			}
		}
		if ( ! $plugin_file ) {
			// phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
			throw new \Exception( "Plugin with slug '{$slug}' not found." );
		}

		$updates    = get_site_transient( 'update_plugins' );
		$has_update = isset( $updates->response[ $plugin_file ] );

		if ( ! $has_update ) {
			return array( 'success' => false, 'message' => "Plugin '{$slug}' is already up to date. No update available." );
		}

		$new_version = $updates->response[ $plugin_file ]->new_version ?? 'unknown';

		if ( $dryRun ) {
			return array(
				'action'      => 'Will update plugin',
				'plugin'      => $slug,
				'current'     => $all_plugins[ $plugin_file ]['Version'] ?? 'unknown',
				'new_version' => $new_version,
				'warning'     => 'Ensure you have a backup before updating plugins.',
			);
		}

		require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
		require_once ABSPATH . 'wp-admin/includes/file.php';

		$clear_cache = $params['clear_update_cache'] ?? true;
		$skin        = new \Automatic_Upgrader_Skin();
		$upgrader    = new \Plugin_Upgrader( $skin );
		$result      = $upgrader->upgrade( $plugin_file, array( 'clear_update_cache' => $clear_cache ) );

		if ( is_wp_error( $result ) ) {
			// phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
			throw new \Exception( 'Update failed: ' . $result->get_error_message() );
		}
		if ( ! $result ) {
			$error = $skin->result;
			if ( is_wp_error( $error ) ) {
				// phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
				throw new \Exception( 'Update failed: ' . $error->get_error_message() );
			}
			throw new \Exception( 'Update failed for unknown reason. Check file permissions and ensure the filesystem is accessible.' );
		}

		wp_clean_plugins_cache( $clear_cache );
		$refreshed_plugins = get_plugins();
		$actual_version    = $refreshed_plugins[ $plugin_file ]['Version'] ?? 'unknown';
		$previous_version  = $all_plugins[ $plugin_file ]['Version'] ?? 'unknown';

		if ( $actual_version === $previous_version ) {
			throw new \Exception(
				esc_html(
					"Update appeared to succeed but the plugin version did not change (still {$actual_version}). " .
					'Check file permissions and disk space.'
				)
			);
		}

		return array(
			'success'          => true,
			'message'          => "Plugin '{$slug}' updated from {$previous_version} to {$actual_version}.",
			'plugin'           => $slug,
			'previous_version' => $previous_version,
			'new_version'      => $actual_version,
		);
	}

	private function searchPlugins( array $params ): array {
		$keyword = $params['keyword'] ?? '';
		$limit   = min( (int) ( $params['limit'] ?? 5 ), 10 );

		if ( empty( $keyword ) ) {
			throw new \Exception( 'A search keyword is required.' );
		}

		if ( ! function_exists( 'plugins_api' ) ) {
			require_once ABSPATH . 'wp-admin/includes/plugin-install.php';
		}

		$response = plugins_api( 'query_plugins', array(
			'search'   => $keyword,
			'per_page' => $limit,
			'fields'   => array(
				'short_description' => true,
				'active_installs'   => true,
				'rating'            => true,
				'num_ratings'       => true,
				'tested'            => true,
				'requires'          => true,
				'requires_php'      => true,
				'download_link'     => false,
				'sections'          => false,
				'tags'              => false,
			),
		) );

		if ( is_wp_error( $response ) ) {
			// phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
			throw new \Exception( 'WordPress.org API error: ' . $response->get_error_message() );
		}

		$results = array();
		if ( ! empty( $response->plugins ) ) {
			foreach ( $response->plugins as $plugin ) {
				$is_arr = is_array( $plugin );
				$get    = function ( $key ) use ( $plugin, $is_arr ) {
					return $is_arr ? ( $plugin[ $key ] ?? '' ) : ( $plugin->$key ?? '' );
				};

				$results[] = array(
					'name'              => $get( 'name' ),
					'slug'              => $get( 'slug' ),
					'version'           => $get( 'version' ),
					'author'            => wp_strip_all_tags( $get( 'author' ) ),
					'short_description' => $get( 'short_description' ),
					'active_installs'   => (int) $get( 'active_installs' ),
					'rating'            => ( (float) $get( 'rating' ) ) / 20,
					'num_ratings'       => (int) $get( 'num_ratings' ),
					'tested'            => $get( 'tested' ),
					'requires_php'      => $get( 'requires_php' ),
				);
			}
		}

		return array(
			'keyword'     => $keyword,
			'total_found' => $response->info['results'] ?? count( $results ),
			'showing'     => count( $results ),
			'plugins'     => $results,
		);
	}

	private function installPlugin( array $params, bool $dryRun ): array {
		$slug = $params['slug'] ?? '';
		if ( empty( $slug ) ) {
			throw new \Exception( 'Plugin slug is required for installation.' );
		}

		if ( $dryRun ) {
			return array(
				'action'      => 'Will install plugin',
				'plugin'      => $slug,
				'warning'     => 'Ensure you trust the plugin source before installing.',
			);
		}

		if ( ! function_exists( 'plugins_api' ) ) {
			require_once ABSPATH . 'wp-admin/includes/plugin-install.php';
		}
		require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
		require_once ABSPATH . 'wp-admin/includes/file.php';

		$api = plugins_api( 'plugin_information', array(
			'slug'   => $slug,
			'fields' => array( 'sections' => false ),
		) );

		if ( is_wp_error( $api ) ) {
			// phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
			throw new \Exception( 'Failed to retrieve plugin information: ' . $api->get_error_message() );
		}

		$skin     = new \Automatic_Upgrader_Skin();
		$upgrader = new \Plugin_Upgrader( $skin );
		$result   = $upgrader->install( $api->download_link );

		if ( is_wp_error( $result ) ) {
			// phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
			throw new \Exception( 'Installation failed: ' . $result->get_error_message() );
		}
		if ( ! $result ) {
			$error = $skin->result;
			if ( is_wp_error( $error ) ) {
				// phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
				throw new \Exception( 'Installation failed: ' . $error->get_error_message() );
			}
			throw new \Exception( 'Installation failed for unknown reason. Check file permissions and ensure the filesystem is accessible.' );
		}

		wp_clean_plugins_cache();

		return array(
			'success' => true,
			'message' => "Plugin '{$api->name}' installed successfully. It is currently inactive. You can activate it using toggle_plugin.",
			'plugin'  => $slug,
		);
	}

	private function bulkUpdatePlugins( array $params, bool $dryRun ): array {
		$slugs = $params['slugs'] ?? array();
		if ( empty( $slugs ) || ! is_array( $slugs ) ) {
			throw new \Exception( 'An array of plugin slugs is required.' );
		}
		if ( $dryRun ) {
			return array(
				'action' => 'Will update multiple plugins',
				'count'  => count( $slugs ),
				'slugs'  => $slugs,
			);
		}

		require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
		require_once ABSPATH . 'wp-admin/includes/file.php';

		$skin     = new \Automatic_Upgrader_Skin();
		$upgrader = new \Plugin_Upgrader( $skin );
		
		$files = array();
		$all_plugins = get_plugins();
		foreach ( $slugs as $slug ) {
			foreach ( $all_plugins as $file => $data ) {
				if ( dirname( $file ) === $slug || $file === $slug ) {
					$files[] = $file;
					break;
				}
			}
		}
		
		if ( empty( $files ) ) {
			throw new \Exception( 'None of the provided slugs matched installed plugins.' );
		}

		$result = $upgrader->bulk_upgrade( $files );

		if ( empty( $result ) ) {
			throw new \Exception( 'Bulk update failed: check filesystem permissions.' );
		}
		wp_clean_plugins_cache();

		return array(
			'success' => true,
			'message' => count( $result ) . ' plugin(s) updated.',
			'results' => $result,
		);
	}
}
