<?php
/**
 * Global Settings class.
 *
 * @package suremembers
 *
 * @since 1.0.0
 */

namespace SureMembers\Admin;

use SureMembers\Inc\Access;
use SureMembers\Inc\Access_Groups;
use SureMembers\Inc\Settings;
use SureMembers\Inc\Traits\Get_Instance;
use SureMembers\Inc\Utils;

defined( 'ABSPATH' ) || exit;

/**
 * Global settings class.
 *
 * @since 1.0.0
 */
class Settings_Screen {
	use Get_Instance;

	/**
	 * Class Constructor.
	 *
	 * @since 1.0.0
	 */
	public function __construct() {

		// All legacy AJAX handlers have been removed - now using REST API only.
		// REST API endpoints are in inc/routers/settings.php.
		// @deprecated 2.0.0 All AJAX endpoints replaced with REST API endpoints at /wp-json/suremembers/v1/.

		add_filter( 'pre_set_site_transient_update_plugins', [ $this, 'add_suremembers_logo' ] );
	}

	/**
	 * Update email template settings (returns data instead of echoing JSON).
	 *
	 * @param string $settings_data JSON string or array of settings data.
	 * @param string $setting_key Settings key.
	 *
	 * @return array{success: bool, data?: array<string, mixed>, message?: string} Result array.
	 *
	 * @since 1.10.14
	 */
	public function update_email_global_template_settings_data( $settings_data, $setting_key ): array {
		// Check user permission.
		if ( ! current_user_can( 'manage_options' ) ) {
			return [
				'success' => false,
				'message' => __( 'Current user does not have the required permission.', 'suremembers' ),
			];
		}

		// Verify the presence of setting data.
		if ( empty( $settings_data ) ) {
			return [
				'success' => false,
				'message' => __( 'Settings cannot be empty.', 'suremembers' ),
			];
		}

		if ( empty( $setting_key ) ) {
			return [
				'success' => false,
				'message' => __( 'Setting key is required to save data.', 'suremembers' ),
			];
		}

		// Decode if it's a JSON string.
		if ( is_string( $settings_data ) ) {
			$settings_data = json_decode( stripslashes_deep( $settings_data ), true, 512, JSON_OBJECT_AS_ARRAY );
		}

		// Sending an array of the keys which we need to allow the basic HTML in the database allowed by the WordPress.
		$data_to_allow_wp_kses = [ 'user_onboarding_content', 'reset_email_content', 'access_exp_content' ];

		$settings_data = is_array( $settings_data ) ? $this->sanitize_settings( $settings_data, $data_to_allow_wp_kses ) : [];

		Settings::update_setting( $setting_key, $settings_data );

		return [
			'success' => true,
			'data'    => [
				'message'       => __( 'Email template updated successfully.', 'suremembers' ),
				'settings_data' => $settings_data,
			],
		];
	}

	/**
	 * Import user CSV data.
	 *
	 * @param array<string, mixed> $user_data User data from CSV.
	 * @param bool                 $send_onboarding_email Whether to send onboarding email.
	 * @param bool                 $send_reset_pass_email Whether to send reset password email.
	 *
	 * @return array{success: bool, data?: array<string, mixed>, message?: string} Result of the import operation.
	 *
	 * @since 1.9.0
	 */
	public static function suremembers_import_users_data( $user_data, $send_onboarding_email = false, $send_reset_pass_email = false ): array {
		// Check user permission.
		if ( ! current_user_can( 'manage_options' ) ) {
			return [
				'success' => false,
				'message' => __( 'Current user does not have the required permission.', 'suremembers' ),
			];
		}

		// Prepare user data.
		$user = [
			'user_login'                           => '',
			'user_email'                           => '',
			'user_pass'                            => '',
			'role'                                 => 'subscriber',
			'first_name'                           => '',
			'last_name'                            => '',
			'user_url'                             => '',
			'user_registered'                      => '',
			'suremembers_access_groups'            => '',
			'suremembers_access_groups_expiration' => '',
		];

		$is_onboarding_email_sent_msg = false;
		$is_reset_pass_email_sent_msg = false;

		// Map user data to the prepared user array.
		foreach ( $user_data as $col => $cell ) {
			// Remove the `*` and space with `_` from the headers.
			$col = strtolower( str_replace( [ ' ', '*' ], [ '_', '' ], $col ) );

			switch ( $col ) {
				case 'username':
					$user['user_login'] = sanitize_user( $cell );
					break;
				case 'email':
					$user['user_email'] = sanitize_email( $cell );
					break;
				case 'password':
					$user['user_pass'] = sanitize_text_field( $cell );
					break;
				case 'role':
					$user['role'] = sanitize_text_field( $cell );
					break;
				case 'generate_password':
					$user['user_pass'] = sanitize_text_field( $cell );
					break;
				case 'first_name':
					$user['first_name'] = sanitize_text_field( $cell );
					break;
				case 'last_name':
					$user['last_name'] = sanitize_text_field( $cell );
					break;
				case 'website':
					$user['user_url'] = esc_url_raw( $cell );
					break;
				case 'registered':
					$user['user_registered'] = sanitize_text_field( $cell );
					break;
				case 'suremembers_access_groups':
					$user['suremembers_access_groups'] = sanitize_text_field( $cell );
					break;
				case 'suremembers_access_groups_expiration':
					$user['suremembers_access_groups_expiration'] = sanitize_text_field( $cell );
					break;
			}
		}

		// Check if the username already exists.
		$exists = username_exists( $user['user_login'] );

		if ( $exists ) {
			return [
				'success' => false,
				'message' => sprintf(
					/* translators:  %s The username of the user. */
					__( 'Username %s already exists.', 'suremembers' ),
					sanitize_text_field( $user['user_login'] )
				),
			];
		}

		// Insert or update the user accordingly.
		$user_id = wp_insert_user( $user );
		if ( is_wp_error( $user_id ) ) {
			return [
				'success' => false,
				'message' => sprintf(
					/* translators:  %1$s: The user's username and %2$s: the error message. */
					__( 'Username %1$s is not imported due to error occurred. Error: %2$s', 'suremembers' ),
					sanitize_text_field( $user['user_login'] ),
					$user_id->get_error_message()
				),
			];
		}

		// Grant access groups if provided.
		if ( ! empty( $user['suremembers_access_groups'] ) ) {
			$get_access_groups = Access_Groups::get_active();
			$strings           = explode( ',', $user['suremembers_access_groups'] );

			foreach ( $strings as $group_id ) {
				// Set the default expiry date to blank.
				$expiration_date = [];

				if ( in_array( intval( $group_id ), array_keys( $get_access_groups ), true ) ) {
					$posted_expiration_date = ! empty( $user['suremembers_access_groups_expiration'] ) ? sanitize_text_field( $user['suremembers_access_groups_expiration'] ) : '';

					// Update the access group expiry date for the user if the access group has the expiration type relative date.
					if ( ! empty( $posted_expiration_date ) && Access::get_access_group_expiry_data( $group_id, 'type' ) === 'relative_date' ) {
						$expiration_date[ $group_id ] = $posted_expiration_date;
					}

					Access::grant( intval( $user_id ), $group_id, 'suremembers', $expiration_date, false );
				}
			}
		}

		// Send onboarding email if requested.
		if ( $send_onboarding_email ) {
			$is_onboarding_email_sent_msg = Utils::send_email_notification( $user_id, 'user_onboarding' ) === false ? sprintf(
				/* translators:  %s: The username of the current user */
				__( 'Onboarding email to username %s not sent.', 'suremembers' ),
				sanitize_text_field( $user['user_login'] )
			) : '';
		}

		// Send reset email if requested.
		if ( $send_reset_pass_email ) {
			$email_template = Settings::get_setting( SUREMEMBERS_EMAIL_TEMPLATE_SETTINGS );
			if ( $email_template['enable_reset_password'] ) {
				$is_reset_pass_email_sent_msg = Utils::send_email_notification( $user_id, 'reset_password' ) === false ? sprintf(
					/* translators:  %s: The username of the processing user */
					__( 'Reset password email to username %s not sent.', 'suremembers' ),
					sanitize_text_field( $user['user_login'] )
				) : '';
			} else {
				wp_new_user_notification( intval( $user_id ), null, 'both' );
			}
		}

		// Return result.
		return [
			'success' => true,
			'data'    => [
				'email_sent' => $is_onboarding_email_sent_msg ? $is_onboarding_email_sent_msg : $is_reset_pass_email_sent_msg,
				'message'    => __( 'User Created Successfully', 'suremembers' ),
			],
		];
	}

	/**
	 * Send test email data.
	 *
	 * @param string $email_template Email template type.
	 * @param string $send_to_email Email address to send to.
	 *
	 * @return array{success: bool, data?: array<string, mixed>, message?: string} Result of the test email operation.
	 *
	 * @since 1.10.0
	 */
	public function send_email_template_test_mail_data( $email_template, $send_to_email ): array {
		// Check user permission.
		if ( ! current_user_can( 'manage_options' ) ) {
			return [
				'success' => false,
				'message' => __( 'Current user does not have the required permission.', 'suremembers' ),
			];
		}

		// Validate inputs.
		if ( empty( $email_template ) || empty( $send_to_email ) ) {
			return [
				'success' => false,
				'message' => __( 'No email template type or email ID found.', 'suremembers' ),
			];
		}

		if ( Settings::send_email_template( $send_to_email, $email_template, [], true ) ) {
			return [
				'success' => true,
				'data'    => [
					'message' => __( 'Test Email Sent Successfully', 'suremembers' ),
				],
			];
		}
			return [
				'success' => false,
				'message' => __( 'No email notification is send.', 'suremembers' ),
			];
	}

	/**
	 * Get user roles array.
	 *
	 * @return array<string, mixed> array of user roles.
	 *
	 * @since 1.0.0
	 */
	public function get_formated_user_roles(): array {
		global $wp_roles;

		if ( ! isset( $wp_roles ) ) {
			return [];
		}

		$available_roles_names = $wp_roles->get_names();
		$excluded_roles        = apply_filters( 'suremembers_settings_excluded_roles', [ 'administrator' => esc_html__( 'Administrator', 'suremembers' ) ] );

		$included_roles = array_diff( $available_roles_names, $excluded_roles );
		return Utils::get_react_select_format( $included_roles );
	}

	/**
	 * Return redirection rules
	 *
	 * @return array<string, mixed>
	 *
	 * @since 1.3.0
	 */
	public function get_redirection_rules(): array {
		return Settings::get_setting( SUREMEMBERS_REDIRECT_RULES );
	}

	/**
	 * Sanitize global settings array.
	 *
	 * @param array<string, mixed> $settings Array of settings to sanitize.
	 * @param array<string, mixed> $keys_to_wp_kses The keys which needs to allow some HTML tags to be saved.
	 *
	 * @return array<string, mixed> Array of settings sanitized.
	 *
	 * @since 1.0.0
	 */
	public function sanitize_settings( $settings, $keys_to_wp_kses = [] ): array {
		$response = [];
		foreach ( $settings as $key => $data ) {
			if ( is_array( $data ) ) {
				$val = $this->sanitize_settings( $data, $keys_to_wp_kses );
			} elseif ( is_bool( $data ) ) {
				$val = rest_sanitize_boolean( $data );
			} else {
				if ( ! empty( $keys_to_wp_kses ) && in_array( $key, $keys_to_wp_kses ) ) {
					$val = wp_kses_post( $data );
				} else {
					$val = sanitize_text_field( $data );
				}
			}
			$response[ $key ] = $val;
		}

		return $response;
	}

	/**
	 * Update global settings AJAX.
	 *
	 * @since 1.0.0
	 * @deprecated 2.0.0 Use REST API endpoint /suremembers/v1/update-global-settings instead (handled by Global_Settings utility class)
	 */
	public function update_global_settings(): void {
		// Skip nonce verification for REST API requests (handled by REST permission_callback).
		if ( ! $this->is_rest_request() ) {
			check_ajax_referer( 'suremembers_global_settings_nonce', 'security' );
		}

		if ( ! $this->check_user_cap() ) {
			wp_send_json_error( [ 'message' => __( 'Current user does not have required permission.', 'suremembers' ) ] );
		}

		if ( ! isset( $_POST['setting_key'] ) || empty( $_POST['setting_key'] ) ) {
			wp_send_json_error( [ 'message' => __( 'Setting key is required to save data.', 'suremembers' ) ] );
		}

		if ( ! isset( $_POST['settings_data'] ) || empty( $_POST['settings_data'] ) ) {
			wp_send_json_error( [ 'message' => __( 'Settings cannot be empty.', 'suremembers' ) ] );
		}

		// Ignoring sanitization as it it done below with custom function.
		$settings_data = json_decode( stripslashes_deep( $_POST['settings_data'] ), true, 512, JSON_OBJECT_AS_ARRAY ); //phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
		$settings_data = is_array( $settings_data ) ? $this->sanitize_settings( $settings_data ) : [];
		$key           = sanitize_text_field( $_POST['setting_key'] );

		Settings::update_setting( $key, $settings_data );

		if ( $key === SUREMEMBERS_CUSTOM_CONTENT ) {
			$data = Settings::get_custom_content_data();
		} else {
			$data = Settings::get_setting( $key );
		}
		wp_send_json_success(
			[
				'message'       => __( 'Settings Saved', 'suremembers' ),
				'settings_data' => $data,
			]
		);
	}

	/**
	 * Render settings page.
	 *
	 * @since 1.0.0
	 */
	public function render_settings_page(): void {
		echo '<div id="suremembers-global-settings"></div>';
	}

	/**
	 * Add user role (returns data instead of echoing JSON).
	 *
	 * @param string $slug User role slug.
	 * @param string $title User role title.
	 *
	 * @return array{success: bool, data?: array<string, mixed>, message?: string} Result array.
	 *
	 * @since 1.10.14
	 */
	public function suremembers_add_user_roles_data( $slug, $title ): array {
		if ( ! $this->check_user_cap() ) {
			return [
				'success' => false,
				'message' => __( 'Current user does not have required permission.', 'suremembers' ),
			];
		}

		if ( empty( $slug ) || empty( $title ) ) {
			return [
				'success' => false,
				'message' => __( 'Slug and title are required.', 'suremembers' ),
			];
		}

		// Check if role already exists.
		if ( get_role( $slug ) ) {
			return [
				'success' => false,
				'message' => __( 'User role already exists.', 'suremembers' ),
			];
		}

		$result = $this->create_user_role( $slug, $title );
		if ( ! empty( $result ) ) {
			return [
				'success' => true,
				'data'    => $result,
			];
		}
			return [
				'success' => false,
				'message' => __( 'User role addition failed', 'suremembers' ),
			];
	}

	/**
	 * Update user role (returns data instead of echoing JSON).
	 *
	 * @param string $id User role ID.
	 * @param string $slug User role slug.
	 * @param string $title User role title.
	 *
	 * @return array{success: bool, data?: array<string, mixed>, message?: string} Result array.
	 *
	 * @since 1.10.14
	 */
	public function suremembers_update_user_roles_data( $id, $slug, $title ): array {
		if ( ! $this->check_user_cap() ) {
			return [
				'success' => false,
				'message' => __( 'Current user does not have required permission.', 'suremembers' ),
			];
		}

		if ( empty( $id ) || empty( $title ) || empty( $slug ) ) {
			return [
				'success' => false,
				'message' => __( 'ID, slug and title are required.', 'suremembers' ),
			];
		}

		remove_role( $id );
		$result = $this->create_user_role( $slug, $title );
		if ( $result ) {
			return [
				'success' => true,
				'data'    => $result,
			];
		}
			return [
				'success' => false,
				'message' => __( 'User role update failed', 'suremembers' ),
			];
	}

	/**
	 * Remove user role (returns data instead of echoing JSON).
	 *
	 * @param string $id User role ID.
	 *
	 * @return array{success: bool, data?: array<string, mixed>, message?: string} Result array.
	 *
	 * @since 1.10.14
	 */
	public function suremembers_remove_user_roles_data( $id ): array {
		if ( ! $this->check_user_cap() ) {
			return [
				'success' => false,
				'message' => __( 'Current user does not have required permission.', 'suremembers' ),
			];
		}

		if ( empty( $id ) ) {
			return [
				'success' => false,
				'message' => __( 'ID is required.', 'suremembers' ),
			];
		}

		// Replace three backslashes with a single backslash.
		$replaced_id = str_replace( '\\\\\\', '\\', $id );

		remove_role( $replaced_id );

		return [
			'success' => true,
			'data'    => [],
		];
	}

	/**
	 * Update redirection rules data.
	 *
	 * @param string $login_redirect Login redirect URL.
	 * @param string $logout_redirect Logout redirect URL.
	 *
	 * @return array{success: bool, data?: array<string, mixed>, message?: string} Result of the operation.
	 *
	 * @since 1.3.0
	 */
	public function save_redirection_rules_data( $login_redirect, $logout_redirect ): array {
		if ( ! $this->check_user_cap() ) {
			return [
				'success' => false,
				'message' => __( 'Unauthorized access', 'suremembers' ),
			];
		}

		$settings = [
			'login_redirect'  => $login_redirect,
			'logout_redirect' => $logout_redirect,
		];

		Settings::update_setting( SUREMEMBERS_REDIRECT_RULES, $settings );

		return [
			'success' => true,
			'data'    => [
				'message' => __( 'Settings saved', 'suremembers' ),
			],
		];
	}

	/**
	 * Returns active access groups matching search term
	 *
	 * @since 1.4.0
	 */
	public function search_access_groups(): void {
		// Skip nonce verification for REST API requests (handled by REST permission_callback).
		if ( ! $this->is_rest_request() ) {
			check_ajax_referer( 'suremembers_global_settings_nonce', 'security' );
		}

		$search = ! empty( $_POST['search'] ) ? sanitize_text_field( $_POST['search'] ) : ''; //phpcs:ignore WordPress.Security.NonceVerification.Missing

		// Call the data method.
		$result = $this->search_access_groups_data( $search );

		if ( $result['success'] ) {
			wp_send_json_success( $result['data'] ?? [] );
		} else {
			wp_send_json_error( [ 'message' => $result['message'] ?? '' ] );
		}
	}

	/**
	 * Search access groups data.
	 *
	 * @param string $search Search term.
	 *
	 * @return array{success: bool, data?: array<string, mixed>, message?: string} Result of the search operation.
	 *
	 * @since 1.4.0
	 */
	public function search_access_groups_data( $search ): array {
		if ( ! $this->check_user_cap() ) {
			return [
				'success' => false,
				'message' => __( 'Unauthorized access', 'suremembers' ),
			];
		}

		if ( empty( $search ) ) {
			return [
				'success' => false,
				'message' => __( 'No search result found', 'suremembers' ),
			];
		}

		$filter_args = [
			's' => $search,
		];

		$access_groups = Access_Groups::get_active( $filter_args );
		$access_groups = Utils::get_react_select_format( $access_groups );

		return [
			'success' => true,
			'data'    => $access_groups,
		];
	}

	/**
	 * License activation data.
	 *
	 * @param string $key License key.
	 *
	 * @return array{success: bool, data?: array<string, mixed>, message?: string} Result of the operation.
	 *
	 * @since 1.8.1
	 */
	public static function suremembers_license_activation_data( $key ): array {
		if ( ! current_user_can( 'manage_options' ) ) {
			return [
				'success' => false,
				'message' => __( 'Current user does not have required permission.', 'suremembers' ),
			];
		}

		if ( empty( $key ) ) {
			return [
				'success' => false,
				'message' => __( 'License key is required.', 'suremembers' ),
			];
		}

		$result = Utils::activate_license( $key );

		if ( ! is_bool( $result ) ) {
			return [
				'success' => false,
				'message' => $result->get_error_message(),
			];
		}

		return [
			'success' => true,
			'data'    => [
				'message' => __( 'License Activated Successfully', 'suremembers' ),
			],
		];
	}

	/**
	 * License deactivation data.
	 *
	 * @return array{success: bool, data?: array<string, mixed>, message?: string} Result of the operation.
	 *
	 * @since 1.8.1
	 */
	public static function suremembers_license_deactivation_data(): array {
		if ( ! current_user_can( 'manage_options' ) ) {
			return [
				'success' => false,
				'message' => __( 'Current user does not have required permission.', 'suremembers' ),
			];
		}

		$result = Utils::deactivate_license();

		if ( ! is_bool( $result ) ) {
			return [
				'success' => false,
				'message' => $result->get_error_message(),
			];
		}

		return [
			'success' => true,
			'data'    => [
				'message' => __( 'License Deactivated Successfully', 'suremembers' ),
			],
		];
	}

	/**
	 * Adds logo for SureMembers plugins on updater page
	 *
	 * @param object $transient Transient object.
	 *
	 * @since 1.10.12
	 */
	public function add_suremembers_logo( $transient ): object {
		$logo_url    = SUREMEMBERS_URL . 'admin/assets/images/icon.svg';
		$plugin_slug = 'suremembers/suremembers.php';

		if ( isset( $transient->response[ $plugin_slug ] ) ) {
			$plugin_data = $transient->response[ $plugin_slug ];

			// Only update the icons.
			$plugin_data->icons = [
				'1x' => $logo_url,
				'2x' => $logo_url,
			];

			$transient->response[ $plugin_slug ] = $plugin_data;
		}

		return $transient;
	}

	/**
	 * Check if the current request is a REST API request.
	 *
	 * @return bool True if REST request, false otherwise.
	 * @since 1.0.0
	 */
	private function is_rest_request(): bool {
		if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
			return true;
		}

		if ( isset( $_SERVER['REQUEST_URI'] ) && strpos( $_SERVER['REQUEST_URI'], '/wp-json/' ) !== false ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
			return true;
		}

		return false;
	}

	/**
	 * Check if user can manage settings.
	 *
	 * @since 1.0.0
	 */
	private function check_user_cap(): bool {
		return current_user_can( 'manage_options' );
	}

	/**
	 * Create user role.
	 *
	 * @param string $slug Slug will be the id of role.
	 * @param string $title User role title.
	 *
	 * @since 1.1.0
	 *
	 * @return \WP_Role|false
	 */
	/**
	 * Create a new user role.
	 *
	 * @param string $slug  The role slug.
	 * @param string $title The role title.
	 * @return \WP_Role|false The role object on success, false on failure.
	 * @since 1.0.0
	 */
	private function create_user_role( $slug, $title ): \WP_Role|false {
		// Check if role already exists.
		if ( get_role( $slug ) ) {
			return false;
		}
		$role = add_role( $slug, $title );
		// Ensure false instead of null if role creation fails.
		return $role instanceof \WP_Role ? $role : false;
	}

	/**
	 * Return selected access group in format required for react select, empty if not access group is selected.
	 *
	 * @since 1.4.0
	 */
	private function get_selected_registration_access_group(): array {
		$settings = Settings::get_setting( SUREMEMBERS_ADMIN_SETTINGS );

		$access_group_ids = isset( $settings['registration_access_group'] ) ? Utils::sanitize_recursively( 'absint', $settings['registration_access_group'] ) : [];
		if ( empty( $access_group_ids ) ) {
			return [];
		}

		$access_groups = Access_Groups::get_active( [ 'post__in' => $access_group_ids ] );
		if ( empty( $access_groups ) ) {
			return [];
		}

		return Utils::get_react_select_format( $access_groups );
	}
}
