<?php

#[AllowDynamicProperties]
abstract class BWFAN_Event {
	public $support_lang = false;
	public $log_type = 'event_triggered';
	public $global_data = array();
	public $event_data = array();
	protected $sync_start_time = 0;
	protected $sync_id = 0;
	public $message_validate_event = null;
	/** @var string Source that event belongs to */
	protected $source_type = 'wp';
	/** @var string Event Optgroup label */
	protected $optgroup_label = 'WordPress';
	/** @var int Optgroup priority */
	protected $optgroup_priority = 10;
	/** @var int Event priority */
	protected $priority = 200;
	/** @var string Event nice name */
	protected $event_name = '';
	/** @var string Event description */
	protected $event_desc = '';
	protected $excluded_actions = array();
	protected $included_actions = array();
	protected $event_saved_data = array();
	/** @var string Event slug used in array making to fetch the event object */
	protected $localize_data = array();
	protected $is_time_independent = false;
	protected $validation_passed = false;
	protected $event_actions = array();
	protected $track_automation_run = true;
	protected $need_unique_key = false;
	/** Customer supported */
	protected $customer_email_tag = '{{contact_email}}';
	/** @var array merge tag groups array supported by the event */
	protected $event_merge_tag_groups = array();
	/** @var array rule groups array supported by the event */
	protected $event_rule_groups = array();
	protected $user_selected_actions = array();
	protected $automations_for_current_event_db = array();
	protected $event_automation_id = null;
	protected $error_message = '';
	protected $automations_arr = array();
	/** v2 */
	protected $automations_v2_arr = array();
	protected $v2 = false;
	protected $is_goal = false;
	protected $goal_name = '';
	protected $goal_desc = '';
	protected $support_v1 = true;
	/** History sync properties */
	protected $page = null;
	protected $offset = null;
	protected $processed = null;
	protected $supported_blocks = [];
	protected $has_run = false;
	protected $unique_key = null;

	protected $automation_add = false;
	protected $automation_add_desc = '';

	/** @var string Disable adding default field in event schema */
	protected $disable_default_fields = false;

	protected $force_async = false;

	public function is_goal() {
		return $this->is_goal;
	}

	public function get_goal_name() {
		if ( ! empty( $this->goal_name ) ) {
			return $this->goal_name;
		}

		return $this->event_name;
	}

	public function get_goal_desc() {
		if ( ! empty( $this->goal_desc ) ) {
			return $this->goal_desc;
		}

		return $this->event_desc;
	}

	public function validate_event( $task_details ) {
		$result            = array();
		$result['status']  = 1;
		$result['message'] = '';

		return $result;
	}

	public function validate_event_data_before_executing_task( $data ) {
		return true;
	}

	public function load_hooks() {
	}

	public function get_automation_event_validation() {
		return array(
			'status'  => 1,
			'message' => '',
		);
	}

	public function get_automation_event_status() {
		return array(
			'status'  => 4,
			'message' => __( 'Event has been changed in the automation', 'wp-marketing-automations' ),
		);
	}

	public function get_automation_event_success() {
		return array(
			'status'  => 1,
			'message' => '',
		);
	}

	/**
	 * show the validate checkbox in event meta fields
	 * contains text related to wc order only.
	 * Is overridable in the child event class
	 *
	 * @param $unique_slug
	 * @param $section_label
	 * @param $field_label
	 */
	public function get_validation_html( $unique_slug, $section_label, $field_label ) {
		?>
        <div class="bwfan-col-sm-12 bwfan-pl-0 bwfan_mt15">
            <label for="" class="bwfan-label-title"><?php echo $section_label; //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></label>
            <input type="checkbox" name="event_meta[validate_event]" id="bwfan-validate_event" value="1" class="validate_event_1 <?php echo esc_html( $unique_slug ); ?>-validate_event" {{is_validated}}/>
            <label for="bwfan-validate_event" class="bwfan-checkbox-label"><?php echo $field_label; //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></label>
            <div class="clearfix bwfan_field_desc"><?php echo __( 'This setting is useful to <u>verify time-delayed Actions</u>. For instance, you can create a follow-up Action that runs after 30 days of placing an order. That Action won\'t trigger if the above selected Order Statuses are not matched to the order.', 'wp-marketing-automations' ); //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></div>
        </div>
		<?php
	}

	/**
	 * A controller function to run automation every time an appropriate event occurs
	 * usually called by the event class just after the event hook to load all automations and run.
	 * @return array|bool
	 */
	public function run_automations() {
		BWFAN_Core()->public->load_active_automations( $this->get_slug() );

		if ( ! is_array( $this->automations_arr ) || count( $this->automations_arr ) === 0 ) {
			BWFAN_Core()->logger->log( 'Async callback: No active automations found. Event - ' . $this->get_slug(), $this->log_type );

			return false;
		}

		/** Extra checking for certain event like form events */
		$this->automations_arr = $this->validate_event_data_before_creating_task( $this->automations_arr );

		if ( ! is_array( $this->automations_arr ) || count( $this->automations_arr ) === 0 ) {
			return false;
		}

		$automation_actions = [];

		foreach ( $this->automations_arr as $automation_id => $automation_data ) {
			if ( $this->get_slug() !== $automation_data['event'] || 0 !== intval( $automation_data['requires_update'] ) ) {
				continue;
			}
			$ran_actions                          = $this->handle_single_automation_run( $automation_data, $automation_id );
			$automation_actions[ $automation_id ] = $ran_actions;
		}

		return $automation_actions;
	}

	public function get_slug() {
		return str_replace( array( 'bwfan_' ), '', sanitize_title( get_class( $this ) ) );
	}

	public function validate_event_data_before_creating_task( $automations_arr ) {
		return $automations_arr;
	}

	/**
	 * Handle execution of each automation to get all the executable tasks for the automation.
	 * Also responsible to run pre executable action function to instruct events to setup required data before execution.
	 *
	 * @param $automation_data
	 * @param $automation_id
	 *
	 * @return bool|int
	 */
	public function handle_single_automation_run( $automation_data, $automation_id ) {
		$this->event_automation_id = $automation_id;

		/** Setup the rules data */
		$this->pre_executable_actions( $automation_data );

		/** get all the actions which have passed the rules */
		$actions = $this->get_executable_actions( $automation_data );

		if ( ! isset( $actions['actions'] ) || ! is_array( $actions['actions'] ) || count( $actions['actions'] ) === 0 ) {
			BWFAN_Core()->logger->log( 'No task eligible for Automation ID - ' . $automation_id . '. Event - ' . $this->get_slug(), $this->log_type );

			return false;
		}

		$event_data = $this->get_automation_event_data( $automation_data );

		/** This only occurs when sync process is going on */
		if ( ! empty( $this->user_selected_actions ) ) {
			$final_actions = $this->filter_executable_actions( $actions['actions'] );

			try {
				$final_actions['actions'] = $this->recalculate_actions_time( $final_actions['actions'] );
			} catch ( Exception $exception ) {
				BWFAN_Core()->logger->log( 'Register task function not overrided by child class ->' . get_class( $this ), $this->log_type );
			}

			$actions['actions'] = $final_actions['actions'];
		}

		try {
			/** Register all those tasks which passed through rules or which are direct actions. The following function is present in every event class. */
			$this->register_tasks( $automation_id, $actions['actions'], $event_data );
		} catch ( Exception $exception ) {
			BWFAN_Core()->logger->log( 'Register task function not overrided by child class' . get_class( $this ), $this->log_type );
		}

		return count( $actions['actions'] );
	}

	/**
	 * Make rules data for every event.
	 *
	 * @param $automation_data
	 */
	public function pre_executable_actions( $automation_data ) {

	}

	/**
	 * Get the actions which are actually going to run.
	 *
	 * @param $automation_meta
	 *
	 * @return array
	 */
	public function get_executable_actions( $automation_meta ) {
		$this->event_actions = [];
		$ui_data             = isset( $automation_meta['uiData'] ) ? $automation_meta['uiData'] : [];

		foreach ( $ui_data as $details ) {
			$return_data = $this->get_actions_data( $details, $automation_meta );
			if ( is_array( $return_data ) && count( $return_data ) > 0 ) {
				$this->event_actions[] = $return_data;
			}
			if ( $this->validation_passed ) {
				$this->validation_passed = false;
				break;
			}
		}

		$executable_actions = $this->combine_actions();

		return $executable_actions;
	}

	/**
	 * Get those actions which satisfies the rules.
	 *
	 * @param $details
	 * @param $automation_meta
	 *
	 * @return array
	 */
	public function get_actions_data( $details, $automation_meta ) {
		$return_data = [];

		switch ( $details['id'] ) {
			case 'condition':
				$group_id         = $details['group_id'];
				$group_conditions = $automation_meta['condition'][ $group_id ];
				$is_passed        = BWFAN_Core()->rules->match_groups( $group_conditions );

				if ( $is_passed ) {
					$return_data['actions']  = $automation_meta['actions'][ $group_id ];
					$return_data['group_id'] = $group_id;
					$this->validation_passed = true;
				}
				break;
			case 'action':
				$group_id                = $details['group_id'];
				$return_data['actions']  = $automation_meta['actions'][ $group_id ];
				$return_data['group_id'] = $group_id;
				break;
			default:
				break;
		}

		return $return_data;
	}

	/**
	 * Combines all the actions of all groups whose tasks will be made.
	 * @return array
	 */
	public function combine_actions() {
		if ( ! is_array( $this->event_actions ) || 0 === count( $this->event_actions ) ) {
			return $this->event_actions;
		}

		$result      = [];
		$all_actions = [];
		foreach ( $this->event_actions as $details ) {
			$actions  = $details['actions'];
			$group_id = $details['group_id'];
			if ( ! is_array( $actions ) || empty( $actions ) ) {
				continue;
			}
			foreach ( $actions as $key1 => $action_detail ) {
				if ( empty( $action_detail['action_slug'] ) || empty( $action_detail['integration_slug'] ) ) {
					continue;
				}
				$action_detail['group_id']  = $group_id;
				$action_detail['action_id'] = $key1;
				$all_actions[]              = $action_detail;
			}
		}

		$this->event_actions = [];
		$result['actions']   = $all_actions;

		return $result;
	}

	/**
	 * Returns the current event settings set in the automation at the time of task creation.
	 *
	 * @param $value
	 *
	 * @return array
	 */
	public function get_automation_event_data( $value ) {
		return [
			'event_source'   => $value['source'],
			'event_slug'     => $value['event'],
			'validate_event' => ( isset( $value['event_meta']['validate_event'] ) ) ? 1 : 0,
		];
	}

	public function filter_executable_actions( $actions ) {
		$final_actions         = [];
		$user_selected_actions = $this->user_selected_actions;

		foreach ( $user_selected_actions as $group_actions ) {

			foreach ( $group_actions as $action_details ) {
				$action_slug = $action_details['action_slug'];

				foreach ( $actions as $act_ind => $act_det ) {
					$act_sl     = $act_det['action_slug'];
					$unique_key = $act_sl . '_' . $act_ind;

					if ( $action_slug === $act_sl ) {
						if ( ! isset( $final_actions[ $unique_key ] ) ) {
							$final_actions[ $unique_key ] = $act_det;
						}
					}
				}
			}
		}

		sort( $final_actions );

		return array(
			'actions' => $final_actions,
		);
	}

	/**
	 * @param $actions
	 *
	 * Recalculate action's execution time with respect to order date.
	 *
	 * @return mixed
	 * @throws Exception
	 */
	public function recalculate_actions_time( $actions ) {
		throw new ErrorException( 'This function `' . __FUNCTION__ . '` Must be override in child class' );
	}

	public function register_tasks( $automation_id, $actions, $event_data ) {
		throw new ErrorException( 'This function `' . __FUNCTION__ . '` Must be override in child class' );
	}

	/**
	 * @param $automation - automation with data
	 *
	 * @return false|void
	 */
	public function run_v2( $automation, $event_slug ) {
		$aid         = $automation['ID'];
		$event       = BWFAN_Core()->sources->get_event( $event_slug );
		$global_data = apply_filters( 'bwfan_modify_event_data', $event->get_event_data() );
		$global_data = BWFAN_Common::get_global_data( $global_data );
		$event_data  = $this->get_automation_event_data( $automation );

		$global_data['event_data']              = $event_data;
		$global_data['global']['automation_id'] = $aid;

		if ( empty( $global_data['global']['cid'] ) ) {
			return false;
		}

		/** Validate automation common settings like run count */
		if ( false === BWFAN_Model_Automations_V2::validation_automation_run_count( $aid, $global_data['global']['cid'], $automation ) ) {
			BWFAN_Common::log_test_data( 'Automation ID ' . $aid . ' already run on a contact ' . $global_data['global']['cid'] . '. Event - ' . $event_slug, 'contact-exist-automation', true );

			return false;
		}

		$data = [
			'cid'       => intval( $global_data['global']['cid'] ),
			'aid'       => $aid,
			'event'     => $event_slug,
			'c_date'    => current_time( 'mysql', 1 ),
			'e_time'    => current_time( 'timestamp', 1 ),
			'last_time' => current_time( 'timestamp', 1 ),
			'data'      => json_encode( $global_data )
		];

		/** In case of duplicate run, when hook runs twice. */
		$already_exists = BWFAN_Model_Automation_Contact::check_duplicate_automation_contact( $data );
		if ( $already_exists ) {
			BWFAN_Common::log_test_data( 'Automation ID ' . $data['aid'] . ' already exists with same data for contact ' . $data['cid'] . '. Event - ' . $data['event'], 'contact-duplicate-automation', true );
			BWFAN_Common::log_test_data( $global_data, 'contact-duplicate-automation', true );

			return false;
		}

		BWFAN_Model_Automation_Contact::insert( $data );
	}

	public function get_automations_data( $v = 1 ) {
		return ( 2 === $v ) ? $this->automations_v2_arr : $this->automations_arr;
	}

	public function check_if_bulk_process_executing( $should_logs_made ) {
		if ( is_array( $this->user_selected_actions ) && count( $this->user_selected_actions ) > 0 ) {
			return false;
		}

		return $should_logs_made;
	}

	/**
	 * Create tasks of the actions.
	 *
	 * @param $automation_id
	 * @param $actions
	 * @param $event_data
	 * @param $data
	 */
	public function create_tasks( $automation_id, $actions, $event_data, $data ) {
		/** Check if Autonami is in sandbox mode */
		if ( true === BWFAN_Common::is_sandbox_mode_active() ) {
			return;
		}

		$a_track_id       = $this->automations_arr[ $automation_id ]['a_track_id'];
		$total_tasks_made = [];
		/** For modify data */
		$data = apply_filters( 'bwfan_modify_event_data', $data );
		/** Get global data */
		$data = BWFAN_Common::get_global_data( $data );

		do_action( 'bwfan_before_creating_tasks', $automation_id, $actions, $event_data, $data );

		$immediate_actions = [];

		foreach ( $actions as $index => $action ) {
			$should_task_create = $this->should_task_create( $action, $data );

			if ( false === $should_task_create ) {
				continue;
			}
			// Task data can be modified before making a task
			$action  = apply_filters( 'bwfan_pre_insert_task', $action, $automation_id, $this );
			$task_id = BWFAN_Core()->tasks->insert_task( $automation_id, $action, $this );

			if ( isset( $action['data_meta'] ) ) {
				$data['data_meta'] = $action['data_meta'];
			}

			$data['event_data'] = $event_data;
			$data['data']       = ( isset( $action['data'] ) ) ? $action['data'] : array();
			$data['group_id']   = $action['group_id'];
			$data['action_id']  = $action['action_id'];
			$data               = apply_filters( 'bwfan_alter_taskdata', $data );
			$data               = apply_filters( 'bwfan_alter_taskdata_' . $this->get_slug(), $data );
			BWFAN_Core()->tasks->insert_taskmeta( $task_id, 'integration_data', $data );

			// Unique task tracking id
			$t_track_id = $a_track_id . '_' . $action['group_id'] . '_' . $action['action_id'];
			BWFAN_Core()->tasks->insert_taskmeta( $task_id, 't_track_id', $t_track_id );

			// Actions can be performed after task in inserted into db
			do_action( 'bwfan_task_created', $index, $task_id );
			do_action( 'bwfan_task_created_' . $this->get_slug(), $index, $task_id );

			$total_tasks_made[] = $task_id;

			/** Checking immediately executable actions */
			if ( ! isset( $action['time']['delay_type'] ) || 'immediately' === $action['time']['delay_type'] ) {
				$immediate_actions[] = $task_id;
			}
		}

		do_action( 'bwfan_after_creating_tasks', $automation_id, $actions, $event_data, $data, $total_tasks_made );

		/** Executing immediately executable actions */
		$this->execute_immediate_tasks( $immediate_actions );

		// Increase the automation run count and fire contact creation async call only when async process in not running
		if ( empty( $this->user_selected_actions ) ) {
			BWFAN_Core()->automations->update_automation_run_count( $automation_id );

			if ( $this->track_automation_run ) {
				// Send an async call for updating contact meta
				$this->send_async_contact_call( $automation_id );
			}
		}

		if ( count( $total_tasks_made ) > 0 ) {
			BWFAN_Core()->logger->log( 'Total ' . count( $total_tasks_made ) . ' tasks created. Event - ' . $this->get_slug() . ', Task IDs -' . implode( ', ', $total_tasks_made ), $this->log_type ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions
		} else {
			BWFAN_Core()->logger->log( '0 Tasks created. Event - ' . $this->get_slug(), $this->log_type ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions
		}
	}

	/**
	 * Check if task for an action should be created or not.
	 *
	 * @param $action_data
	 *
	 * @return bool
	 */
	public function should_task_create( $action_data, $data ) {
		if ( ! isset( $action_data['integration_slug'] ) ) {
			return false;
		}

		$action_instance = BWFAN_Core()->integration->get_action( $action_data['action_slug'] );

		/** If action not found then load connector classes */
		if ( empty( $action_instance ) ) {
			WFCO_Load_Connectors::load_connectors_direct();
			BWFAN_Load_Connectors::get_instance()->run_connectors();
			$action_instance = BWFAN_Core()->integration->get_action( $action_data['action_slug'] );
		}

		if ( ! $action_instance instanceof BWFAN_Action ) {
			return false;
		}

		$check_action_data = $action_instance->check_required_data( $data );

		if ( false === $check_action_data ) {
			return false;
		}

		$check_language_support = $this->check_language_support( $action_data, $data );
		if ( false === $check_language_support ) {
			return false;
		}

		return true;
	}

	public function check_language_support( $action_data, $data ) {
		/** checking for language support **/
		if ( BWFAN_Common::should_skip_language_support() ) {
			return true;
		}

		if ( false === $this->support_lang || ! isset( $action_data['language'] ) || ! isset( $action_data['language']['enable_lang'] ) || 1 !== absint( $action_data['language']['enable_lang'] ) && ! isset( $action_data['language']['lang'] ) || empty( $action_data['language']['lang'] ) ) {
			return true;
		}

		$selected_lang = $action_data['language']['lang'];
		$lang          = $this->get_language_from_event( $data );
		if ( $lang === $selected_lang ) {
			return true;
		}

		return false;
	}

	public function get_language_from_event( $data ) {
		$lang  = '';
		$order = isset( $data['global']['wc_order'] ) ? $data['global']['wc_order'] : '';
		if ( ! $order instanceof WC_Order && isset( $data['global']['order_id'] ) ) {
			$order = wc_get_order( $data['global']['order_id'] );
		}

		if ( ! $order instanceof WC_Order && isset( $data['global']['wc_order_id'] ) ) {
			$order = wc_get_order( $data['global']['wc_order_id'] );
		}

		if ( $order instanceof WC_Order ) {

			if ( isset( $data['global']['language'] ) && ! empty( $data['global']['language'] ) ) {
				$lang = $data['global']['language'];
			}

		} elseif ( isset( $data['global']['cart_abandoned_id'] ) ) {
			$cart_details  = BWFAN_Model_Abandonedcarts::get( $data['global']['cart_abandoned_id'] );
			$checkout_data = json_decode( $cart_details['checkout_data'], true );
			if ( isset( $checkout_data['lang'] ) ) {
				$lang = $checkout_data['lang'];
			}
		}

		return $lang;
	}

	public function execute_immediate_tasks( $task_ids ) {
		if ( empty( $task_ids ) ) {
			return;
		}

		/** set claim_id to 1 for the immediate tasks so it will not run by the action scheduler */

		global $wpdb;
		$placeholders = array_fill( 0, count( $task_ids ), '%d' );
		$placeholders = implode( ', ', $placeholders );

		$query = $wpdb->prepare( "UPDATE `{$wpdb->prefix}bwfan_tasks` SET `claim_id` = 1 WHERE `ID` IN ($placeholders)", $task_ids );
		$wpdb->query( $query ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching

		/** @var BWFAN_Tasks $task_ins */
		$task_ins = BWFAN_Tasks::get_instance();
		foreach ( $task_ids as $id ) {
			$task_ins->bwfan_ac_execute_task( $id );
		}
	}

	/**
	 * Send async call for updating the contact automation details
	 *
	 * @param $automation_id
	 */
	public function send_async_contact_call( $automation_id ) {
		$email = $this->get_email_event();
		if ( false === $email ) {
			BWFAN_Core()->logger->log( $this->error_message . '. Automation ID - ' . $automation_id . '. Event - ' . $this->get_slug(), $this->log_type );

			return;
		}

		$user_id   = $this->get_user_id_event();
		$url       = rest_url( '/autonami/v1/update-contact-automation' );
		$body_data = array(
			'automation_id' => $automation_id,
			'email'         => $email,
			'user_id'       => $user_id,
			'unique_key'    => get_option( 'bwfan_u_key', false ),
		);
		$args      = bwf_get_remote_rest_args( $body_data );

		wp_remote_post( $url, $args );
	}

	/**
	 * If any event has email and it does not contain order object, then following method must be overridden by child event class.
	 * Return email
	 * @return bool
	 */
	public function get_email_event() {
		$order = $this->order;
		if ( $order instanceof WC_Order ) {
			return $order->get_billing_email();
		}

		$this->error_message = __( 'Not a valid WC order object', 'wp-marketing-automations' );
		$email               = false;

		return $email;
	}

	/**
	 * If any event has user id and it does not contain order object, then following method must be overridden by child event class.
	 * Return user id
	 * @return bool
	 */
	public function get_user_id_event() {
		$order = $this->order;
		if ( $order instanceof WC_Order ) {
			return $order->get_user_id();
		}

		$this->error_message = __( 'Not a valid WC order object', 'wp-marketing-automations' );
		$user_id             = false;

		return $user_id;
	}

	/**
	 * Calculate actions time based on record date.
	 *
	 * @param $actions
	 * @param $record_date DateTime
	 *
	 * @return mixed
	 * @throws Exception
	 */

	public function calculate_actions_time( $actions, $record_date ) {
		BWFAN_Common::convert_from_gmt( $record_date ); // convert to site time
		BWFAN_Common::convert_to_gmt( $record_date );

		$record_date_timestamp = $record_date->getTimestamp();
		$current_timestamp     = current_time( 'timestamp', 1 );
		$datetime1             = new DateTime( date( 'Y-m-d H:i:s', $record_date_timestamp ) );//start time
		$datetime2             = new DateTime( date( 'Y-m-d H:i:s', $current_timestamp ) );//end time
		$interval              = $datetime1->diff( $datetime2 );
		$days_difference       = intval( $interval->format( '%a' ) );
		$hours_difference      = intval( $interval->format( '%h' ) );
		$minutes_difference    = intval( $interval->format( '%i' ) );

		foreach ( $actions as $action_index => $action_details ) {
			$delay_type = $action_details['time']['delay_type'];

			if ( 'fixed' === $delay_type && isset( $action_details['time']['fixed_date'] ) && ! empty( $action_details['time']['fixed_date'] ) ) {
				$fixed_date            = $action_details['time']['fixed_date'];
				$fixed_date_timestamp  = strtotime( $fixed_date );
				$fixed_time            = $action_details['time']['fixed_time'];
				$fixed_time_seconds    = BWFAN_Common::get_seconds_from_time_format( $fixed_time );
				$task_actual_timestamp = intval( $fixed_date_timestamp ) + intval( $fixed_time_seconds );

				if ( $task_actual_timestamp < $current_timestamp ) {
					$actions[ $action_index ]['time']['delay_type'] = 'immediately';
				}
			}

			if ( 'after_delay' === $delay_type ) {
				$time_type              = $action_details['time']['time_type'];
				$time_number            = intval( $action_details['time']['time_number'] );
				$new_time_number        = $time_number;
				$time_increament_string = '';

				if ( 'days' === $time_type ) {
					if ( $time_number > $days_difference ) {
						$new_time_number = $time_number - $days_difference;
					}

					$time_increament_string = '+' . $new_time_number . ' days';
				} elseif ( 'hours' === $time_type ) {
					if ( $time_number > $hours_difference ) {
						$new_time_number = $time_number - $hours_difference;
					}

					$time_increament_string = '+' . $new_time_number . ' hours';
				} elseif ( 'minutes' === $time_type ) {
					if ( $time_number > $minutes_difference ) {
						$new_time_number = $time_number - $minutes_difference;
					}

					$time_increament_string = '+' . $new_time_number . ' minutes';
				}

				$timestamp = strtotime( $time_increament_string, $record_date_timestamp );
				if ( $timestamp > $current_timestamp ) {
					$actions[ $action_index ]['time']['time_number'] = $new_time_number;
				} else {
					$actions[ $action_index ]['time']['delay_type'] = 'immediately';
				}
			}
		}

		return $actions;
	}

	public function get_view( $db_eventmeta_saved_value ) {

	}

	public function get_default_data() {
		//Use in every event
		$source = $this->source_type;

		$data = array(
			'source' => $source,
			'event'  => $this->get_slug(),
		);

		return $data;
	}

	/**
	 * Send the event data to endpoint for processing
	 *
	 * @param $data
	 *
	 * @return array|void|WP_Error
	 */
	public function send_async_call( $data ) {
		$should_fire_call = ( $this->get_current_event_automations() || $this->get_current_goal_automations() );
		/** In case of Form Submission, Proceed the send_async_call, to trigger the CRM's Form feed */
		$form_submit_events = BWFAN_Common::get_form_submit_events();
		$is_form_submission = is_array( $form_submit_events ) && in_array( get_class( $this ), $form_submit_events );

		if ( false === $should_fire_call && false === $is_form_submission ) {
			BWFAN_Core()->logger->log( 'No automations found for event ' . $this->get_slug(), $this->log_type ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions

			return;
		}

		if ( true === $is_form_submission ) {
			$data['is_form_submission'] = 1;
		}

		$data['unique_key'] = get_option( 'bwfan_u_key', false );

		$url  = rest_url( '/autonami/v1/events' );
		$data = apply_filters( 'bwfan_send_async_call_data', $data );

		try {
			$a_e_id = BWFAN_Model_Automation_Events::insert_data( $data );
		} catch ( Error $e ) {
			BWFAN_Common::log_test_data( 'Automation Event Insert Row Error: ' . $e->getMessage(), 'db-creation-errors', true );
			$table_instance = new BWFAN_DB_Table_Automation_Events();
			$table_instance->create_table();

			$a_e_id = BWFAN_Model_Automation_Events::insert_data( $data );
		}

		if ( ! empty( $a_e_id ) && intval( $a_e_id ) > 0 ) {
			$data['a_e_id'] = $a_e_id;
		}

		$args = bwf_get_remote_rest_args( $data );

		BWFAN_Common::event_advanced_logs( 'Sending data for event: ' . $this->get_slug() );
		BWFAN_Common::event_advanced_logs( 'URL: ' . $url );
		BWFAN_Common::event_advanced_logs( $args );

		if ( 1 === BWFAN_Common::$stop_async_call && false === $this->is_force_asyc() ) {
			return;
		}
		$flag_saved_val = get_transient( 'bwfan_stop_async_call' );
		if ( 1 === intval( $flag_saved_val ) && false === $this->is_force_asyc() ) {
			return;
		}

		$start_time = microtime( true );

		$response = wp_remote_post( $url, $args );

		$end_time = microtime( true );

		if ( ( $end_time - $start_time ) > 0.2 ) {
			/** Curl took minimum 0.2 secs */
			set_transient( 'bwfan_stop_async_call', 1, WEEK_IN_SECONDS );

			BWFAN_Common::$stop_async_call = 1;
		}

		BWFAN_Common::event_advanced_logs( 'Event endpoint response' );
		if ( is_wp_error( $response ) ) {
			BWFAN_Common::event_advanced_logs( $response->get_error_message() );
		} elseif ( isset( $response['body'] ) ) {
			BWFAN_Common::event_advanced_logs( $response['body'] );
			BWFAN_Common::event_advanced_logs( $response['response'] );
		}

		return $response;
	}

	/**
	 * Check if any active automation for current event is present
	 *
	 * @return array|bool
	 */
	public function get_current_event_automations() {
		BWFAN_Core()->public->load_active_automations( $this->get_slug() );
		BWFAN_Core()->public->load_active_v2_automations( $this->get_slug() );

		if ( ( ! is_array( $this->automations_arr ) || count( $this->automations_arr ) === 0 ) && ( ! is_array( $this->automations_v2_arr ) || count( $this->automations_v2_arr ) === 0 ) ) {
			return false;
		}

		return true;
	}

	/**
	 * Get all active automations by the goal
	 *
	 * @param bool $fetch_goal_ids
	 *
	 * @return array|false
	 */
	public function get_current_goal_automations( $fetch_goal_ids = false ) {
		if ( ! $this->is_goal() ) {
			return false;
		}

		$goal_automations = BWFAN_Model_Automations_V2::get_goal_automations( $this->get_slug() );
		if ( empty( $goal_automations ) ) {
			return false;
		}

		if ( false === $fetch_goal_ids ) {
			return $goal_automations;
		}

		$a_ids = $all_goal_ids = [];
		foreach ( $goal_automations as $automation ) {
			$automation_id = $automation['ID'] ?? 0;
			$benchmark     = ! empty( $automation['benchmark'] ) && is_string( $automation['benchmark'] ) ? json_decode( $automation['benchmark'], true ) : [];
			if ( empty( $automation_id ) || empty( $benchmark ) ) {
				continue;
			}
			$goal_ids = [];
			foreach ( $benchmark as $step_id => $slug ) {
				if ( $this->get_slug() !== $slug ) {
					continue;
				}
				$goal_ids[]     = $step_id;
				$all_goal_ids[] = $step_id;
			}
			$a_ids[ $automation_id ] = $goal_ids;
		}

		return [
			'a_ids'    => $a_ids,
			'goal_ids' => $all_goal_ids,
		];
	}

	public function get_contact_id_for_goal( $capture_args ) {
		if ( isset( $capture_args['contact_id'] ) && absint( $capture_args['contact_id'] ) > 0 ) {
			return absint( $capture_args['contact_id'] );
		}

		return 0;
	}

	public function get_task_view( $global_data ) {
		return '';
	}

	/**
	 * Set global data for all the merge tags which are supported by this event.
	 *
	 * @param $task_meta
	 */
	public function set_merge_tags_data( $task_meta ) {
		$wc_order_id = BWFAN_Merge_Tag_Loader::get_data( 'wc_order_id' );
		if ( empty( $wc_order_id ) || $wc_order_id !== $task_meta['global']['order_id'] ) {
			$set_data = array(
				'wc_order_id' => $task_meta['global']['order_id'],
				'email'       => $task_meta['global']['email'],
				'wc_order'    => wc_get_order( $task_meta['global']['order_id'] ),
			);
			BWFAN_Merge_Tag_Loader::set_data( $set_data );
		}
	}

	public function get_source() {
		return $this->source_type;
	}

	public function get_optgroup_label() {
		return $this->optgroup_label;
	}

	public function get_name() {
		return $this->event_name;
	}

	public function get_desc() {
		return $this->event_desc;
	}

	public function get_priority() {
		return $this->priority;
	}

	public function get_included_actions() {
		return $this->included_actions;
	}

	public function get_excluded_actions() {
		return $this->excluded_actions;
	}

	public function set_event_saved_data( $data ) {
		$this->event_saved_data = $data;
	}

	public function is_time_independent() {
		return $this->is_time_independent;
	}

	/**
	 * Return localize data of event for frontend UI
	 * @return array
	 */
	public function get_localize_data() {
		$this->localize_data = [
			'source_type'         => $this->source_type,
			'source_type_label'   => $this->optgroup_label,
			'event_name'          => $this->event_name,
			'event_desc'          => $this->event_desc,
			'slug'                => $this->get_slug(),
			'is_time_independent' => $this->is_time_independent,
			'included_actions'    => $this->included_actions,
			'excluded_actions'    => $this->excluded_actions,
			'event_saved_data'    => $this->event_saved_data,
			'support_lang'        => $this->support_lang,
			'support_v1'          => $this->support_v1,
			'customer_email_tag'  => $this->customer_email_tag,
			'available'           => 'yes',
			'need_unique_key'     => $this->need_unique_key,
			'supported_blocks'    => $this->supported_blocks,
		];

		return apply_filters( 'bwfan_event_' . $this->get_slug() . '_localize_data', $this->localize_data, $this );
	}

	/**
	 * Returns event data
	 *
	 * @param string $selected_event
	 *
	 * @return mixed
	 */
	public function get_event_data_for_api( $selected_event = '' ) {
		if ( ! $this->is_v2() ) {
			return [];
		}
		$data = $this->localize_data;

		$default_event_field = [
			[
				'id'       => 'bwfan_automation_run',
				'type'     => 'radio',
				'label'    => __( 'Runs On Contact', 'wp-marketing-automations' ),
				'options'  => [
					[
						'label' => __( 'Once', 'wp-marketing-automations' ),
						'value' => 'once'
					],
					[
						'label' => __( 'Multiple Times', 'wp-marketing-automations' ),
						'value' => 'multiple'
					]
				],
				'tip'      => "",
				"required" => false,
			],
			[
				'id'        => 'enter_automation_on_active_contact',
				'label'     => __( "Allow currently active contacts in this automation to re-enter again", 'wp-marketing-automations' ),
				'className' => 'bwf-tooglecontrol-advance',
				'type'      => 'toggle',
				'toggler'   => [
					'fields'   => [
						[
							'id'    => 'bwfan_automation_run',
							'value' => 'multiple',
						]
					],
					'relation' => 'OR',
				],
			]
		];

		$default_run_value = [
			'bwfan_automation_run' => 'once'
		];

		$is_selected_event = $selected_event === $this->get_slug();

		$fields         = $is_selected_event && method_exists( $this, 'get_fields_schema' ) ? $this->get_fields_schema() : [];
		$default_values = $is_selected_event && method_exists( $this, 'get_default_values' ) ? $this->get_default_values() : [];

		$data['fields']         = ! $is_selected_event || $this->disable_default_fields ? $fields : array_merge( $fields, $default_event_field );
		$data['default_values'] = ! $is_selected_event || $this->disable_default_fields ? $default_values : array_merge( $default_values, $default_run_value );

		return $data;
	}

	public function is_v2() {
		return $this->v2;
	}

	public function get_fields_schema() {
		return array();
	}

	public function is_support_v1() {
		return $this->support_v1;
	}

	/**
	 * Get Goal schema data
	 *
	 * @return array
	 */
	public function get_goal_data_for_api() {
		if ( ! $this->is_v2() ) {
			return [];
		}
		$data = $this->localize_data;

		$default_goal_field = [
			[
				'id'       => 'bwfan_goal_run',
				'type'     => 'radio',
				'label'    => __( 'If the contact doesn\'t meet the specified goal', 'wp-marketing-automations' ),
				'options'  => [
					[
						'label' => __( 'Wait until the goal is met', 'wp-marketing-automations' ),
						'value' => 'wait'
					],
					[
						'label' => __( 'Continue anyway', 'wp-marketing-automations' ),
						'value' => 'continue'
					],
					[
						'label' => __( 'End this automation', 'wp-marketing-automations' ),
						'value' => 'end'
					]
				],
				'tip'      => "",
				"required" => false,
			]
		];

		$default_run_value = [
			'bwfan_goal_run' => 'wait'
		];
		$schema            = $this->get_goal_fields_schema();
		$schema            = empty( $schema ) ? $this->get_fields_schema() : $schema;

		$default_values = method_exists( $this, 'get_default_goal_values' ) ? $this->get_default_goal_values() : [];

		$data['fields']         = array_merge( $schema, $default_goal_field );
		$data['default_values'] = array_merge( $default_values, $default_run_value );

		return $data;
	}

	public function get_goal_fields_schema() {
		return array();
	}

	public function get_default_goal_values() {
		return array();
	}

	/**
	 * Return Available event rule group
	 * @return array
	 */
	public function get_rule_group() {
		$rule_groups = $this->event_rule_groups;
		$default_groups = [ 'bwf_automation', 'languages', 'bwf_date_time', 'bwf_pushengage' ];
		$default_rule_groups = apply_filters( 'bwfan_default_rule_groups', $default_groups );
		$default_rule_groups = is_array( $default_rule_groups ) && ! empty( $default_rule_groups ) ? $default_rule_groups : $default_groups;

		$rule_groups = array_merge( $rule_groups, $default_rule_groups );
		$rule_groups = array_values( array_unique( $rule_groups ) );

		return apply_filters( 'bwfan_event_' . $this->get_slug() . '_rules_group', $rule_groups, $this );
	}

	/**
	 * Return Available event Merge tag group
	 * @return array
	 */
	public function get_merge_tag_groups() {
		if ( true === $this->support_lang ) {
			$this->event_merge_tag_groups[] = 'language';
		}

		$this->event_merge_tag_groups[] = 'bwfan_default';
		/** Added Advanced Coupon merge tags group  */
		if ( function_exists( 'bwfan_is_advanced_coupon_for_woocommerce_active' ) && bwfan_is_advanced_coupon_for_woocommerce_active() && defined( 'BWFAN_PRO_VERSION' ) && version_compare( BWFAN_PRO_VERSION, '3.5.3', '>=' ) ) {
			$this->event_merge_tag_groups[] = 'bwfan_adv_coupon';
		}

		return apply_filters( 'bwfan_event_' . $this->get_slug() . '_merge_tag_group', $this->event_merge_tag_groups, $this );
	}

	/**
	 * Return user selected actions against this event
	 * @return null
	 */
	public function get_user_selected_actions() {
		return $this->user_selected_actions;
	}

	public function set_automations_data( $data, $v = 1 ) {
		if ( empty( $data ) ) {
			return;
		}
		if ( 2 === $v ) {
			$this->automations_v2_arr = $data;

			return;
		}
		$this->automations_arr = $data;
	}

	public function make_task_data( $automation_id, $automation_data ) {

	}

	public function set_source_type( $type ) {
		$this->source_type = $type;
	}

	/** v2 Methods: START */

	public function capture_async_data() {
		throw new ErrorException( 'This function `' . __FUNCTION__ . '` Must be override in child class' );
	}

	/**
	 * Validate single v2 automation if passed to run
	 *
	 * @param $automation_data
	 *
	 * @return bool
	 */
	public function validate_v2_event_settings( $automation_data ) {
		return true;
	}

	/**
	 * Validate v2 automation before start
	 *
	 * @param $automation_contact_row
	 *
	 * @return bool
	 */
	public function validate_v2_before_start( $automation_contact_row ) {
		return true;
	}

	/**
	 * Validate automation goal settings
	 *
	 * @param $automation_data
	 *
	 * @return bool
	 */
	public function validate_goal_settings( $automation_settings, $automation_data ) {
		return false;
	}

	/**
	 * Validate automation goal settings
	 *
	 * @param $entity
	 * @param $automation_data
	 * @param $version
	 *
	 * @return bool
	 */
	public function validate_bulk_action_event_settings( $entity, $automation_data, $version ) {
		return true;
	}

	/**
	 * Run v2 automation for a contact
	 * Validate and save in the automation contact table
	 *
	 * @param $automation_id
	 * @param $automation_data
	 *
	 * @return false|int
	 * @throws Exception
	 */
	public function handle_automation_run_v2( $automation_id, $automation_data ) {
		/** If no start node found */
		if ( ! isset( $automation_data['start'] ) || 0 === intval( $automation_data['start'] ) ) {
			return false;
		}

		/** Global data */
		$global_data = $this->global_data;
		$global_data = ! is_array( $global_data ) ? [] : $global_data;
		$global_data = BWFAN_Common::get_global_data( $global_data );

		/** Event data */
		$event_data = $this->event_data;
		$event_data = ! is_array( $event_data ) ? [] : $event_data;

		$global_data['event_data'] = $event_data;

		/** If no contact ID found, log and return */
		if ( ! isset( $global_data['global'] ) || ! isset( $global_data['global']['cid'] ) || 0 === intval( $global_data['global']['cid'] ) ) {
			BWFAN_Common::log_test_data( 'No cid found for Automation ID - ' . $automation_id . '. Event - ' . $this->get_slug(), 'no-contact-id', true );
			BWFAN_Common::log_test_data( $global_data, 'no-contact-id', true );

			return false;
		}

		/** If contact is active in automation */
		$exclude_check = false;
		if ( isset( $automation_data['event_meta'] ) && isset( $automation_data['event_meta']['enter_automation_on_active_contact'] ) && 1 === absint( $automation_data['event_meta']['enter_automation_on_active_contact'] ) ) {
			$exclude_check = true;
		}

		if ( false === $exclude_check && BWFAN_Model_Automation_Contact::maybe_contact_in_automation( $global_data['global']['cid'], $automation_id ) ) {
			BWFAN_Common::log_test_data( 'Contact ' . $global_data['global']['cid'] . ' is active in the automation - ' . $automation_id . '. Event - ' . $this->get_slug(), 'contact-exist-automation', true );

			return false;
		}

		/** Validate automation common settings like run count */
		if ( false === BWFAN_Model_Automations_V2::validation_automation_run_count( $automation_id, $global_data['global']['cid'], $automation_data, $exclude_check ) ) {
			BWFAN_Common::log_test_data( 'Automation ID ' . $automation_id . ' already run on a contact ' . $global_data['global']['cid'] . '. Event - ' . $this->get_slug(), 'contact-exist-automation', true );

			return false;
		}

		/** set automation id in event global data */
		$global_data['global']['automation_id'] = $automation_id;
		$contact_id                             = intval( $global_data['global']['cid'] );

		$data = [
			'cid'       => $contact_id,
			'aid'       => $automation_id,
			'event'     => $this->get_slug(),
			'c_date'    => current_time( 'mysql', 1 ),
			'e_time'    => current_time( 'timestamp', 1 ),
			'last_time' => current_time( 'timestamp', 1 ),
			'data'      => json_encode( $global_data )
		];

		/** In case of duplicate run, when hook runs twice. */
		$already_exists = BWFAN_Model_Automation_Contact::check_duplicate_automation_contact( $data );
		if ( $already_exists ) {
			BWFAN_Common::log_test_data( 'Automation ID ' . $data['aid'] . ' already exists with same data for contact ' . $data['cid'] . '. Event - ' . $data['event'], 'contact-duplicate-automation', true );
			BWFAN_Common::log_test_data( $global_data, 'contact-duplicate-automation', true );

			return false;
		}

		$run_immediately = apply_filters( 'bwfan_run_v2_automation_immediately', true, $automation_id, $data );
		if ( true === $run_immediately ) {
			$data['e_time'] = $data['e_time'] + 5;
		}

		BWFAN_Model_Automation_Contact::insert( $data );
		$p_key = BWFAN_Model_Automation_Contact::insert_id();

		BWFAN_Common::event_advanced_logs( 'Automation started on contact ID: ' . $contact_id );

		$this->update_automation_contact_field( $contact_id, $automation_id );

		/** Check if automation needs to run immediately */
		if ( true === $run_immediately ) {
			$ins = BWFAN_Automation_V2_Contact::get_instance();
			$ins->bwfan_ac_execute_action( $p_key );
		}

		return $p_key;
	}

	public function update_automation_contact_field( $contact_id, $automation_id ) {
		if ( ! class_exists( 'BWFCRM_Contact' ) ) {
			return;
		}

		/** CRM contact object */
		$contact = new BWFCRM_Contact( $contact_id );

		if ( ! $contact->is_contact_exists() ) {
			return;
		}

		/** Get Automation ids from automation active field */
		$active_automations = $contact->get_field_by_slug( 'automation-active' );
		$active_aids        = json_decode( $active_automations, true );
		$active_aids        = ( ! empty( $active_aids ) && is_array( $active_aids ) ) ? $active_aids : array();

		$active_aids[] = (string) $automation_id;
		$active_aids   = array_unique( $active_aids );
		sort( $active_aids );
		$active_aids = wp_json_encode( $active_aids );

		/** Get automation ids from automation entered field */
		$entered_automations = $contact->get_field_by_slug( 'automation-entered' );
		$entered_aids        = json_decode( $entered_automations, true );
		$entered_aids        = ( ! empty( $entered_aids ) && is_array( $entered_aids ) ) ? $entered_aids : array();

		$entered_aids[] = (string) $automation_id;
		$entered_aids   = array_unique( $entered_aids );
		sort( $entered_aids );
		$entered_aids = wp_json_encode( $entered_aids );

		/** Set updated automation active and automation entered value */
		$contact->set_field_by_slug( 'automation-active', $active_aids );
		$contact->set_field_by_slug( 'automation-entered', $entered_aids );
		$contact->save_fields();
	}

	public function capture_v2_data( $automation_data ) {
		return $automation_data;
	}

	/**
	 * to avoid unserialize of the current class
	 */
	public function __wakeup() {
		throw new ErrorException( 'BWFAN_Core can`t converted to string' );
	}

	/**
	 * to avoid serialize of the current class
	 */
	public function __sleep() {
		throw new ErrorException( 'BWFAN_Core can`t converted to string' );
	}

	/** v2 Methods: END */

	/**
	 * Returns optgroup priority
	 */
	public function get_optgroup_priority() {
		return $this->optgroup_priority;
	}

	protected function validate_order( $data, $event_data = [] ) {
		if ( ! isset( $data['order_id'] ) ) {
			return false;
		}

		$order = wc_get_order( $data['order_id'] );
		if ( ! $order instanceof WC_Order ) {
			return false;
		}

		/** If event data is empty, return true */
		if ( empty( $event_data ) ) {
			return true;
		}

		/** Check if order status checking enabled with order validation */
		$is_check_status = apply_filters( 'bwfan_check_order_status_with_order_validation', false, $data );
		if ( false === $is_check_status ) {
			return true;
		}

		$order_status              = 'wc-' . $order->get_status();
		$order_automation_statuses = isset( $event_data['order_status'] ) ? $event_data['order_status'] : [];

		/** check order status with automation setting */
		return in_array( $order_status, $order_automation_statuses, true );
	}

	protected function validate_subscription( $data ) {
		if ( ! isset( $data['wc_subscription_id'] ) || ! function_exists( 'wcs_get_subscription' ) ) {
			return false;
		}

		$subscription = wcs_get_subscription( $data['wc_subscription_id'] );
		if ( $subscription instanceof WC_Subscription ) {
			return true;
		}

		return false;
	}

	public function is_db_normalize() {
		return false;
	}

	public function is_contact_add_to_automation_allowed() {
		return $this->automation_add;
	}

	/**
	 * need to extend by child class
	 *
	 * @param $cid
	 *
	 * @return array
	 */
	public function get_manually_added_contact_automation_data( $automation_data, $cid ) {
		return array_merge( $automation_data, [ 'cid' => $cid ] );
	}

	protected function is_force_asyc() {
		return apply_filters( 'bwfan_force_async', $this->force_async );
	}

	/**
	 * To avoid cloning of current class
	 */
	protected function __clone() {
	}

	/**
	 * Get supported blocks
	 *
	 * @return bool|mixed
	 */
	public function get_supported_blocks() {
		return $this->supported_blocks;
	}
}
