<?php
namespace Sellkit\Blocks\Helpers\Smart_Coupon;

defined( 'ABSPATH' ) || die();

/**
 * Smart Coupon block helper class.
 *
 * @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
 * @SuppressWarnings(PHPMD.NPathComplexity)
 * @since 2.3.0
 */
class Helper {
	/**
	 * Class constructor.
	 *
	 * @since 2.3.0
	 */
	public function __construct() {
		add_action( 'wp_ajax_sellkit_block_check_smart_coupon', [ $this, 'check_coupon' ] );
		add_action( 'wp_ajax_nopriv_sellkit_block_check_smart_coupon', [ $this, 'check_coupon' ] );
		add_action( 'wp_ajax_sellkit_block_get_smart_coupon', [ $this, 'get_coupon' ] );
		add_action( 'wp_ajax_nopriv_sellkit_block_get_smart_coupon', [ $this, 'get_coupon' ] );
	}

	/**
	 * Create Coupons.
	 *
	 * @SuppressWarnings(PHPMD.CyclomaticComplexity)
	 * @since 2.3.0
	 * @param string $display_type Display type.
	 */
	public function create_coupons( $display_type ) {
		$rule = $this->get_rule_by_conditions( $display_type );

		$coupon_meta           = get_post_meta( $rule );
		$filters               = get_post_meta( $rule, 'filters', true );
		$coupon_type           = ! empty( $coupon_meta['sellkit_type'][0] ) ? $coupon_meta['sellkit_type'][0] : 'percent';
		$coupon_amount         = ! empty( $coupon_meta['value'][0] ) ? $coupon_meta['value'][0] : 0;
		$use_with_others       = ! empty( $coupon_meta['use_with_other_coupon'][0] ) ? $coupon_meta['use_with_other_coupon'][0] : false;
		$apply_to_on_sale      = ! empty( $coupon_meta['apply_onsale_product'][0] ) ? $coupon_meta['apply_onsale_product'][0] : false;
		$minimum_subtotal      = ! empty( $coupon_meta['minimum_subtotal_count'][0] ) ? $coupon_meta['minimum_subtotal_count'][0] : '';
		$coupon_limitation     = ! empty( $coupon_meta['can_use_count_total'][0] ) ? $coupon_meta['can_use_count_total'][0] : '';
		$expiration_number     = ! empty( $coupon_meta['sellkit_expiration_date_number'][0] ) ? $coupon_meta['sellkit_expiration_date_number'][0] : '';
		$expiration_type       = ! empty( $coupon_meta['sellkit_expiration_date_type'][0] ) ? $coupon_meta['sellkit_expiration_date_type'][0] : '';
		$is_individual         = ! empty( $coupon_meta['sellkit_can_use'][0] ) ? $coupon_meta['sellkit_can_use'][0] : false;
		$coupon_limit_per_user = ! empty( $coupon_meta['sellkit_can_use_count'][0] ) ? $coupon_meta['sellkit_can_use_count'][0] : '';
		$expiration_time       = $this->get_expiration_time( $expiration_number, $expiration_type );

		$coupon = new \WC_Coupon();

		// Generate a non existing coupon code name.
		$coupon_code = self::generate_coupon_code();

		// Set the necessary coupon data.
		$coupon->set_code( $coupon_code );

		if ( empty( $filters ) ) {
			$filters = [];
		}

		foreach ( $filters as $filter ) {
			if ( 'products' === $filter['subject'] && 'is' === $filter['operator'] ) {
				$coupon->set_product_ids( sellkit_get_multi_select_values( $filter['value'] ) );
			}

			if ( 'products' === $filter['subject'] && 'is_not' === $filter['operator'] ) {
				$coupon->set_excluded_product_ids( sellkit_get_multi_select_values( $filter['value'] ) );
			}

			if ( 'categories' === $filter['subject'] && 'is_not' === $filter['operator'] ) {
				$coupon->set_excluded_product_categories( sellkit_get_multi_select_values( $filter['value'] ) );
			}

			if ( 'categories' === $filter['subject'] && 'is' === $filter['operator'] ) {
				$coupon->set_product_categories( sellkit_get_multi_select_values( $filter['value'] ) );
			}
		}

		if ( 'percent' === $coupon_type && $coupon_amount > 100 ) {
			$coupon_amount = 100;
		}

		if ( empty( $coupon_amount ) ) {
			return;
		}

		$coupon->set_discount_type( $coupon_type );
		$coupon->set_amount( floatval( $coupon_amount ) );
		$coupon->set_individual_use( ! $use_with_others );
		$coupon->set_exclude_sale_items( ! $apply_to_on_sale );
		$coupon->set_minimum_amount( $minimum_subtotal );
		$coupon->set_usage_limit( $coupon_limitation );
		$coupon->set_usage_limit_per_user( $coupon_limit_per_user );

		$coupon->add_meta_data( 'sellkit_personalised_coupon_rule', $rule );

		if ( ! empty( $expiration_time ) ) {
			$coupon->set_date_expires( $expiration_time );
		}

		if ( $is_individual && ! empty( wp_get_current_user()->user_email ) ) {
			$coupon->set_email_restrictions( wp_get_current_user()->user_email );
		}

		// Create, publish and save coupon (data).
		$coupon->save();

		return [
			'code' => $coupon_code,
			'amount' => $coupon_amount,
			'type' => $coupon_type,
			'expiration_date' => empty( $expiration_time ) ? '' : get_date_from_gmt( date( 'Y-m-d H:i:s', $expiration_time ), 'Y/m/d h:i A' ),
			'display_type' => $display_type,
			'rule_id' => $rule,
			'coupon_id' => $coupon->get_id(),
		];
	}

	/**
	 * Coupons generator.
	 *
	 * @since 2.3.0
	 * @return string
	 */
	public static function generate_coupon_code() {
		return strtolower( wp_generate_password( 10, false ) );
	}

	/**
	 * Gets expiration time.
	 *
	 * @since 2.3.0
	 * @param string $number Number of type.
	 * @param string $type The type of time.
	 */
	private function get_expiration_time( $number, $type ) {
		if ( empty( $number ) || empty( $type ) ) {
			return false;
		}

		$type_days = 1;

		if ( 'weeks' === $type ) {
			$type_days = 7;
		}

		if ( 'months' === $type ) {
			$type_days = 30;
		}

		return time() + ( ( intval( $number ) * $type_days ) * ( 60 * 60 * 24 ) );
	}

	/**
	 * Gets coupons.
	 *
	 * @since 2.3.0
	 */
	public function get_coupon() {
		check_ajax_referer( 'sellkit_smart_coupon_code', 'nonce' );

		$display_type = sellkit_htmlspecialchars( INPUT_GET, 'display_type' );
		$coupon       = $this->create_coupons( $display_type );

		if ( ! empty( $coupon ) ) {
			setcookie( 'sellkit_personalised_coupon', wp_json_encode( $coupon ), time() + 86400, '/' );
		}

		wp_send_json_success( $coupon );
	}

	/**
	 * Gets rules by conditions.
	 *
	 * @SuppressWarnings(PHPMD.NPathComplexity)
	 * @since 2.3.0
	 * @return string
	 * @param string $display_type Display Type.
	 */
	private function get_rule_by_conditions( $display_type ) {
		$args = [
			'post_type' => 'sellkit-coupon',
			'post_status' => 'publish',
			'posts_per_page' => -1,
			'orderby'  => [ 'meta_value_num' => 'ASC' ],
			'meta_key' => 'sellkit_usage_limit', // phpcs:ignore
		];

		if ( 'add-to-content' === $display_type ) {
			$args['meta_query'] = [ // phpcs:ignore
				'relation' => 'AND',
				[
					'key'     => 'sellkit_add_content_page_post',
					'value'   => 'true',
				],
			];
		}

		$query = new \WP_Query( $args );

		foreach ( $query->posts as $post ) {
			$conditions     = get_post_meta( $post->ID, 'conditions', true );
			$is_valid       = true;
			$condition_type = ! empty( $conditions[1]['type'] ) ? $conditions[1]['type'] : 'and';

			if ( 'or' === $condition_type ) {
				$is_valid = false;
			}

			if ( ! is_array( $conditions ) ) {
				continue;
			}

			foreach ( $conditions as $condition ) {
				if ( is_array( $condition['condition_value'] ) && ! empty( $condition['condition_value'][0]['value'] ) ) {
					$condition['condition_value'] = sellkit_get_multi_select_values( $condition['condition_value'] );
				}

				$result = sellkit_condition_match( $condition['condition_subject'], $condition['condition_operator'], $condition['condition_value'] );

				if ( is_wp_error( $result ) ) {
					continue;
				}

				if ( ! $result ) {
					$is_valid = false;
				}

				if ( $result && 'or' === $condition_type ) {
					$is_valid = true;
					break;
				}
			}

			if ( true === $is_valid ) {
				return $post->ID;
			}
		}
	}

	/**
	 * Checks the cookie coupon.
	 *
	 * @since 2.3.0
	 */
	public function check_coupon() {
		check_ajax_referer( 'sellkit_smart_coupon_code', 'nonce' );

		$rule_id      = sellkit_htmlspecialchars( INPUT_GET, 'rule_id' );
		$coupon_id    = sellkit_htmlspecialchars( INPUT_GET, 'coupon_id' );
		$display_type = sellkit_htmlspecialchars( INPUT_GET, 'display_type' );
		$conditions   = get_post_meta( $rule_id, 'conditions', true );

		if ( $coupon_id ) {
			$this->maybe_update_coupon( $display_type, $coupon_id );
		}

		if ( sellkit_conditions_validation( $conditions ) ) {
			wp_send_json_success( [ 'coupon_is_valid' => true ] );
		}

		wp_send_json_success( [ 'coupon_is_valid' => false ] );
	}

	/**
	 * Update Coupon if needed.
	 *
	 * @SuppressWarnings(PHPMD.CyclomaticComplexity)
	 * @SuppressWarnings(PHPMD.NPathComplexity)
	 * @since 2.3.0
	 * @param string  $display_type Display Type.
	 * @param integer $coupon_id Coupon ID.
	 */
	public function maybe_update_coupon( $display_type, $coupon_id ) {
		$rule = $this->get_rule_by_conditions( $display_type );

		$coupon_meta           = get_post_meta( $rule );
		$filters               = get_post_meta( $rule, 'filters', true );
		$coupon_type           = ! empty( $coupon_meta['sellkit_type'][0] ) ? $coupon_meta['sellkit_type'][0] : 'percent';
		$coupon_amount         = ! empty( $coupon_meta['value'][0] ) ? $coupon_meta['value'][0] : 0;
		$use_with_others       = ! empty( $coupon_meta['use_with_other_coupon'][0] ) ? $coupon_meta['use_with_other_coupon'][0] : false;
		$apply_to_on_sale      = ! empty( $coupon_meta['apply_onsale_product'][0] ) ? $coupon_meta['apply_onsale_product'][0] : false;
		$minimum_subtotal      = ! empty( $coupon_meta['minimum_subtotal_count'][0] ) ? $coupon_meta['minimum_subtotal_count'][0] : '';
		$coupon_limitation     = ! empty( $coupon_meta['can_use_count_total'][0] ) ? $coupon_meta['can_use_count_total'][0] : '';
		$expiration_number     = ! empty( $coupon_meta['sellkit_expiration_date_number'][0] ) ? $coupon_meta['sellkit_expiration_date_number'][0] : '';
		$expiration_type       = ! empty( $coupon_meta['sellkit_expiration_date_type'][0] ) ? $coupon_meta['sellkit_expiration_date_type'][0] : '';
		$is_individual         = ! empty( $coupon_meta['sellkit_can_use'][0] ) ? $coupon_meta['sellkit_can_use'][0] : false;
		$coupon_limit_per_user = ! empty( $coupon_meta['sellkit_can_use_count'][0] ) ? $coupon_meta['sellkit_can_use_count'][0] : '';
		$expiration_time       = $this->get_expiration_time( $expiration_number, $expiration_type );
		$has_changed           = true;

		$coupon = new \WC_Coupon( $coupon_id );

		if ( empty( $filters ) ) {
			$filters = [];
		}

		foreach ( $filters as $filter ) {
			if ( 'products' === $filter['subject'] && 'is' === $filter['operator'] && sellkit_get_multi_select_values( $filter['value'] ) !== $coupon->get_product_ids() ) {
				$coupon->set_product_ids( sellkit_get_multi_select_values( $filter['value'] ) );
				$has_changed = true;
			}

			if ( 'products' === $filter['subject'] && 'is_not' === $filter['operator'] && sellkit_get_multi_select_values( $filter['value'] ) !== $coupon->set_excluded_product_ids() ) {
				$coupon->set_excluded_product_ids( sellkit_get_multi_select_values( $filter['value'] ) );
				$has_changed = true;
			}

			if ( 'categories' === $filter['subject'] && 'is_not' === $filter['operator'] && sellkit_get_multi_select_values( $filter['value'] ) !== $coupon->set_excluded_product_categories() ) {
				$coupon->set_excluded_product_categories( sellkit_get_multi_select_values( $filter['value'] ) );
				$has_changed = true;
			}

			if ( 'categories' === $filter['subject'] && 'is' === $filter['operator'] && sellkit_get_multi_select_values( $filter['value'] ) !== $coupon->set_product_categories() ) {
				$coupon->set_product_categories( sellkit_get_multi_select_values( $filter['value'] ) );
				$has_changed = true;
			}
		}

		if ( 'percent' === $coupon_type && $coupon_amount > 100 ) {
			$coupon_amount = 100;
		}

		if ( empty( $coupon_amount ) ) {
			return;
		}

		if ( $coupon_type !== $coupon->get_discount_type() ) {
			$coupon->set_discount_type( $coupon_type );
			$has_changed = true;
		}

		if ( floatval( $coupon_amount ) !== $coupon->get_amount() ) {
			$coupon->set_amount( floatval( $coupon_amount ) );
			$has_changed = true;
		}

		if ( ! $use_with_others !== $coupon->get_individual_use() ) {
			$coupon->set_individual_use( ! $use_with_others );
			$has_changed = true;
		}

		if ( ! $apply_to_on_sale !== $coupon->get_exclude_sale_items() ) {
			$coupon->set_exclude_sale_items( ! $apply_to_on_sale );
			$has_changed = true;
		}

		if ( $minimum_subtotal !== $coupon->get_minimum_amount() ) {
			$coupon->set_minimum_amount( $minimum_subtotal );
			$has_changed = true;
		}

		if ( $coupon_limitation !== $coupon->get_usage_limit() ) {
			$coupon->set_usage_limit( $coupon_limitation );
			$has_changed = true;
		}

		if ( $coupon_limit_per_user !== $coupon->get_usage_limit_per_user() ) {
			$coupon->set_usage_limit_per_user( $coupon_limit_per_user );
			$has_changed = true;
		}

		if ( ! empty( $expiration_time ) && $expiration_time !== $coupon->get_date_expires() ) {
			$coupon->set_date_expires( $expiration_time );
			$has_changed = true;
		}

		if ( $is_individual && ! empty( wp_get_current_user()->user_email ) && wp_get_current_user()->user_email !== $coupon->get_email_restrictions() ) {
			$coupon->set_email_restrictions( wp_get_current_user()->user_email );
			$has_changed = true;
		}

		if ( $is_individual && 'anyone' !== $is_individual && '' !== $coupon->get_usage_limit_per_user() ) {
			$coupon->set_usage_limit_per_user( '' );
			$has_changed = true;
		}

		if ( $is_individual && 'anyone' === $is_individual && '' !== $coupon->get_email_restrictions() ) {
			$coupon->set_email_restrictions( '' );
			$has_changed = true;
		}

		if ( $has_changed ) {
			$coupon->save();

			$coupon_data = [
				'code' => $coupon->get_code(),
				'amount' => $coupon_amount,
				'type' => $coupon_type,
				'expiration_date' => empty( $expiration_time ) ? '' : get_date_from_gmt( date( 'Y-m-d H:i:s', $expiration_time ), 'Y/m/d h:i A' ),
				'display_type' => $display_type,
				'rule_id' => $rule,
				'coupon_id' => $coupon->get_id(),
			];

			setcookie( 'sellkit_personalised_coupon', wp_json_encode( $coupon_data ), time() + 86400, '/' );
		}
	}
}
