<?php
/**
 * Shared helpers for Blaminhor Essentials WP-CLI commands.
 *
 * @package BlaminhorEssentials
 */

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

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

/**
 * Reusable helpers shared across the `wp blaminhor` command tree.
 */
trait Blaminhor_Essentials_CLI_Helpers {

	/**
	 * Abort the current command unless the running user can manage the plugin.
	 *
	 * WP-CLI honours --user=<login> for capability checks. A CI environment
	 * invoking commands as a low-privilege role must not be able to mutate
	 * sensitive settings (SMTP credentials, redirections, etc.).
	 */
	protected function ensure_capabilities() {
		if ( ! function_exists( 'blaminhor_essentials_current_user_can_manage' ) ) {
			WP_CLI::error( __( 'Blaminhor Essentials helpers are not loaded.', 'blaminhor-essentials' ) );
		}
		if ( ! blaminhor_essentials_current_user_can_manage() ) {
			WP_CLI::error( __( 'Insufficient capabilities. Run with --user=<admin-login> or as an administrator.', 'blaminhor-essentials' ) );
		}
	}

	/**
	 * Coerce a CLI-style boolean ("1", "true", "yes", "on", "0", "false", "no", "off") into a real bool.
	 *
	 * @param mixed $value Raw value passed via --flag=value.
	 * @return bool
	 */
	protected function parse_bool( $value ) {
		if ( is_bool( $value ) ) {
			return $value;
		}
		if ( is_numeric( $value ) ) {
			return (int) $value !== 0;
		}
		if ( ! is_string( $value ) ) {
			return false;
		}
		return in_array( strtolower( trim( $value ) ), array( '1', 'true', 'yes', 'on' ), true );
	}

	/**
	 * Mask a credential before printing it.
	 *
	 * @param string $value       Raw secret.
	 * @param int    $reveal_last Number of trailing chars to keep visible (0 = none).
	 * @return string
	 */
	protected function mask_sensitive( $value, $reveal_last = 0 ) {
		$value = (string) $value;
		if ( '' === $value ) {
			return '';
		}
		$length = strlen( $value );
		if ( $reveal_last > 0 && $length > $reveal_last ) {
			return str_repeat( '*', max( 3, $length - $reveal_last ) ) . substr( $value, -$reveal_last );
		}
		return '***';
	}

	/**
	 * Render items through the standard WP-CLI formatter (table/json/csv/yaml/ids/count).
	 *
	 * The `ids` format is intercepted here because the underlying formatter
	 * expects a flat list of scalars to implode() — it does not auto-pluck
	 * the first field from associative rows. We extract the first column
	 * (conventionally the row's ID) and print it space-separated, matching
	 * what `wp post list --format=ids`, `wp plugin list --format=ids`, etc. do.
	 *
	 * @param array $items          Array of associative arrays.
	 * @param array $assoc_args     CLI assoc args (must accept `format`, `fields` overrides).
	 * @param array $default_fields Default field list to expose; index 0 is treated as the ID column.
	 */
	protected function format_for_output( $items, $assoc_args, $default_fields ) {
		$format = isset( $assoc_args['format'] ) ? (string) $assoc_args['format'] : 'table';
		if ( 'ids' === $format ) {
			$id_field = isset( $default_fields[0] ) ? $default_fields[0] : 'id';
			$ids      = array();
			foreach ( $items as $item ) {
				if ( is_object( $item ) ) {
					$ids[] = isset( $item->{$id_field} ) ? $item->{$id_field} : '';
				} elseif ( is_array( $item ) ) {
					$ids[] = isset( $item[ $id_field ] ) ? $item[ $id_field ] : '';
				}
			}
			WP_CLI::line( implode( ' ', array_filter( $ids, 'strlen' ) ) );
			return;
		}

		$assoc_args = wp_parse_args(
			$assoc_args,
			array(
				'format' => 'table',
				'fields' => $default_fields,
			)
		);
		$formatter = new \WP_CLI\Formatter( $assoc_args, $default_fields );
		$formatter->display_items( $items );
	}

	/**
	 * Resolve the plugin singleton, aborting with a clear error if unavailable.
	 *
	 * @return Blaminhor_Essentials
	 */
	protected function plugin() {
		if ( ! function_exists( 'blaminhor_essentials' ) ) {
			WP_CLI::error( __( 'Blaminhor Essentials is not loaded.', 'blaminhor-essentials' ) );
		}
		return blaminhor_essentials();
	}
}
