<?php
namespace Barn2\Plugin\Password_Protected_Categories\Admin;

use Barn2\Plugin\Password_Protected_Categories\Dependencies\Setup_Wizard\Util as Setup_WizardUtil;
use Barn2\Plugin\Password_Protected_Categories\Dependencies\Lib\Registerable;
use Barn2\Plugin\Password_Protected_Categories\Dependencies\Lib\Service\Premium_Service;
use Barn2\Plugin\Password_Protected_Categories\PPC_Util;
use Barn2\Plugin\Password_Protected_Categories\Dependencies\Lib\Util;

/**
 * This class provides functions for the 'visibility' field for categories and custom taxonomies in the admin.
 *
 * @package   Barn2\password-protected-categories
 * @author    Barn2 Plugins <support@barn2.co.uk>
 * @license   GPL-3.0
 * @copyright Barn2 Media Ltd
 */
class Term_Visibility_Field implements Premium_Service, Registerable {

	public function register() {
		\add_action( 'admin_init', [ $this, 'term_visibility_hooks' ] );
	}

	public function term_visibility_hooks() {
		foreach ( PPC_Util::get_protectable_taxonomies() as $tax ) {
			// Add visibility field
			\add_action( "{$tax}_add_form_fields", [ $this, 'add_visibility_field' ], 20 );
			\add_action( "{$tax}_edit_form_fields", [ $this, 'edit_visibility_field' ], 10 );

			// Save visibility field
			\add_action( "created_{$tax}", [ $this, 'save_visibility_field' ], 10, 2 );
			\add_action( "edit_{$tax}", [ $this, 'save_visibility_field' ], 10, 2 );

			// Add visibility column to product category table
			\add_filter( "manage_edit-{$tax}_columns", [ $this, 'term_table_visibility_column_heading' ] );
			\add_filter( "manage_{$tax}_custom_column", [ $this, 'term_table_visibility_column' ], 10, 3 );

			// If the the term is protected, but no protection is selected
			add_action( 'admin_notices', [ $this, 'empty_protection_notice' ] );
			add_filter( 'pre_insert_term', [ $this, 'empty_protection_error' ], 10, 2 );

			// @todo To make Visibility column sortable we need to filter 'get_terms_args' and change 'orderby' args into a meta query (if possible)
			// add_filter( 'manage_edit-cat_sortable_columns', array( $this, 'term_table_make_visibility_sortable' ) );
		}
	}

	/**
	 * Add visibility field to 'add product category' screen
	 */
	public function add_visibility_field() {
		?>
		<div class="form-field term-visibility-wrap">
			<?php $this->visibility_label(); ?>
			<?php $this->visibility_group(); ?>
		</div>
		<?php
	}

	/**
	 * Add visibility field to 'edit product category' screen
	 *
	 * @param mixed $term The product category being edited
	 */
	public function edit_visibility_field( $term ) {
		$visibility = PPC_Util::get_visibility( $term->term_id );
		?>
		<tr class="form-field term-visibility-wrap">
			<th scope="row" valign="top">
				<?php $this->visibility_label(); ?>
			</th>
			<td>
				<?php $this->visibility_group( $term ); ?>
			</td>
		</tr>
		<?php
	}

	/**
	 * Save visibility and password for product category
	 *
	 * @param mixed $term_id Term ID being saved
	 * @param mixed $tt_id The term taxonomy ID
	 */
	public function save_visibility_field( $term_id, $tt_id = '' ) {
		if ( ! isset( $_POST['ppc_term_nonce'] ) || ! \wp_verify_nonce( \sanitize_key( $_POST['ppc_term_nonce'] ), 'ppc_save_term_visibility' ) ) {
			return;
		}

		if ( ! \current_user_can( 'manage_categories' ) ) {
			return;
		}

		$visibility = isset( $_POST['cat_visibility'] ) ? sanitize_text_field( $_POST['cat_visibility'] ) : false;

		// Bail if no visibility to save (e.g. on 'quick edit')
		if ( ! $visibility ) {
			return;
		}

		if ( 'protected' === $visibility ) {
			$protection = isset( $_POST['cat_protection'] ) ? Setup_WizardUtil::clean( $_POST['cat_protection'] ) : [];

			// Remove existing meta for this category
			\delete_term_meta( $term_id, 'password' );
			\delete_term_meta( $term_id, 'user_roles' );
			\delete_term_meta( $term_id, 'users' );

			if ( empty( $protection ) ) {
				// If no protection options set, revert to public visibility.
				$visibility = 'public';
			} else {
				// Passwords
				if ( \in_array( 'password', $protection ) ) {
					$passwords = isset( $_POST['cat_passwords'] ) ? Setup_WizardUtil::clean( $_POST['cat_passwords'] ) : [];

					// Filter array to remove any empty inputs
					$passwords = \is_array( $passwords ) ? \array_values( \array_filter( $passwords ) ) : [];

					if ( empty( $passwords ) ) {
						// Set default password in case none was entered
						$passwords = [ 'password123' ];
					}

					\add_term_meta( $term_id, 'password', $passwords );
				}

				// User roles
				if ( \in_array( 'user_role', $protection ) ) {
					$user_roles = isset( $_POST['cat_user_roles'] ) ? Setup_WizardUtil::clean( $_POST['cat_user_roles'] ) : [];
					\add_term_meta( $term_id, 'user_roles', $user_roles );
				}

				// Users
				if ( \in_array( 'user', $protection ) ) {
					$user_ids = isset( $_POST['cat_users'] ) ? Setup_WizardUtil::clean( $_POST['cat_users'] ) : [];
					\add_term_meta( $term_id, 'users', $user_ids );
				}
			}
		}

		\update_term_meta( $term_id, 'visibility', $visibility );
	}

	public function term_table_visibility_column_heading( $columns ) {
		return $this->list_table_insert_after_column( $columns, 'name', 'visibility', __( 'Visibility', 'password-protected-categories' ) );
	}

	public function term_table_visibility_column( $output, $column, $term_id ) {
		if ( 'visibility' === $column ) {
			$screen     = get_current_screen();
			$tax_string = false;

			if ( isset( $screen->taxonomy ) ) {
				$tax_string = $screen->taxonomy;
			} elseif ( isset( $_GET['taxonomy'] ) && ! empty( $_GET['taxonomy'] ) ) {
				$tax_string = sanitize_text_field( $_GET['taxonomy'] );
			} elseif ( isset( $_POST['taxonomy'] ) && ! empty( $_POST['taxonomy'] ) ) {
				$tax_string = sanitize_text_field( $_POST['taxonomy'] );
			}

			$category = PPC_Util::get_term_visibility( get_term_by( 'id', absint( $term_id ), $tax_string ) );

			if ( 'public' === $category->get_visibility() ) {
				foreach ( $category->ancestors() as $ancestor ) {
					if ( 'public' !== $ancestor->get_visibility() ) {
						$output = sprintf( '<em>(%s)</em>', __( 'inherited', 'password-protected-categories' ) );
						break;
					}
				}
				if ( ! $output ) {
					$output = __( 'Public', 'password-protected-categories' );
				}
			} elseif ( 'protected' === $category->get_visibility() ) {
				$output          = __( 'Protected', 'password-protected-categories' );
				$protection_type = [];

				if ( $category->has_password_protection() ) {
					$protection_type[] = __( 'password', 'password-protected-categories' );
				}
				if ( $category->has_role_protection() ) {
					$protection_type[] = __( 'user role', 'password-protected-categories' );
				}
				if ( $category->has_user_protection() ) {
					$protection_type[] = __( 'user', 'password-protected-categories' );
				}

				if ( $protection_type ) {
					/* translators: 1: 'Protected' label, 2: the protection type. */
					$output = \sprintf( _x( '%1$s - %2$s', 'protected visibility format', 'password-protected-categories' ), $output, \implode( ', ', $protection_type ) );
				}
			} elseif ( 'private' === $category->get_visibility() ) {
				$output = __( 'Private', 'password-protected-categories' );
			}
		}

		return $output;
	}

	private function visibility_label() {
		?>
		<label><?php esc_html_e( 'Visibility', 'password-protected-categories' ); ?></label>
		<?php
	}

	private function list_table_insert_after_column( $columns, $after_key, $insert_key, $insert_value ) {
		$new_columns = [];

		foreach ( $columns as $key => $column ) {
			if ( $after_key === $key ) {
				$new_columns[ $key ]        = $column;
				$new_columns[ $insert_key ] = $insert_value;
			} else {
				$new_columns[ $key ] = $column;
			}
		}

		return $new_columns;
	}

	private function visibility_group( $term = false ) {
		$category       = $term ? PPC_Util::get_term_visibility( $term ) : null;
		$visibility     = $category ? $category->get_visibility() : 'public';
		$cat_passwords  = $category ? PPC_Util::get_term_passwords( $term->term_id, true ) : [];
		$cat_user_roles = $category ? $category->get_roles() : [];
		$cat_users      = $category ? $category->get_users() : [];
		$has_passwords  = \count( $cat_passwords ) > 0 && $visibility === 'protected';
		$has_user_roles = \count( $cat_user_roles ) > 0;
		$has_users      = \count( $cat_users ) > 0;

		// If there are no passwords, add an empty one so we always display at least one password input
		if ( empty( $cat_passwords ) ) {
			$cat_passwords = [ '' ];
		}

		if ( $visibility === 'private' ) {
			PPC_Util::display_deprecated_notice();
		}

		?>
		<?php \wp_nonce_field( 'ppc_save_term_visibility', 'ppc_term_nonce' ); ?>
		<div class="hidden ppc-notice notice notice-error">
			<p><?php esc_html_e( 'The protection field can not be empty.', 'password-protected-categories' ); ?></p>
		</div>
		<fieldset id="cat_visibility" class="cat-visibility">
			<legend class="screen-reader-text"><?php esc_html_e( 'Visibility', 'password-protected-categories' ); ?></legend>
			<label class="cat-visibility__option"><input type="radio" name="cat_visibility" id="public_visibility" value="public" <?php checked( $visibility, 'public' ); ?> /> <?php esc_html_e( 'Public', 'password-protected-categories' ); ?></label>
			<label class="cat-visibility__option">
				<input type="radio" name="cat_visibility" id="protected_visibility" value="protected" <?php checked( $visibility, 'protected' ); ?> /> <?php esc_html_e( 'Protected', 'password-protected-categories' ); ?>
				<?php echo PPC_Util::help_tip( __( 'Protect the category by password, or restrict to specific roles or users. Its contents (including posts and sub-categories) will inherit the same protection.', 'password-protected-categories' ) ); ?>
			</label>
			<fieldset id="cat_protection" class="cat-protection cat-visibility__field"
			<?php
			if ( 'protected' !== $visibility ) {
				echo ' style="display:none;"';
			}
			?>
			>
				<legend class="screen-reader-text"><?php esc_html_e( 'Protect by:', 'password-protected-categories' ); ?></legend>

				<div class="cat-protection__item">
					<label class="cat-protection__option"><input type="checkbox" class="cat-protection__check" id="password_protection" name="cat_protection[]" value="password"<?php checked( $has_passwords ); ?> /> <?php esc_html_e( 'Password protected', 'password-protected-categories' ); ?></label>
					<div id="cat_passwords" class="cat-protection__field"
					<?php
					if ( ! $has_passwords ) {
						echo ' style="display:none;"';
					}
					?>
					>
							<?php
							foreach ( $cat_passwords as $index => $password ) :
								$first = $index === 0;
								?>
							<div class="cat-password" data-first="<?php echo esc_attr( $first ? 'true' : 'false' ); ?>" data-index="<?php echo esc_attr( $index ); ?>">
								<label class="screen-reader-text"><?php esc_html_e( 'Enter password', 'password-protected-categories' ); ?></label>
								<input class="cat-password__field" id="cat_password_<?php echo esc_attr( $index ); ?>" type="text" name="cat_passwords[]" value="<?php echo esc_attr( $password ); ?>" placeholder="<?php esc_attr_e( 'Enter password&hellip;', 'password-protected-categories' ); ?>" />
								<span class="cat-password__icons">
									<a class="cat-password__icon cat-password__icon--add" data-action="add" href="#"><span class="dashicons dashicons-plus"></span></a>
									<?php if ( ! $first ) : ?>
										<a class="cat-password__icon cat-password__icon--delete" data-action="delete" href="#"><span class="dashicons dashicons-minus"></span></a>
									<?php endif; ?>
								</span>
							</div>
							<?php endforeach; ?>
					</div>
				</div>

				<div class="cat-protection__item">
					<label class="cat-protection__option"><input type="checkbox" class="cat-protection__check" id="user_role_protection" name="cat_protection[]" value="user_role"<?php checked( $has_user_roles ); ?> /> <?php esc_html_e( 'User roles', 'password-protected-categories' ); ?></label>
					<div class="cat-protection__field"
					<?php
					if ( ! $has_user_roles ) {
						echo ' style="display:none;"';
					}
					?>
					>
						<select name="cat_user_roles[]" id="cat_user_roles" class="cat-protection__select" multiple="multiple" style="width:95%;" data-placeholder="<?php esc_attr_e( 'Select or search user roles&hellip;', 'password-protected-categories' ); ?>">
							<?php foreach ( apply_filters( 'wc_ppc_admin_available_roles', wp_roles()->roles ) as $role => $details ) : ?>
								<?php
								$name     = translate_user_role( $details['name'] );
								$selected = in_array( $role, $cat_user_roles );
								?>
								<option value="<?php echo esc_attr( $role ); ?>"<?php selected( $selected ); ?>><?php echo $name; ?></option>
							<?php endforeach; ?>
						</select>
					</div>
				</div>

				<div class="cat-protection__item cat-protection__item--last">
					<label class="cat-protection__option"><input type="checkbox" class="cat-protection__check" id="user_protection" name="cat_protection[]" value="user"<?php checked( $has_users ); ?> /> <?php esc_html_e( 'Users', 'password-protected-categories' ); ?></label>
					<div class="cat-protection__field"
					<?php
					if ( ! $has_users ) {
						echo ' style="display:none;"';
					}
					?>
					>
						<select name="cat_users[]" data-users="<?php echo esc_attr( wp_json_encode( $cat_users ) ); ?>" id="cat_users" class="cat-protection__select" multiple="multiple" style="width:95%;" data-placeholder="<?php esc_attr_e( 'Search users&hellip;', 'password-protected-categories' ); ?>"></select>
					</div>
				</div>
			</fieldset>
		</fieldset>
		<?php
	}

	public function empty_protection_notice() {
		$screen = get_current_screen();

		if ( $screen->base === 'term' && $screen->parent_base === 'edit' ) {
			if ( PPC_Util::is_protection_empty( absint( $_GET['tag_ID'] ) ) ) { //phpcs:ignore WordPress.Security.NonceVerification.Recommended
				?>
				<div class="notice notice-warning is-dismissible">
					<p><?php esc_html_e( "This category doesn't have any protections.", 'password-protected-categories' ); ?></p>
				</div>
				<?php
			}
		}
	}

	public function empty_protection_error( $term, $taxonomy ) {
		$term_data = Setup_WizardUtil::clean( $_POST ); //phpcs:ignore WordPress.Security.NonceVerification.Recommended

		if ( ! isset( $term_data['cat_visibility'] ) ) {
			return $term;
		}

		$is_protected = $term_data['cat_visibility'] === 'protected';

		$passwords = isset( $term_data['cat_passwords'] ) ? $term_data['cat_passwords'] : [];
		$passwords = array_filter( $passwords );

		$user_roles = isset( $term_data['cat_user_roles'] ) ? $term_data['cat_user_roles'] : [];
		$user_roles = array_filter( $user_roles );

		$users = isset( $term_data['cat_users'] ) ? $term_data['cat_users'] : [];
		$users = array_filter( $users );

		if ( ! $is_protected ) {
			return $term;
		}

		if ( empty( $passwords ) && empty( $user_roles ) && empty( $users ) ) {
			return new \WP_Error(
				'empty_protection',
				__( 'The protection field can not be empty.', 'password-protected-categories' ),
				[
					'status' => 400,
				]
			);
		}

		return $term;
	}

}
