<?php
/**
 * Add quick/bulk edit fields on the ad overview page
 *
 * @package AdvancedAds
 * @author  Advanced Ads <info@wpadvancedads.com>
 * @since   2.0
 */

namespace AdvancedAds\Admin\Ads;

use Exception;
use Advanced_Ads_Privacy;
use AdvancedAds\Constants;
use AdvancedAds\Abstracts\Ad;
use AdvancedAds\Utilities\WordPress;
use AdvancedAds\Framework\Utilities\Params;

/**
 * WP integration
 */
class Quick_Bulk_Edit {
	/**
	 * Hooks into WordPress
	 *
	 * @return void
	 */
	public function hooks() {
		add_action( 'quick_edit_custom_box', [ $this, 'add_quick_edit_fields' ], 10, 2 );
		add_action( 'bulk_edit_custom_box', [ $this, 'add_bulk_edit_fields' ], 10, 2 );
		add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_scripts' ] );
		add_action( 'save_post', [ $this, 'save_quick_edits' ], 100 );
		add_action( 'save_post', [ $this, 'save_bulk_edit' ], 100 );
		add_action( 'advanced-ads-ad-render-column-ad_type', [ $this, 'print_ad_json' ] );
	}

	/**
	 * Print ad JSON for debugging
	 *
	 * @param Ad $ad the ad being saved.
	 *
	 * @return void
	 */
	public function print_ad_json( $ad ): void {
		?>
		<script type="text/javascript">
			var ad_json_<?php echo esc_attr( $ad->get_id() ); ?> = <?php echo wp_json_encode( $this->get_json_data( $ad ) ); ?>;
		</script>
		<?php
	}

	/**
	 * Save changes made during bulk edit
	 *
	 * @return void
	 */
	public function save_bulk_edit() {
		// Not bulk edit, not ads or not enough permissions.
		if (
			! wp_verify_nonce( sanitize_key( Params::get( '_wpnonce', '', FILTER_SANITIZE_FULL_SPECIAL_CHARS ) ), 'bulk-posts' )
			|| Constants::POST_TYPE_AD !== sanitize_key( Params::get( 'post_type' ) )
			|| ! current_user_can( 'advanced_ads_edit_ads' )
		) {
			return;
		}

		$changes = [ 'on', 'off' ];

		$debug_mode     = Params::get( 'debug_mode' );
		$set_expiry     = Params::get( 'expiry_date' );
		$ad_label       = Params::get( 'ad_label', false );
		$ignore_privacy = Params::get( 'ignore_privacy' );

		$has_change = in_array( $debug_mode, $changes, true ) || in_array( $set_expiry, $changes, true ) || in_array( $ignore_privacy, $changes, true ) || false !== $ad_label;

		/**
		 * Allow add-ons to confirm early abort if no change has been made and avoid iterating through an ad stack.
		 *
		 * @param bool $has_change whether some ads have been changed.
		 */
		$has_change = apply_filters( 'advanced-ads-bulk-edit-has-change', $has_change );

		// No changes, bail out.
		if ( ! $has_change ) {
			return;
		}

		$expiry_date = 'on' === $set_expiry ?
			$this->get_expiry_timestamp( 'get' ) : 0;

		$ads = array_map(
			function ( $ad ) {
				return wp_advads_get_ad( absint( $ad ) );
			},
			wp_unslash( Params::get( 'post', [], FILTER_DEFAULT, FILTER_REQUIRE_ARRAY ) )
		);

		foreach ( $ads as $ad ) {
			if ( in_array( $debug_mode, $changes, true ) ) {
				$ad->set_debugmode( 'on' === $debug_mode );
			}

			if ( in_array( $set_expiry, $changes, true ) ) {
				$ad->set_prop( 'expiry_date', $expiry_date );
			}

			if ( false !== $ad_label ) {
				$ad->set_prop( 'ad_label', esc_html( trim( $ad_label ) ) );
			}

			if ( 'on' === $ignore_privacy ) {
				$ad->set_prop( 'privacy', [ 'ignore-consent' => 'on' ] );
			} elseif ( 'off' === $ignore_privacy ) {
				$ad->unset_prop( 'privacy' );
			}

			/**
			 * Allow add-on to bulk save ads.
			 *
			 * @param Ad $ad current ad being saved.
			 */
			$ad = apply_filters( 'advanced-ads-bulk-edit-save', $ad );

			$ad->save();
		}
	}

	/**
	 * Save ad edited with quick edit
	 *
	 * @param int $id the ad being saved.
	 *
	 * @return void
	 */
	public function save_quick_edits( $id ) {
		// Not inline edit, or no permission.
		if (
			! wp_verify_nonce( sanitize_key( Params::post( '_inline_edit' ) ), 'inlineeditnonce' ) ||
			! current_user_can( 'advanced_ads_edit_ads' )
		) {
			return;
		}

		$ad = wp_advads_get_ad( $id );

		// Not an ad.
		if ( ! $ad ) {
			return;
		}

		// Render columns properly.
		( new List_Table() )->hooks();

		$ad->set_prop( 'debugmode', Params::post( 'debugmode', false, FILTER_VALIDATE_BOOLEAN ) );
		$ad->set_prop(
			'expiry_date',
			Params::post( 'enable_expiry' ) ? $this->get_expiry_timestamp() : 0
		);

		if ( isset( Advanced_Ads_Privacy::get_instance()->options()['enabled'] ) ) {
			if ( Params::post( 'ignore_privacy' ) ) {
				$ad->set_prop( 'privacy', [ 'ignore-consent' => 'on' ] );
			} else {
				$ad->unset_prop( 'privacy' );
			}
		}

		$ad_label = Params::post( 'ad_label', false );
		if ( false !== $ad_label ) {
			$ad->set_prop( 'ad_label', esc_html( trim( $ad_label ) ) );
		}

		/**
		 * Allow add-ons to edit and ad before it is saved.
		 *
		 * @param Ad $ad the ad being saved.
		 */
		$ad = apply_filters( 'advanced-ads-quick-edit-save', $ad );

		$ad->save();
	}

	/**
	 * Get Unix timestamp from the date time inputs values
	 *
	 * @param string $method method used for the form - `post` or `get`.
	 *
	 * @return int
	 */
	private function get_expiry_timestamp( $method = 'post' ) {
		$day     = absint( 'get' === $method ? Params::get( 'day' ) : Params::post( 'day' ) );
		$month   = absint( 'get' === $method ? Params::get( 'month' ) : Params::post( 'month' ) );
		$year    = 'get' === $method ? Params::get( 'year', 0, FILTER_VALIDATE_INT ) : Params::post( 'year', 0, FILTER_VALIDATE_INT );
		$hours   = absint( 'get' === $method ? Params::get( 'hour' ) : Params::post( 'hour' ) );
		$minutes = absint( 'get' === $method ? Params::get( 'minute' ) : Params::post( 'minute' ) );

		try {
			$local_dt = new \DateTimeImmutable( 'now', WordPress::get_timezone() );
			$local_dt = $local_dt->setDate( $year, $month, $day )->setTime( $hours, $minutes );

			return $local_dt->getTimestamp();
		} catch ( Exception $e ) {
			return 0;
		}
	}

	/**
	 * Enqueue scripts and print inline JS variable.
	 *
	 * @return void
	 */
	public function enqueue_scripts() {
		$screen = get_current_screen();

		if ( 'edit-advanced_ads' !== $screen->id ) {
			return;
		}

		wp_advads()->registry->enqueue_script( 'screen-ads-listing' );
	}

	/**
	 * Add the bulk edit inputs
	 *
	 * @param string $column_name the current column.
	 * @param string $post_type   the current post type.
	 *
	 * @return void
	 */
	public function add_bulk_edit_fields( $column_name, $post_type ) {
		if ( Constants::POST_TYPE_AD !== $post_type || 'ad_type' !== $column_name ) {
			return;
		}

		$privacy_options = \Advanced_Ads_Privacy::get_instance()->options();
		include plugin_dir_path( ADVADS_FILE ) . 'views/admin/bulk-edit.php';

		/**
		 * Allow add-ons to add more fields.
		 */
		do_action( 'advanced-ads-bulk-edit-fields' );
	}

	/**
	 * Add the quick edit inputs
	 *
	 * @param string $column_name the current column.
	 * @param string $post_type   the current post type.
	 *
	 * @return void
	 */
	public function add_quick_edit_fields( $column_name, $post_type ) {
		if ( Constants::POST_TYPE_AD !== $post_type || 'ad_date' !== $column_name ) {
			return;
		}

		$privacy_options = \Advanced_Ads_Privacy::get_instance()->options();
		include plugin_dir_path( ADVADS_FILE ) . 'views/admin/quick-edit.php';

		/**
		 * Allow add-ons to add more fields.
		 */
		do_action( 'advanced-ads-quick-edit-fields' );
	}

	/**
	 * Print date and time inputs for the ad expiry
	 *
	 * @param int    $timestamp default expiry date.
	 * @param string $prefix    prefix for input names.
	 * @param bool   $seconds   whether to add seconds input.
	 *
	 * @return void
	 */
	public static function print_date_time_inputs( $timestamp = 0, $prefix = '', $seconds = false ) {
		try {
			$initial_date = (bool) $timestamp ? new \DateTimeImmutable( "@$timestamp", new \DateTimeZone( 'UTC' ) ) : current_datetime();
		} catch ( Exception $e ) {
			$initial_date = current_datetime();
		}

		$current_year = (int) ( current_datetime()->format( 'Y' ) );

		global $wp_locale;
		?>
		<label>
			<span class="screen-reader-text"><?php esc_html_e( 'Month', 'advanced-ads' ); ?></span>
			<select name="<?php echo esc_attr( $prefix ); ?>month">
				<?php for ( $mo = 1; $mo < 13; $mo++ ) : ?>
					<?php $month = zeroise( $mo, 2 ); ?>
					<option value="<?php echo esc_attr( $month ); ?>" <?php selected( $month, $initial_date->format( 'm' ) ); ?>>
						<?php echo esc_html( $month . '-' . $wp_locale->get_month_abbrev( $wp_locale->get_month( $mo, 2 ) ) ); ?>
					</option>
				<?php endfor; ?>
			</select>
		</label>
		<label>
			<span class="screen-reader-text"><?php esc_html_e( 'Day', 'advanced-ads' ); ?></span>
			<input type="number" name="<?php echo esc_attr( $prefix ); ?>day" min="1" max="31" value="<?php echo esc_attr( $initial_date->format( 'd' ) ); ?>"/>
		</label>,
		<label>
			<span class="screen-reader-text"><?php esc_html_e( 'Year', 'advanced-ads' ); ?></span>
			<select name="<?php echo esc_attr( $prefix ); ?>year">
				<?php for ( $y = $current_year; $y < $current_year + 11; $y++ ) : ?>
					<option value="<?php echo esc_attr( $y ); ?>" <?php selected( $y, (int) $initial_date->format( 'Y' ) ); ?>><?php echo esc_html( $y ); ?></option>
				<?php endfor; ?>
			</select>
		</label>
		@
		<label>
			<span class="screen-reader-text"><?php esc_html_e( 'Hour', 'advanced-ads' ); ?></span>
			<input type="number" name="<?php echo esc_attr( $prefix ); ?>hour" min="0" max="23" value="<?php echo esc_attr( $initial_date->format( 'H' ) ); ?>"/>
		</label>:
		<label>
			<span class="screen-reader-text"><?php esc_html_e( 'Minute', 'advanced-ads' ); ?></span>
			<input type="number" name="<?php echo esc_attr( $prefix ); ?>minute" min="0" max="59" value="<?php echo esc_attr( $initial_date->format( 'i' ) ); ?>"/>
		</label>
		<?php if ( $seconds ) : ?>
			:
			<label>
				<span class="screen-reader-text"><?php esc_html_e( 'Second', 'advanced-ads' ); ?></span>
				<input type="number" name="<?php echo esc_attr( $prefix ); ?>second" min="0" max="59" value="<?php echo esc_attr( $initial_date->format( 's' ) ); ?>"/>
			</label>
		<?php endif; ?>
		<?php $timezone = wp_timezone_string(); ?>
		<span><?php echo esc_html( strlen( $timezone ) !== strlen( str_replace( [ '+', '-' ], '', $timezone ) ) ? "UTC$timezone" : $timezone ); ?></span>
		<?php
	}

	/**
	 * Get ad data for json output
	 *
	 * @param Ad $ad Ad instance.
	 *
	 * @return array
	 */
	private function get_json_data( $ad ): array {
		$expiry = $ad->get_expiry_date();

		if ( $expiry ) {
			$expiry_date = array_combine(
				[ 'year', 'month', 'day', 'hour', 'minute' ],
				explode( '-', wp_date( 'Y-m-d-H-i', $expiry ) )
			);
		}

		$ad_data = [
			'debug_mode' => $ad->is_debug_mode(),
			'expiry'     => $expiry
				? [
					'expires'     => true,
					'expiry_date' => $expiry_date,
				]
				: [
					'expires' => false,
				],
			'ad_label'   => $ad->get_prop( 'ad_label' ),
		];

		if ( isset( Advanced_Ads_Privacy::get_instance()->options()['enabled'] ) ) {
			$ad_data['ignore_privacy'] = isset( $ad->get_data()['privacy']['ignore-consent'] );
		}

		/**
		 * Allow add-ons to add more ad data fields.
		 *
		 * @param array $ad_data the fields to be sent back to the browser.
		 * @param       $ad      Ad the ad being currently edited.
		 */
		$ad_data = apply_filters( 'advanced-ads-quick-edit-ad-data', $ad_data, $ad );

		return $ad_data;
	}
}
