<?php
/**
 * `wp blaminhor modules ...` — lifecycle commands.
 *
 * @package BlaminhorEssentials
 */

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

if ( ! defined( 'WP_CLI' ) || ! WP_CLI ) {
	return;
}

/**
 * List, inspect, activate and deactivate Blaminhor Essentials modules.
 */
class Blaminhor_Essentials_CLI_Modules {

	use Blaminhor_Essentials_CLI_Helpers;

	/**
	 * List every registered module with its status.
	 *
	 * ## OPTIONS
	 *
	 * [--active-only]
	 * : Only show modules that are currently active.
	 *
	 * [--inactive-only]
	 * : Only show modules that are currently inactive.
	 *
	 * [--category=<category>]
	 * : Filter by category slug (content-media, seo-links, database-migration,
	 *   security-maintenance, emails, performance).
	 *
	 * [--fields=<fields>]
	 * : Limit the output to specific object fields. Defaults to id,name,category,status.
	 *   Available fields: id, name, description, category, status.
	 *
	 * [--format=<format>]
	 * : Render format. Accepted values: table, json, csv, yaml, count, ids. Default: table.
	 *
	 * ## EXAMPLES
	 *
	 *     $ wp blaminhor modules list
	 *     $ wp blaminhor modules list --active-only --format=json
	 *     $ wp blaminhor modules list --category=emails
	 *
	 * @subcommand list
	 * @when after_wp_load
	 *
	 * @param array $args       Positional arguments (unused).
	 * @param array $assoc_args Associative arguments.
	 */
	public function list_( $args, $assoc_args ) {
		$plugin    = $this->plugin();
		$available = $plugin->get_available_modules();
		$active    = $plugin->get_active_modules();

		$active_only   = isset( $assoc_args['active-only'] );
		$inactive_only = isset( $assoc_args['inactive-only'] );
		$category      = isset( $assoc_args['category'] ) ? (string) $assoc_args['category'] : '';

		if ( $active_only && $inactive_only ) {
			WP_CLI::error( __( 'Cannot combine --active-only and --inactive-only.', 'blaminhor-essentials' ) );
		}

		$rows = array();
		foreach ( $available as $id => $module ) {
			$is_active = isset( $active[ $id ] );
			if ( $active_only && ! $is_active ) {
				continue;
			}
			if ( $inactive_only && $is_active ) {
				continue;
			}
			if ( '' !== $category && ( ! isset( $module['category'] ) || $module['category'] !== $category ) ) {
				continue;
			}
			$rows[] = array(
				'id'          => $id,
				'name'        => isset( $module['name'] ) ? $module['name'] : $id,
				'description' => isset( $module['description'] ) ? $module['description'] : '',
				'category'    => isset( $module['category'] ) ? $module['category'] : '',
				'status'      => $is_active ? 'active' : 'inactive',
			);
		}

		$this->format_for_output( $rows, $assoc_args, array( 'id', 'name', 'category', 'status' ) );
	}

	/**
	 * Show detailed information about a single module.
	 *
	 * ## OPTIONS
	 *
	 * <module-id>
	 * : The module slug (e.g. smtp, redirections, seo-manager).
	 *
	 * [--format=<format>]
	 * : Render format. Accepted values: table, json, csv, yaml. Default: table.
	 *
	 * ## EXAMPLES
	 *
	 *     $ wp blaminhor modules info smtp
	 *     $ wp blaminhor modules info redirections --format=json
	 *
	 * @when after_wp_load
	 *
	 * @param array $args       Positional arguments.
	 * @param array $assoc_args Associative arguments.
	 */
	public function info( $args, $assoc_args ) {
		$module_id = isset( $args[0] ) ? (string) $args[0] : '';
		if ( '' === $module_id ) {
			WP_CLI::error( __( 'Missing module ID. Usage: wp blaminhor modules info <module-id>', 'blaminhor-essentials' ) );
		}

		$plugin    = $this->plugin();
		$available = $plugin->get_available_modules();

		if ( ! isset( $available[ $module_id ] ) ) {
			WP_CLI::error( sprintf(
				/* translators: %s: module ID typed by the user. */
				__( 'Unknown module "%s". Run `wp blaminhor modules list` to see available modules.', 'blaminhor-essentials' ),
				$module_id
			) );
		}

		$module    = $available[ $module_id ];
		$is_active = $plugin->is_module_active( $module_id );

		$rows = array(
			array(
				'key'   => 'id',
				'value' => $module_id,
			),
			array(
				'key'   => 'name',
				'value' => isset( $module['name'] ) ? $module['name'] : $module_id,
			),
			array(
				'key'   => 'description',
				'value' => isset( $module['description'] ) ? $module['description'] : '',
			),
			array(
				'key'   => 'category',
				'value' => isset( $module['category'] ) ? $module['category'] : '',
			),
			array(
				'key'   => 'status',
				'value' => $is_active ? 'active' : 'inactive',
			),
		);

		$this->format_for_output( $rows, $assoc_args, array( 'key', 'value' ) );
	}

	/**
	 * Activate a module.
	 *
	 * Honours the module's optional `pre_activation_check()` static method —
	 * conflicts (e.g. another cache plugin already installed) surface as a
	 * WP_CLI error, leaving the active list untouched.
	 *
	 * ## OPTIONS
	 *
	 * <module-id>
	 * : The module slug to activate.
	 *
	 * ## EXAMPLES
	 *
	 *     $ wp blaminhor modules activate smtp
	 *     Success: Module "smtp" activated.
	 *
	 * @when after_wp_load
	 *
	 * @param array $args       Positional arguments.
	 * @param array $assoc_args Associative arguments (unused).
	 */
	public function activate( $args, $assoc_args ) {
		$this->ensure_capabilities();

		$module_id = isset( $args[0] ) ? (string) $args[0] : '';
		if ( '' === $module_id ) {
			WP_CLI::error( __( 'Missing module ID. Usage: wp blaminhor modules activate <module-id>', 'blaminhor-essentials' ) );
		}

		$plugin    = $this->plugin();
		$available = $plugin->get_available_modules_raw();

		if ( ! isset( $available[ $module_id ] ) ) {
			WP_CLI::error( sprintf(
				/* translators: %s: module ID typed by the user. */
				__( 'Unknown module "%s". Run `wp blaminhor modules list` to see available modules.', 'blaminhor-essentials' ),
				$module_id
			) );
		}

		if ( $plugin->is_module_active( $module_id ) ) {
			WP_CLI::warning( sprintf(
				/* translators: %s: module ID */
				__( 'Module "%s" is already active.', 'blaminhor-essentials' ),
				$module_id
			) );
			return;
		}

		$result = $plugin->activate_module( $module_id );

		if ( is_wp_error( $result ) ) {
			WP_CLI::error( $result->get_error_message() );
		}

		if ( false === $result ) {
			WP_CLI::error( sprintf(
				/* translators: %s: module ID */
				__( 'Failed to activate module "%s".', 'blaminhor-essentials' ),
				$module_id
			) );
		}

		blaminhor_essentials_log(
			sprintf( 'Module "%s" activated via WP-CLI.', $module_id ),
			'info',
			'cli',
			array( 'event' => 'module_activate' )
		);

		WP_CLI::success( sprintf(
			/* translators: %s: module ID */
			__( 'Module "%s" activated.', 'blaminhor-essentials' ),
			$module_id
		) );
	}

	/**
	 * Deactivate a module.
	 *
	 * Triggers the module's `on_deactivate()` hook so it can clean up
	 * drop-ins, transients, .htaccess sections, etc.
	 *
	 * ## OPTIONS
	 *
	 * <module-id>
	 * : The module slug to deactivate.
	 *
	 * [--yes]
	 * : Skip the interactive confirmation prompt.
	 *
	 * ## EXAMPLES
	 *
	 *     $ wp blaminhor modules deactivate smtp
	 *     $ wp blaminhor modules deactivate backup --yes
	 *
	 * @when after_wp_load
	 *
	 * @param array $args       Positional arguments.
	 * @param array $assoc_args Associative arguments.
	 */
	public function deactivate( $args, $assoc_args ) {
		$this->ensure_capabilities();

		$module_id = isset( $args[0] ) ? (string) $args[0] : '';
		if ( '' === $module_id ) {
			WP_CLI::error( __( 'Missing module ID. Usage: wp blaminhor modules deactivate <module-id>', 'blaminhor-essentials' ) );
		}

		$plugin    = $this->plugin();
		$available = $plugin->get_available_modules_raw();

		if ( ! isset( $available[ $module_id ] ) ) {
			WP_CLI::error( sprintf(
				/* translators: %s: module ID */
				__( 'Unknown module "%s".', 'blaminhor-essentials' ),
				$module_id
			) );
		}

		if ( ! $plugin->is_module_active( $module_id ) ) {
			WP_CLI::warning( sprintf(
				/* translators: %s: module ID */
				__( 'Module "%s" is already inactive.', 'blaminhor-essentials' ),
				$module_id
			) );
			return;
		}

		WP_CLI::confirm(
			sprintf(
				/* translators: %s: module ID */
				__( 'Deactivate module "%s"? This will run its cleanup hooks.', 'blaminhor-essentials' ),
				$module_id
			),
			$assoc_args
		);

		$result = $plugin->deactivate_module( $module_id );

		if ( false === $result ) {
			WP_CLI::error( sprintf(
				/* translators: %s: module ID */
				__( 'Failed to deactivate module "%s".', 'blaminhor-essentials' ),
				$module_id
			) );
		}

		blaminhor_essentials_log(
			sprintf( 'Module "%s" deactivated via WP-CLI.', $module_id ),
			'info',
			'cli',
			array( 'event' => 'module_deactivate' )
		);

		WP_CLI::success( sprintf(
			/* translators: %s: module ID */
			__( 'Module "%s" deactivated.', 'blaminhor-essentials' ),
			$module_id
		) );
	}

	/**
	 * Print whether a module is active or inactive (porcelain output).
	 *
	 * Exits with status 0 if active, 1 if inactive — convenient for shell
	 * scripts: `wp blaminhor modules status smtp && do_smtp_stuff`.
	 *
	 * ## OPTIONS
	 *
	 * <module-id>
	 * : The module slug to inspect.
	 *
	 * ## EXAMPLES
	 *
	 *     $ wp blaminhor modules status smtp
	 *     active
	 *     $ echo $?
	 *     0
	 *
	 * @when after_wp_load
	 *
	 * @param array $args       Positional arguments.
	 * @param array $assoc_args Associative arguments (unused).
	 */
	public function status( $args, $assoc_args ) {
		$module_id = isset( $args[0] ) ? (string) $args[0] : '';
		if ( '' === $module_id ) {
			WP_CLI::error( __( 'Missing module ID. Usage: wp blaminhor modules status <module-id>', 'blaminhor-essentials' ) );
		}

		$plugin    = $this->plugin();
		$available = $plugin->get_available_modules_raw();

		if ( ! isset( $available[ $module_id ] ) ) {
			WP_CLI::error( sprintf(
				/* translators: %s: module ID */
				__( 'Unknown module "%s".', 'blaminhor-essentials' ),
				$module_id
			) );
		}

		if ( $plugin->is_module_active( $module_id ) ) {
			WP_CLI::line( 'active' );
			return;
		}

		WP_CLI::line( 'inactive' );
		WP_CLI::halt( 1 );
	}
}
