<?php

/**
 * ThemeHandler — Domain handler for WordPress theme lifecycle actions.
 *
 * Owns: search_themes, install_theme, update_theme, bulk_update_themes, delete_theme.
 *
 * The two existing theme abilities (get_theme_info, switch_theme) live in
 * SystemHandler and NavigationHandler respectively — they predate this handler
 * and are left in place to avoid churn.
 *
 * @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 ThemeHandler implements ActionHandlerInterface {

	public function getSupportedActions(): array {
		return array( 'search_themes', 'install_theme', 'update_theme', 'bulk_update_themes', 'delete_theme' );
	}

	public function handle( string $actionId, array $params, bool $dryRun ): array {
		return match ( $actionId ) {
			'search_themes'      => $this->searchThemes( $params ),
			'install_theme'      => $this->installTheme( $params, $dryRun ),
			'update_theme'       => $this->updateTheme( $params, $dryRun ),
			'bulk_update_themes' => $this->bulkUpdateThemes( $params, $dryRun ),
			'delete_theme'       => $this->deleteTheme( $params, $dryRun ),
			default              => throw new \Exception( esc_html( "ThemeHandler: unknown action '{$actionId}'." ) ),
		};
	}

	private function ensureThemeApiLoaded(): void {
		if ( ! function_exists( 'themes_api' ) ) {
			require_once ABSPATH . 'wp-admin/includes/theme.php';
		}
		if ( ! function_exists( 'wp_get_themes' ) ) {
			require_once ABSPATH . 'wp-includes/theme.php';
		}
	}

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

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

		$this->ensureThemeApiLoaded();

		$response = themes_api( 'query_themes', array(
			'search'   => $keyword,
			'per_page' => $limit,
			'fields'   => array(
				'description'    => true,
				'rating'         => true,
				'num_ratings'    => true,
				'downloaded'     => true,
				'requires'       => true,
				'requires_php'   => true,
				'screenshot_url' => true,
				'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->themes ) ) {
			foreach ( $response->themes as $theme ) {
				$is_arr = is_array( $theme );
				$get    = function ( $key ) use ( $theme, $is_arr ) {
					return $is_arr ? ( $theme[ $key ] ?? '' ) : ( $theme->$key ?? '' );
				};

				$results[] = array(
					'name'           => $get( 'name' ),
					'slug'           => $get( 'slug' ),
					'version'        => $get( 'version' ),
					'author'         => wp_strip_all_tags( is_array( $get( 'author' ) ) ? ( $get( 'author' )['display_name'] ?? '' ) : $get( 'author' ) ),
					'description'    => wp_strip_all_tags( (string) $get( 'description' ) ),
					'rating'         => ( (float) $get( 'rating' ) ) / 20,
					'num_ratings'    => (int) $get( 'num_ratings' ),
					'downloaded'     => (int) $get( 'downloaded' ),
					'requires'       => $get( 'requires' ),
					'requires_php'   => $get( 'requires_php' ),
					'screenshot_url' => $get( 'screenshot_url' ),
				);
			}
		}

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

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

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

		$this->ensureThemeApiLoaded();
		require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
		require_once ABSPATH . 'wp-admin/includes/file.php';

		$api = themes_api( 'theme_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 theme information: ' . $api->get_error_message() );
		}

		$skin     = new \Automatic_Upgrader_Skin();
		$upgrader = new \Theme_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_themes_cache();

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

	private function updateTheme( array $params, bool $dryRun ): array {
		$stylesheet = $params['stylesheet'] ?? '';
		if ( empty( $stylesheet ) ) {
			throw new \Exception( 'stylesheet (theme directory name) is required.' );
		}

		$this->ensureThemeApiLoaded();
		$theme = wp_get_theme( $stylesheet );
		if ( ! $theme->exists() ) {
			// phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
			throw new \Exception( "Theme '{$stylesheet}' is not installed." );
		}

		$updates    = get_site_transient( 'update_themes' );
		$has_update = isset( $updates->response[ $stylesheet ] );

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

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

		if ( $dryRun ) {
			return array(
				'action'      => 'Will update theme',
				'theme'       => $stylesheet,
				'current'     => $theme->get( 'Version' ),
				'new_version' => $new_version,
				'warning'     => 'Ensure you have a backup before updating themes.',
			);
		}

		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 \Theme_Upgrader( $skin );
		$result      = $upgrader->upgrade( $stylesheet, 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_themes_cache( $clear_cache );
		$refreshed      = wp_get_theme( $stylesheet );
		$actual_version = $refreshed->get( 'Version' ) ?: 'unknown';
		$previous       = $theme->get( 'Version' ) ?: 'unknown';

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

		return array(
			'success'          => true,
			'message'          => "Theme '{$stylesheet}' updated from {$previous} to {$actual_version}.",
			'theme'            => $stylesheet,
			'previous_version' => $previous,
			'new_version'      => $actual_version,
		);
	}

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

		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 \Theme_Upgrader( $skin );

		$valid = array();
		foreach ( $stylesheets as $stylesheet ) {
			$theme = wp_get_theme( $stylesheet );
			if ( $theme->exists() ) {
				$valid[] = $stylesheet;
			}
		}

		if ( empty( $valid ) ) {
			throw new \Exception( 'None of the provided stylesheets matched installed themes.' );
		}

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

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

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

	private function deleteTheme( array $params, bool $dryRun ): array {
		$stylesheet = $params['stylesheet'] ?? '';
		if ( empty( $stylesheet ) ) {
			throw new \Exception( 'stylesheet (theme directory name) is required.' );
		}

		$this->ensureThemeApiLoaded();
		$theme = wp_get_theme( $stylesheet );
		if ( ! $theme->exists() ) {
			// phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
			throw new \Exception( "Theme '{$stylesheet}' is not installed." );
		}

		$active = wp_get_theme();
		if ( $active->get_stylesheet() === $stylesheet ) {
			throw new \Exception( 'Cannot delete the currently active theme. Switch to another theme first using switch_theme.' );
		}
		// Block deleting the parent of an active child theme — would brick the site.
		if ( $active->get_template() === $stylesheet ) {
			// phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
			throw new \Exception( "Cannot delete '{$stylesheet}' — it is the parent theme of the active child theme. Switch to another theme first." );
		}

		if ( $dryRun ) {
			return array(
				'action'  => 'Will delete theme',
				'theme'   => $stylesheet,
				'name'    => $theme->get( 'Name' ),
				'version' => $theme->get( 'Version' ),
				'warning' => 'This will permanently remove the theme files. Backups of theme files are NOT made automatically.',
			);
		}

		if ( ! function_exists( 'delete_theme' ) ) {
			require_once ABSPATH . 'wp-admin/includes/theme.php';
		}
		if ( ! function_exists( 'WP_Filesystem' ) ) {
			require_once ABSPATH . 'wp-admin/includes/file.php';
		}

		$result = delete_theme( $stylesheet );

		if ( is_wp_error( $result ) ) {
			// phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
			throw new \Exception( 'Delete failed: ' . $result->get_error_message() );
		}
		if ( $result === false || $result === null ) {
			throw new \Exception( 'Delete failed. Check filesystem permissions.' );
		}

		wp_clean_themes_cache();

		return array(
			'success' => true,
			'message' => "Theme '{$stylesheet}' deleted.",
			'theme'   => $stylesheet,
		);
	}
}
