<?php

final class BWFAN_Pro_WC_Create_Coupon extends BWFAN_Action {

	private static $ins = null;

	protected function __construct() {
		$this->action_name     = __( 'Create Coupon', 'wp-marketing-automations-pro' );
		$this->action_desc     = __( 'This action creates a personalized coupon for the customer', 'wp-marketing-automations-pro' );
		$this->required_fields = array( 'coupon', 'coupon_name' );
		$this->action_priority = 5;
		$this->support_v2      = true;
		$this->support_v1      = false;
	}

	public static function get_instance() {
		if ( null === self::$ins ) {
			self::$ins = new self();
		}

		return self::$ins;
	}

	/**
	 *  Make all the data which is required by the current action.
	 * This data will be used while executing the task of this action.
	 *
	 * @param $automation_data
	 * @param $step_data
	 *
	 * @return array|void
	 */
	public function make_v2_data( $automation_data, $step_data ) {
		$data_to_set          = array();
		$data_to_set['email'] = $automation_data['global']['email'];

		if ( ! isset( $step_data['coupon_data'] ) || empty( $step_data['coupon_data'] ) ) {
			return;
		}
		$coupon_details = $step_data['coupon_data'];

		$data_to_set['coupon']           = [];
		$data_to_set['coupon_type']      = isset( $coupon_details['type'] ) ? $coupon_details['type'] : 'new';
		$data_to_set['coupon']['prefix'] = isset( $coupon_details['general'] ) && isset( $coupon_details['general']['coupon_prefix'] ) ? BWFAN_Common::decode_merge_tags( $coupon_details['general']['coupon_prefix'] ) : '';

		if ( $data_to_set['coupon_type'] === 'existing' ) {
			$data_to_set['coupon_id'] = isset( $coupon_details['coupon_id'] ) && isset( $coupon_details['coupon_id']['key'] ) && ! empty( $coupon_details['coupon_id']['key'] ) ? $coupon_details['coupon_id']['key'] : '';
		} else {
			$data_to_set['coupon']['discount_type'] = isset( $coupon_details['general'] ) && isset( $coupon_details['general']['discount_type'] ) ? $coupon_details['general']['discount_type'] : 'percent';
			$data_to_set['coupon']['coupon_amount'] = isset( $coupon_details['general'] ) && isset( $coupon_details['general']['amount'] ) ? $coupon_details['general']['amount'] : 0;

			$data_to_set['coupon']['free_shipping'] = isset( $coupon_details['general'] ) && isset( $coupon_details['general']['allow_shipping'] ) ? $coupon_details['general']['allow_shipping'] : 0;

			/** getting the restrictions info of the coupons */
			if ( isset( $coupon_details['restrictions'] ) ) {
				if ( isset( $coupon_details['restrictions']['min_spend'] ) ) {
					$data_to_set['coupon']['minimum_amount'] = $coupon_details['restrictions']['min_spend'];
				}

				if ( isset( $coupon_details['restrictions']['max_spend'] ) ) {
					$data_to_set['coupon']['maximum_amount'] = $coupon_details['restrictions']['max_spend'];
				}

				if ( isset( $coupon_details['restrictions']['exclude_sale_item'] ) ) {
					$data_to_set['coupon']['exclude_sale_items'] = $coupon_details['restrictions']['exclude_sale_item'];
				}

				/**  individual_use in coupon data */
				if ( isset( $coupon_details['restrictions']['individual_use'] ) ) {
					$data_to_set['coupon']['individual_use'] = $coupon_details['restrictions']['individual_use'];
				}

				/**  restrict_customer_email in coupon data */
				if ( isset( $coupon_details['restrictions']['restrict_customer_email'] ) ) {
					$data_to_set['coupon']['restrict_customer_email'] = $coupon_details['restrictions']['restrict_customer_email'];
				}

				/** passing the product ids in coupon data */
				if ( isset( $coupon_details['restrictions']['products'] ) && is_array( $coupon_details['restrictions']['products'] ) ) {
					$data_to_set['coupon']['product_ids'] = array_map( function ( $product ) {
						return isset( $product['id'] ) ? $product['id'] : "";
					}, $coupon_details['restrictions']['products'] );
				}

				/** passing the excluded product ids in coupon data */
				if ( isset( $coupon_details['restrictions']['exclude_products'] ) && is_array( $coupon_details['restrictions']['exclude_products'] ) ) {
					$data_to_set['coupon']['exclude_product_ids'] = array_map( function ( $product ) {
						return isset( $product['id'] ) ? $product['id'] : "";
					}, $coupon_details['restrictions']['exclude_products'] );
				}

				/** passing the category ids in coupon data */
				if ( isset( $coupon_details['restrictions']['categories'] ) && is_array( $coupon_details['restrictions']['categories'] ) ) {
					$data_to_set['coupon']['product_categories'] = array_map( function ( $category ) {
						return isset( $category['id'] ) ? $category['id'] : "";
					}, $coupon_details['restrictions']['categories'] );
				}

				/** passing the excluded category ids in coupon data */
				if ( isset( $coupon_details['restrictions']['exclude_categories'] ) && is_array( $coupon_details['restrictions']['exclude_categories'] ) ) {
					$data_to_set['coupon']['exclude_product_categories'] = array_map( function ( $category ) {
						return isset( $category['id'] ) ? $category['id'] : "";
					}, $coupon_details['restrictions']['exclude_categories'] );
				}
			}
		}

		/** set the coupon expiry details */
		if ( isset( $coupon_details['general'] ) && isset( $coupon_details['general']['expiry'] ) ) {
			$data_to_set['coupon']['expiry'] = $coupon_details['general']['expiry'];
		}

		if ( isset( $coupon_details['general'] ) && isset( $coupon_details['general']['specific_expiry_type'] ) ) {
			$data_to_set['coupon']['specific_expiry_type'] = $coupon_details['general']['specific_expiry_type'];
		}

		/** get details of the limit usage settings of coupon */
		if ( isset( $coupon_details['limits'] ) ) {
			if ( isset( $coupon_details['limits']['usage_limit_per_coupon'] ) ) {
				$data_to_set['coupon']['usage_limit'] = $coupon_details['limits']['usage_limit_per_coupon'];
			}

			if ( isset( $coupon_details['limits']['usage_limit_per_user'] ) ) {
				$data_to_set['coupon']['usage_limit_per_user'] = $coupon_details['limits']['usage_limit_per_user'];
			}

			if ( isset( $coupon_details['limits']['usage_limit_x_item'] ) ) {
				$data_to_set['coupon']['limit_usage_to_x_items'] = $coupon_details['limits']['usage_limit_x_item'];
			}
		}

		return $data_to_set;
	}

	public function process_v2() {
		$data = $this->data;

		/** Coupon name */
		$coupon_prefix  = $data['coupon']['prefix'];
		$dynamic_string = BWFAN_Common::get_dynamic_string( 6 );

		$coupon_name = $coupon_prefix . $dynamic_string;

		/** set new coupon meta */
		$new_coupon_meta['_is_bwfan_coupon']     = 1;
		$new_coupon_meta['_bwfan_automation_id'] = $data['automation_id'];
		$new_coupon_meta['_bwfan_step_id']       = $data['step_id'];
		$new_coupon_meta['expiry_date']          = '';
		$new_coupon_meta['date_expires']         = '';
		$new_coupon_meta['customer_email']       = array();

		$new_coupon_meta['usage_limit'] = isset( $data['coupon']['usage_limit'] ) ? $data['coupon']['usage_limit'] : '';
		$specific_expiry_type           = isset( $data['coupon']['specific_expiry_type'] ) ? intval( $data['coupon']['specific_expiry_type'] ) : 0;
		/** set coupon expiry dates */
		if ( $specific_expiry_type > 0 && $specific_expiry_type !== 3 && isset( $data['coupon']['expiry'] ) && ! empty( $data['coupon']['expiry'] ) && 0 < absint( $data['coupon']['expiry'] ) ) {
			$expiry                          = $this->get_expiry_dates_v2( $data['coupon']['expiry'], $specific_expiry_type );
			$new_coupon_meta['expiry_date']  = $expiry['expire_on'];
			$new_coupon_meta['date_expires'] = $expiry['expiry_timestamped'];
		}

		if ( isset( $data['coupon_type'] ) && $data['coupon_type'] === 'existing' ) {
			if ( ! isset( $data['coupon_id'] ) || empty( $data['coupon_id'] ) ) {
				return $this->error_response( __( 'Coupon ID is required for existing coupon type', 'wp-marketing-automations-pro' ) );
			}

			$coupon_id = $data['coupon_id'];
			$coupon    = new WC_Coupon( $coupon_id );

			if ( ! $coupon instanceof WC_Coupon ) {
				return $this->error_response( __( 'Coupon does not exist', 'wp-marketing-automations-pro' ) );
			}

			/** creating new coupon */
			$new_coupon_id = $this->create_coupon( $coupon_name, $new_coupon_meta );
			if ( is_array( $new_coupon_id ) && count( $new_coupon_id ) > 0 ) {
				/** Some error occurred while making coupon post */
				return $this->prepare_response( $coupon_id );
			}
			$new_coupon = new WC_Coupon( $new_coupon_id );
			// Get existing coupon meta
			$existing_coupon_meta = get_post_meta( $coupon_id );
			// Copy existing coupon meta to new coupon
			foreach ( $existing_coupon_meta as $key => $values ) {
				foreach ( $values as $value ) {
					// Ensure to exclude core meta keys that should not be duplicated
					if ( ! in_array( $key, array(
						'_edit_lock',
						'_edit_last',
						'date_expires',
						'usage_limit',
						'usage_count',
						'expiry_date',
						'_is_bwfan_coupon',
						'_bwfan_automation_id',
						'_bwfan_step_id'
					) ) ) {
						add_post_meta( $new_coupon_id, $key, maybe_unserialize( $value ) );
					}
				}
			}

			if ( isset( $data['coupon']['limit_usage_to_x_items'] ) && ! empty( $data['coupon']['limit_usage_to_x_items'] ) ) {
				$new_coupon->set_limit_usage_to_x_items( $data['coupon']['limit_usage_to_x_items'] );
			}

			if ( isset( $data['coupon']['usage_limit_per_user'] ) && ! empty( $data['coupon']['usage_limit_per_user'] ) ) {
				$new_coupon->set_usage_limit_per_user( $data['coupon']['usage_limit_per_user'] );
			}

			// Save the new coupon
			$new_coupon->save();
		} else {
			if ( ! isset( $data['coupon']['discount_type'] ) || ! array_key_exists( $data['coupon']['discount_type'], wc_get_coupon_types() ) ) {
				return $this->error_response( __( 'Invalid discount type: ' . $data['coupon']['discount_type'], 'wp-marketing-automations-pro' ) );
			}

			/** creating new coupon */
			$coupon_id = $this->create_coupon( $coupon_name, $new_coupon_meta );
			if ( is_array( $coupon_id ) && count( $coupon_id ) > 0 ) {
				/** Some error occurred while making coupon post */
				return $this->prepare_response( $coupon_id );
			}

			/** restricted coupon with customer email */
			if ( isset( $data['coupon']['restrict_customer_email'] ) && 1 === absint( $data['coupon']['restrict_customer_email'] ) ) {
				$this->handle_coupon_restriction( $coupon_id, $data['email'] );
			}

			/** passing other coupon details */
			$this->handle_other_coupon_restriction( $coupon_id, $data['coupon'] );
		}

		/** update new coupon value in automation contact row */
		$automation_contact_id = $data['automation_contact_id'];
		$row_data              = $this->get_automation_contact_row( $automation_contact_id );
		if ( ! empty( $row_data ) ) {
			$coupons_data                     = isset( $row_data['coupons'] ) && is_array( $row_data['coupons'] ) ? $row_data['coupons'] : [];
			$coupons_data[ $data['step_id'] ] = $coupon_name;
			$row_data['coupons']              = $coupons_data;

			BWFAN_Model_Automation_Contact::update( array(
				'data' => json_encode( $row_data )
			), array(
				'ID' => $automation_contact_id,
			) );
		}

		/** using special property to end the current automation process for a contact */
		BWFAN_Common::$end_v2_current_contact_automation = true;

		do_action( 'bwfan_coupon_created_v2', $coupon_id, $coupon_name, $data );

		/** Set coupon name in data */
		$data['coupon_name'] = $coupon_name;
		$this->set_data( $data );

		return $this->prepare_response( $coupon_id );
	}

	/**
	 * Get automation contact row data only
	 *
	 * @param $automation_contact_id
	 *
	 * @return mixed|void|null
	 */
	public function get_automation_contact_row( $automation_contact_id ) {
		if ( empty( $automation_contact_id ) ) {
			return;
		}

		$automation_contact_data = BWFAN_Model_Automation_Contact::get_data( $automation_contact_id );
		if ( empty( $automation_contact_data ) ) {
			return;
		}

		return json_decode( $automation_contact_data['data'], true );
	}

	public function handle_other_coupon_restriction( $coupon_id, $coupon_data ) {
		if ( empty( $coupon_data ) ) {
			return;
		}

		$coupon = new WC_Coupon( $coupon_id );
		if ( ! $coupon instanceof WC_Coupon ) {
			return;
		}

		/** set coupon type */
		$coupon->set_discount_type( $coupon_data['discount_type'] );
		$coupon->set_amount( $coupon_data['coupon_amount'] );
		$coupon->set_free_shipping( $coupon_data['free_shipping'] );

		if ( isset( $coupon_data['minimum_amount'] ) ) {
			$coupon->set_minimum_amount( $coupon_data['minimum_amount'] );
		}

		if ( isset( $coupon_data['maximum_amount'] ) ) {
			$coupon->set_maximum_amount( $coupon_data['maximum_amount'] );
		}

		if ( isset( $coupon_data['exclude_sale_items'] ) ) {
			$coupon->set_exclude_sale_items( $coupon_data['exclude_sale_items'] );
		}

		if ( isset( $coupon_data['individual_use'] ) ) {
			$coupon->set_individual_use( $coupon_data['individual_use'] );
		}

		if ( isset( $coupon_data['product_ids'] ) ) {
			$coupon->set_product_ids( $coupon_data['product_ids'] );
		}

		if ( isset( $coupon_data['exclude_product_ids'] ) ) {
			$coupon->set_excluded_product_ids( $coupon_data['exclude_product_ids'] );
		}

		if ( isset( $coupon_data['product_categories'] ) ) {
			$coupon->set_product_categories( $coupon_data['product_categories'] );
		}

		if ( isset( $coupon_data['exclude_product_categories'] ) ) {
			$coupon->set_excluded_product_categories( $coupon_data['exclude_product_categories'] );
		}

		if ( isset( $coupon_data['usage_limit'] ) ) {
			$coupon->set_usage_limit( $coupon_data['usage_limit'] );
		}

		if ( isset( $coupon_data['usage_limit_per_user'] ) ) {
			$coupon->set_usage_limit_per_user( $coupon_data['usage_limit_per_user'] );
		}

		if ( isset( $coupon_data['limit_usage_to_x_items'] ) ) {
			$coupon->set_limit_usage_to_x_items( $coupon_data['limit_usage_to_x_items'] );
		}

		$coupon->save();

		return $coupon;
	}

	/** set expiry date for newly created coupon
	 *
	 * @param $expiry
	 * @param $specific_expiry_type
	 *
	 * @return array
	 */
	public function get_expiry_dates_v2( $expiry, $specific_expiry_type ) {
		$dbj = new DateTime();
		if ( $specific_expiry_type == 2 ) { // in case specific date mention
			$exptime = strtotime( strval( $expiry ) );
			$dbj->setTimestamp( $exptime );
		} else {
			$expiry  += 1;
			$exptime = strtotime( "+{$expiry} days" );
			$dbj->setTimestamp( $exptime );
		}

		$exp_date         = $dbj->format( 'Y-m-d' );
		$exp_date_email   = date( 'Y-m-d', $exptime );
		$expiry_timestamp = $exptime;

		return array(
			'expiry'             => $exp_date,
			'expire_on'          => $exp_date_email,
			'expiry_timestamped' => $expiry_timestamp,
		);
	}

	public function create_coupon( $coupon_name, $meta_data ) {
		$args = array(
			'post_type'   => 'shop_coupon',
			'post_status' => 'publish',
			'post_title'  => $coupon_name,
		);

		$coupon_id = wp_insert_post( $args );
		if ( ! is_wp_error( $coupon_id ) ) {
			$meta_data['usage_count'] = 0;
			if ( is_array( $meta_data ) && count( $meta_data ) > 0 ) {
				foreach ( $meta_data as $key => $val ) {
					update_post_meta( $coupon_id, $key, $val );
				}
			}

			return $coupon_id;
		}

		return array(
			'err_msg' => $coupon_id->get_error_message(),
		);
	}

	public function prepare_response( $result ) {
		if ( is_array( $result ) && count( $result ) > 0 ) { // Error in coupon creation
			return $this->error_response( $result['err_msg'] );
		}

		if ( ! is_integer( $result ) ) {
			return $this->error_response( __( 'Coupon does not exist', 'wp-marketing-automations-pro' ) );
		}

		$get_type = get_post_field( 'post_type', $result );
		if ( 'shop_coupon' !== $get_type ) {
			return $this->error_response( __( 'Coupon does not exist', 'wp-marketing-automations-pro' ) );
		}

		return $this->success_message( "Coupon {$this->data['coupon_name']} created." );
	}

	/**
	 * @param $coupon_id
	 * @param $email
	 *
	 * @return void|WC_Coupon
	 */
	public function handle_coupon_restriction( $coupon_id, $email ) {
		if ( ! is_email( $email ) ) {
			return;
		}

		$coupon = new WC_Coupon( $coupon_id );
		if ( 0 === $coupon->get_id() ) {
			return;
		}

		$coupon->set_email_restrictions( [ $email ] );
		$coupon->save();

		return $coupon;
	}

	/**
	 * Execute the current action.
	 * Return 3 for successful execution , 4 for permanent failure.
	 *
	 * @param $action_data
	 *
	 * @return array
	 */
	public function execute_action( $action_data ) {
		$this->set_data( $action_data['processed_data'] );
		$result = $this->process();
		if ( $this->fields_missing ) {
			return array(
				'status'  => 4,
				'message' => $result['body'][0],
			);
		}

		if ( is_array( $result ) && count( $result ) > 0 ) { // Error in coupon creation
			return array(
				'status'  => 4,
				'message' => $result['err_msg'],
			);
		}

		if ( ! is_integer( $result ) ) {
			return array(
				'status'  => 4,
				'message' => __( 'Coupon does not exist', 'wp-marketing-automations-pro' ),
			);
		}
		$get_type = get_post_field( 'post_type', $result );
		if ( 'shop_coupon' !== $get_type ) {
			return array(
				'status'  => 4,
				'message' => __( 'Coupon does not exist', 'wp-marketing-automations-pro' ),
			);
		}

		return array(
			'status'  => 3,
			'message' => "Coupon {$this->data['coupon_name']} created."
		);
	}

	public function get_fields_schema() {
		return [
			[
				'id'                  => 'coupon_data',
				'type'                => 'create_coupon',
				'required'            => true,
				'coupon_type_options' => BWFAN_Common::prepared_field_options( wc_get_coupon_types() ),
			]
		];
	}

	public function get_desc_text( $data ) {
		$data = json_decode( wp_json_encode( $data ), true );
		if ( ! isset( $data['coupon_data'] ) || empty( $data['coupon_data'] ) || ! isset( $data['coupon_data']['general'] ) ) {
			return '';
		}

		return isset( $data['coupon_data']['general']['title'] ) ? $data['coupon_data']['general']['title'] : '';
	}
}

/**
 * Register this action. Registering the action will make it eligible to see it on single automation screen in select actions dropdown.
 */
return 'BWFAN_Pro_WC_Create_Coupon';
