<?php
/**
 * Users admin controller.
 *
 * @package Awesomemotive\Rewardswp\Controllers\Admin
 * @since 1.0.0
 */

namespace Awesomemotive\Rewardswp\Controllers\Admin;

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

use Awesomemotive\Rewardswp\Interfaces\ControllerInterface;
use Awesomemotive\Rewardswp\Services\AssetsService;
use Awesomemotive\Rewardswp\Services\MembersService;
use Exception;
use function Awesomemotive\Rewardswp\Helpers\create_member;
use function Awesomemotive\Rewardswp\Helpers\get_member;
use function Awesomemotive\Rewardswp\Helpers\get_member_by;
use function Awesomemotive\Rewardswp\Helpers\get_user_first_name;
use function Awesomemotive\Rewardswp\Helpers\get_user_last_name;
use function Awesomemotive\Rewardswp\Helpers\rewardswp_log_error;

/**
 * Controller for integrating with WordPress user administration.
 *
 * Adds RewardsWP member functionality to the WordPress user creation and editing screens.
 *
 * @since 1.0.0
 */
class UsersAdminController implements ControllerInterface {

	/**
	 * AJAX nonce for user profile operations.
	 *
	 * @since 1.0.0
	 *
	 * @var string
	 */
	const AJAX_NONCE = 'rewardswp_user_profile_nonce';

	/**
	 * The user profile script handle name.
	 *
	 * @since 1.0.0
	 *
	 * @var string
	 */
	const USER_PROFILE_SCRIPT_HANDLE = 'rewardswp-user-profile';

	/**
	 * The user profile style handle name.
	 *
	 * @since 1.0.0
	 *
	 * @var string
	 */
	const USER_PROFILE_STYLE_HANDLE = 'rewardswp-user-profile-styles';

	/**
	 * Assets service instance.
	 *
	 * @since 1.0.0
	 *
	 * @var AssetsService
	 */
	private AssetsService $assets_service;

	/**
	 * Members service instance.
	 *
	 * @since 1.0.0
	 *
	 * @var MembersService
	 */
	private MembersService $members_service;

	/**
	 * Constructor.
	 *
	 * @since 1.0.0
	 *
	 * @param AssetsService  $assets_service  The assets service instance.
	 * @param MembersService $members_service The members service instance.
	 */
	public function __construct( AssetsService $assets_service, MembersService $members_service ) {
		$this->assets_service  = $assets_service;
		$this->members_service = $members_service;
	}

	/**
	 * Initialize the controller.
	 *
	 * @since 1.0.0
	 *
	 * @return void
	 */
	public function init() {
		// Add field to user creation form
		add_action( 'user_new_form', [ $this, 'add_member_field_to_user_form' ] );

		// Add field to user profile form
		add_action( 'show_user_profile', [ $this, 'add_member_field_to_user_profile' ] );
		add_action( 'edit_user_profile', [ $this, 'add_member_field_to_user_profile' ] );

		// Process the field when user is created
		add_action( 'user_register', [ $this, 'process_member_creation_on_user_register' ] );

		// Process the field when user profile is updated
		add_action( 'personal_options_update', [ $this, 'process_member_update_on_profile_save' ] );
		add_action( 'edit_user_profile_update', [ $this, 'process_member_update_on_profile_save' ] );

		// Enqueue assets for user profile pages
		add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_profile_assets' ] );

		// AJAX handlers for member search
		add_action( 'wp_ajax_rewardswp_search_available_members', [ $this, 'handle_ajax_search_available_members' ] );
	}

	/**
	 * Add member registration field to the user creation form.
	 *
	 * @since 1.0.0
	 *
	 * @param string $type The type of new user form.
	 *
	 * @return void
	 */
	public function add_member_field_to_user_form( string $type ): void {
		// Only show on admin user creation form
		if ( 'add-new-user' !== $type ) {
			return;
		}

		if ( ! current_user_can( 'manage_options' ) ) {
			return;
		}

		wp_nonce_field( 'rewardswp_user_member_nonce', 'rewardswp_user_member_nonce' );
		?>
		<table class="form-table" role="presentation">
			<tr>
				<th scope="row"><?php esc_html_e( 'RewardsWP', 'rewardswp' ); ?></th>
				<td>
					<input
						type="checkbox"
						name="rewardswp_register_as_member"
						id="rewardswp_register_as_member"
						value="1"
					/>
					<label for="rewardswp_register_as_member"><?php esc_html_e( 'Add user to rewards program', 'rewardswp' ); ?></label>
				</td>
			</tr>
		</table>
		<?php
	}

	/**
	 * Add member management field to user profile forms.
	 *
	 * @since 1.0.0
	 *
	 * @param \WP_User $user The user object.
	 *
	 * @return void
	 */
	public function add_member_field_to_user_profile( \WP_User $user ): void {
		if ( ! current_user_can( 'manage_options' ) ) {
			return;
		}

		// Check if user is already a member
		$existing_member = get_member_by( 'user_id', $user->ID );
		$is_member       = ! is_null( $existing_member );

		wp_nonce_field( 'rewardswp_user_member_nonce', 'rewardswp_user_member_nonce' );
		?>
		<h3><?php esc_html_e( 'RewardsWP', 'rewardswp' ); ?></h3>
		<table class="form-table" role="presentation">
			<tr>
				<th scope="row"><?php esc_html_e( 'Member', 'rewardswp' ); ?></th>
				<td>
					<select
						id="rewardswp_linked_member"
						name="rewardswp_linked_member"
						class="rewardswp-member-select"
						data-user-id="<?php echo esc_attr( $user->ID ); ?>"
					>
						<?php if ( $is_member ) : ?>
							<option value="<?php echo esc_attr( $existing_member->id ); ?>" selected>
								<?php
								$display_name = $existing_member->get_full_name() ?: $existing_member->email;
								printf(
									'%s (ID: %d)',
									esc_html( $display_name ),
									esc_attr( $existing_member->id )
								);
								?>
							</option>
						<?php else : ?>
							<option value=""><?php esc_html_e( 'No member linked', 'rewardswp' ); ?></option>
						<?php endif; ?>
					</select>
					<p class="description">
						<?php esc_html_e( 'Search and select a member to link to this user account.', 'rewardswp' ); ?>
					</p>
				</td>
			</tr>
		</table>
		<?php
	}

	/**
	 * Process member creation when a new user is registered.
	 *
	 * @since 1.0.0
	 *
	 * @param int $user_id The newly created user ID.
	 *
	 * @return void
	 */
	public function process_member_creation_on_user_register( int $user_id ): void {
		// Verify nonce
		if ( ! isset( $_POST['rewardswp_user_member_nonce'] ) ||
			! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['rewardswp_user_member_nonce'] ) ), 'rewardswp_user_member_nonce' ) ) {
			return;
		}

		// Check if user should be registered as member.
		$register_as_member = isset( $_POST['rewardswp_register_as_member'] ) && '1' === sanitize_text_field( wp_unslash( $_POST['rewardswp_register_as_member'] ) );

		if ( ! $register_as_member ) {
			return;
		}

		// Check permissions
		if ( ! current_user_can( 'manage_options' ) ) {
			return;
		}

		// Get user data
		$user = get_user_by( 'ID', $user_id );
		if ( ! $user || ! $user instanceof \WP_User ) {
			return;
		}

		// Check if user has a valid email (required for member creation)
		if ( empty( $user->user_email ) || ! is_email( $user->user_email ) ) {
			rewardswp_log_error(
				'Cannot create member for user ID {user_id}: invalid or missing email address.',
				[
					'user_id' => $user_id,
				]
			);
			return;
		}

		// Check if user is already a member (shouldn't happen on new registration, but better safe)
		$existing_member = get_member_by( 'user_id', $user_id );
		if ( ! is_null( $existing_member ) ) {
			return;
		}

		try {
			// Prepare member data
			$member_data = [
				'user_id'    => $user_id,
				'email'      => $user->user_email,
				'first_name' => get_user_first_name( $user_id ) ?: '',
				'last_name'  => get_user_last_name( $user_id ) ?: '',
				'status'     => 'active',
			];

			// Create member
			$member = create_member( $member_data );

			if ( is_wp_error( $member ) ) {
				// Log error but don't interrupt user creation.
				rewardswp_log_error(
					'Failed to create member for user ID {user_id}: {message}',
					[
						'user_id' => $user_id,
						'message' => $member->get_error_message(),
					]
				);
			}
		} catch ( Exception $e ) {
			// Log error but don't interrupt user creation
			rewardswp_log_error(
				'Exception while creating member for user ID {user_id}: {message}',
				[
					'user_id' => $user_id,
					'message' => $e->getMessage(),
				]
			);
		}
	}

	/**
	 * Process member creation/removal when user profile is updated.
	 *
	 * @since 1.0.0
	 *
	 * @param int $user_id The user ID being updated.
	 *
	 * @return void
	 */
	public function process_member_update_on_profile_save( int $user_id ): void {
		// Verify nonce
		if ( ! isset( $_POST['rewardswp_user_member_nonce'] ) ||
			! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['rewardswp_user_member_nonce'] ) ), 'rewardswp_user_member_nonce' ) ) {
			return;
		}

		// Check permissions
		if ( ! current_user_can( 'manage_options' ) ) {
			return;
		}

		// Get current linked member and new selection
		$existing_member   = get_member_by( 'user_id', $user_id );
		$current_member_id = $existing_member ? $existing_member->id : 0;
		$new_member_id     = isset( $_POST['rewardswp_linked_member'] ) ? absint( $_POST['rewardswp_linked_member'] ) : 0;

		// No changes needed
		if ( $current_member_id === $new_member_id ) {
			return;
		}

		try {
			// Handle unlinking current member
			if ( $current_member_id && ! $new_member_id ) {
				// Unlinking member from user
				$existing_member->user_id = null;
				$result                   = $existing_member->update();

				if ( is_wp_error( $result ) ) {
					throw new Exception( $result->get_error_message() );
				}

				add_action(
					'admin_notices',
					function () {
					// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- All output is properly escaped.
						echo '<div class="notice notice-success is-dismissible"><p>' .
						esc_html__( 'Member has been unlinked from this user.', 'rewardswp' ) .
						'</p></div>';
					}
				);
			}
			// Handle linking new member
			elseif ( $new_member_id ) {
				// First unlink current member if exists
				if ( $existing_member ) {
					$existing_member->user_id = null;
					$existing_member->update();
				}

				// Link new member
				$new_member = get_member( $new_member_id );
				if ( ! $new_member ) {
					throw new Exception( __( 'Selected member not found.', 'rewardswp' ) );
				}

				// Check if this member is already linked to another user
				if ( $new_member->user_id && $new_member->user_id != $user_id ) {
					throw new Exception( __( 'This member is already linked to another user.', 'rewardswp' ) );
				}

				$new_member->user_id = $user_id;
				$result              = $new_member->update();

				if ( is_wp_error( $result ) ) {
					throw new Exception( $result->get_error_message() );
				}

				add_action(
					'admin_notices',
					function () {
					// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- All output is properly escaped.
						echo '<div class="notice notice-success is-dismissible"><p>' .
						esc_html__( 'Member has been successfully linked to this user.', 'rewardswp' ) .
						'</p></div>';
					}
				);
			}
		} catch ( Exception $e ) {
			add_action(
				'admin_notices',
				function () use ( $e ) {
				// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- All output is properly escaped.
					echo '<div class="notice notice-error is-dismissible"><p>' .
					esc_html__( 'Error updating member link: ', 'rewardswp' ) .
					esc_html( $e->getMessage() ) .
					'</p></div>';
				}
			);
		}
	}

	/**
	 * Enqueue assets for user profile pages.
	 *
	 * @since 1.0.0
	 *
	 * @return void
	 */
	public function enqueue_profile_assets(): void {
		if ( ! $this->is_user_profile_page() ) {
			return;
		}

		$this->enqueue_user_profile_assets();
	}

	/**
	 * Enqueue user profile specific assets including Select2.
	 *
	 * @since 1.0.0
	 *
	 * @return void
	 */
	private function enqueue_user_profile_assets(): void {
		// Ensure Select2 is loaded (if available from other plugins)
		$select2_handle = $this->assets_service->ensure_select2_loaded();

		// Determine dependencies - only include existing Select2 if available
		$dependencies = [ 'jquery' ];
		if ( 'rewardswp-select2' !== $select2_handle ) {
			$dependencies[] = $select2_handle;
		}

		// Register and enqueue our user profile script (webpack compiled)
		$this->assets_service->register_script(
			self::USER_PROFILE_SCRIPT_HANDLE,
			'user-profile.js',
			$dependencies
		);
		wp_enqueue_script( self::USER_PROFILE_SCRIPT_HANDLE );

		// Register and enqueue user profile styles (webpack compiled)
		// Our custom styles should load after Select2 base styles
		$style_dependencies = [];
		if ( 'rewardswp-select2' === $select2_handle ) {
			$style_dependencies[] = 'rewardswp-select2-styles';
		}

		$this->assets_service->register_style( self::USER_PROFILE_STYLE_HANDLE, 'user-profile-styles.css', $style_dependencies );
		wp_enqueue_style( self::USER_PROFILE_STYLE_HANDLE );

		// Add inline script with localized data specific to user profile functionality
		wp_add_inline_script(
			self::USER_PROFILE_SCRIPT_HANDLE,
			'window.rewardswpUserProfile = ' . wp_json_encode(
				[
					'ajaxUrl'       => admin_url( 'admin-ajax.php' ),
					'nonce'         => wp_create_nonce( self::AJAX_NONCE ),
					'select2Handle' => $select2_handle,
					'strings'       => [
						'searchMembers'  => __( 'Search Members...', 'rewardswp' ),
						'noMemberLinked' => __( 'No member linked', 'rewardswp' ),
						'loadingMembers' => __( 'Loading members...', 'rewardswp' ),
						'errorLoading'   => __( 'Error loading members', 'rewardswp' ),
						'noMembersFound' => __( 'No members found or eligible for assignment', 'rewardswp' ),
					],
				]
			) . ';',
			'before'
		);
	}

	/**
	 * Check if current page is a user profile page.
	 *
	 * @since 1.0.0
	 *
	 * @return bool
	 */
	private function is_user_profile_page(): bool {
		global $pagenow;

		return in_array( $pagenow, [ 'profile.php', 'user-edit.php', 'user-new.php' ], true );
	}

	/**
	 * Handle AJAX request to search available members.
	 *
	 * @since 1.0.0
	 *
	 * @return void
	 */
	public function handle_ajax_search_available_members(): void {
		// Verify nonce using WordPress standard method
		check_ajax_referer( self::AJAX_NONCE, 'nonce' );

		// Check permissions
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error( [ 'message' => esc_html__( 'Insufficient permissions.', 'rewardswp' ) ] );
			return;
		}

		// Get search term and current user ID
		$search_term     = sanitize_text_field( wp_unslash( $_POST['search'] ?? '' ) );
		$current_user_id = isset( $_POST['user_id'] ) ? absint( $_POST['user_id'] ) : 0;

		try {
			// Build query parameters using the abstraction API
			$query_params = [
				'user_id' => [
					'value'   => [ null, 0, $current_user_id ],
					'compare' => 'IN',
				],
			];

			// Add search filtering if provided
			if ( ! empty( $search_term ) ) {
				$query_params['like_query'] = [
					'search_term' => $search_term,
					'columns'     => [
						'first_name',
						'last_name',
						'email',
						'CONCAT(first_name, " ", last_name)',
					],
					'compare'     => 'OR',
				];
			}

			// Get members using our API
			$members = $this->members_service->get_members( $query_params, 50, 1 );

			// Format results for Select2
			$formatted_results = [];

			foreach ( $members as $member ) {
				$display_name = '';
				if ( ! empty( $member->first_name ) || ! empty( $member->last_name ) ) {
					$display_name = trim( $member->first_name . ' ' . $member->last_name );
				}
				if ( empty( $display_name ) ) {
					$display_name = $member->email;
				}

				$formatted_results[] = [
					'id'   => $member->id,
					'text' => sprintf( '%s (ID: %d)', $display_name, $member->id ),
					'data' => [
						'member_id'     => $member->id,
						'first_name'    => $member->first_name,
						'last_name'     => $member->last_name,
						'email'         => $member->email,
						'referral_code' => $member->referral_code,
						'current_user'  => $member->user_id == $current_user_id,
					],
				];
			}

			wp_send_json_success( [ 'results' => $formatted_results ] );

		} catch ( Exception $e ) {
			wp_send_json_error( [ 'message' => esc_html__( 'Error searching members.', 'rewardswp' ) ] );
		}
	}
}
