<?php
if ( ! defined( 'ABSPATH' ) ) {
	die( 'You are not allowed to call this page directly.' );
}

class FrmFormAction {

	/**
	 * Root id for all actions of this type.
	 *
	 * @var string
	 */
	public $id_base;

	/**
	 * Name for this action type.
	 *
	 * @var string
	 */
	public $name;

	/**
	 * Name of the option used to store the settings for this action type.
	 *
	 * @var string
	 */
	public $option_name;

	/**
	 * Option array passed to wp_register_sidebar_widget().
	 *
	 * @var array
	 */
	public $action_options;

	/**
	 * Option array passed to wp_register_widget_control().
	 *
	 * @var array
	 */
	public $control_options;

	/**
	 * The ID of the form to evaluate.
	 *
	 * @var int
	 */
	public $form_id;

	/**
	 * Unique ID number of the current instance.
	 *
	 * @var int
	 */
	public $number = false;

	/**
	 * Unique ID string of the current instance (id_base-number).
	 *
	 * @var string
	 */
	public $id = '';

	/**
	 * Set true when we update the data after a POST submit - makes sure we don't do it twice.
	 *
	 * @var bool
	 */
	public $updated = false;

	// Member functions that you must over-ride.

	/**
	 * This function should check that $new_instance is set correctly.
	 * The newly calculated value of $instance should be returned.
	 * If "false" is returned, the instance won't be saved/updated.
	 *
	 * @param array $new_instance New settings for this instance as input by the user via form().
	 * @param array $old_instance Old settings for this instance.
	 *
	 * @return array Settings to save or bool false to cancel saving
	 */
	public function update( $new_instance, $old_instance ) {
		return $new_instance;
	}

	/**
	 * Echo the settings update form
	 *
	 * @param WP_Post $instance Current settings.
	 * @param array   $args
	 *
	 * @return string
	 */
	public function form( $instance, $args = array() ) {
		echo '<p class="no-options-widget">' . esc_html__( 'There are no options for this action.', 'formidable' ) . '</p>';
		return 'noform';
	}

	/**
	 * @return array of the default options
	 */
	public function get_defaults() {
		return array();
	}

	/**
	 * @return array
	 */
	public function get_switch_fields() {
		return array();
	}

	/**
	 * @param object $action
	 * @param object $form
	 *
	 * @return object
	 */
	public function migrate_values( $action, $form ) {
		return $action;
	}

	// Functions you'll need to call.

	/**
	 * PHP5 constructor
	 *
	 * @param string $id_base Optional Base ID for the widget, lower case,
	 * if left empty a portion of the widget's class name will be used. Has to be unique.
	 * @param string $name Name for the widget displayed on the configuration page.
	 * @param array  $action_options Optional Passed to wp_register_sidebar_widget().
	 *    - description: shown on the configuration page.
	 *    - classname.
	 * @param array  $control_options Optional Passed to wp_register_widget_control().
	 *    - width: required if more than 250px.
	 *    - height: currently not used but may be needed in the future.
	 */
	public function __construct( $id_base, $name, $action_options = array(), $control_options = array() ) {
		if ( ! defined( 'ABSPATH' ) ) {
			die( 'You are not allowed to call this page directly.' );
		}

		$this->id_base = strtolower( $id_base );

		/**
		 * @since 6.31
		 *
		 * @param string $name
		 */
		$name = apply_filters( 'frm_' . $id_base . '_action_name', $name );

		$this->name        = $name;
		$this->option_name = 'frm_' . $this->id_base . '_action';

		$default_options = array(
			'classes'     => '',
			'active'      => true,
			'event'       => array( 'create' ),
			'limit'       => 1,
			'force_event' => false,
			'priority'    => 20,
			'ajax_load'   => true,
			'plugin'      => $this->id_base,
			'tooltip'     => $name,
			'group'       => $id_base,
			'color'       => '',
			'keywords'    => '',
			'description' => '',
			'is_new'      => false,
			'is_beta'     => false,
		);

		$action_options          = apply_filters( 'frm_' . $id_base . '_action_options', $action_options );
		$group                   = $this->get_group( $action_options );
		$action_options['group'] = $group['id'];

		if ( ! isset( $action_options['color'] ) ) {
			// Deterministic fallback so all instances of the same action type render with the same color across requests.
			$colors                  = array( 'green', 'orange', 'purple' );
			$index                   = abs( crc32( $id_base ) ) % count( $colors );
			$action_options['color'] = 'var(--' . $colors[ $index ] . ')';
		}

		$upgrade_class = isset( $action_options['classes'] ) && $action_options['classes'] === 'frm_show_upgrade';

		if ( $action_options['group'] === $id_base ) {
			$upgrade_class             = str_contains( $action_options['classes'], 'frm_show_upgrade' );
			$action_options['classes'] = $group['icon'];
		} elseif ( empty( $action_options['classes'] ) || $upgrade_class ) {
			$action_options['classes'] = $group['icon'];
		}

		if ( $upgrade_class ) {
			$action_options['classes'] .= ' frm_show_upgrade';
		}

		$this->action_options  = wp_parse_args( $action_options, $default_options );
		$this->control_options = wp_parse_args( $control_options, array( 'id_base' => $this->id_base ) );
	}

	/**
	 * @param string $id_base
	 * @param string $name
	 * @param array  $action_options
	 * @param array  $control_options
	 *
	 * @return void
	 */
	public function FrmFormAction( $id_base, $name, $action_options = array(), $control_options = array() ) {
		self::__construct( $id_base, $name, $action_options, $control_options );
	}

	/**
	 * Help to switch old field id by new field id for duplicate form
	 *
	 * @param string $action id of the field that needs to be switched.
	 *
	 * @return string
	 */
	public function maybe_switch_field_ids( $action ) {
		$updated_action = apply_filters( 'frm_maybe_switch_field_ids', $action );

		if ( $updated_action === $action ) {
			return FrmFieldsHelper::switch_field_ids( $action );
		}

		return $updated_action;
	}

	/**
	 * @since 4.0
	 *
	 * @param array $action_options
	 *
	 * @return array
	 */
	protected function get_group( $action_options ) {
		$groups = FrmFormActionsController::form_action_groups();
		$group  = 'misc';

		if ( isset( $action_options['group'] ) && isset( $groups[ $action_options['group'] ] ) ) {
			$group = $action_options['group'];
		} elseif ( isset( $groups[ $this->id_base ] ) ) {
			$group = $this->id_base;
		} else {
			foreach ( $groups as $name => $check_group ) {
				if ( isset( $check_group['actions'] ) && in_array( $this->id_base, $check_group['actions'], true ) ) {
					$group = $name;
					break;
				}
			}
		}

		$groups[ $group ]['id'] = $group;
		return $groups[ $group ];
	}

	/**
	 * Constructs name attributes for use in form() fields
	 *
	 * This function should be used in form() methods to create name attributes for fields to be saved by update()
	 *
	 * @param string $field_name Field name.
	 * @param string $post_field
	 *
	 * @return string Name attribute for $field_name
	 */
	public function get_field_name( $field_name, $post_field = 'post_content' ) {
		$name  = $this->option_name . '[' . $this->number . ']';
		$name .= $post_field ? '[' . $post_field . ']' : '';

		return $name . ( '[' . $field_name . ']' );
	}

	/**
	 * Constructs id attributes for use in form() fields
	 *
	 * This function should be used in form() methods to create id attributes for fields to be saved by update()
	 *
	 * @param string $field_name Field name.
	 *
	 * @return string ID attribute for $field_name
	 */
	public function get_field_id( $field_name ) {
		return $field_name . '_' . $this->number;
	}

	/**
	 * @param int|string $number
	 *
	 * @return void
	 */
	public function _set( $number ) {
		$this->number = $number;
		$this->id     = $this->id_base . '-' . $number;
	}

	/**
	 * @param false|int|string $form_id
	 *
	 * @return object
	 */
	public function prepare_new( $form_id = false ) {
		if ( $form_id ) {
			$this->form_id = $form_id;
		}

		$post_content   = array();
		$default_values = $this->get_global_defaults();

		// Fill default values
		$post_content = wp_parse_args( $post_content, $default_values );

		if ( ! isset( $post_content['event'] ) && ! $this->action_options['force_event'] ) {
			$post_content['event'] = array( reset( $this->action_options['event'] ) );
		}

		$form_action = array(
			'post_title'   => $this->name,
			'post_content' => $post_content,
			'post_excerpt' => $this->id_base,
			'ID'           => '',
			'post_status'  => 'publish',
			'post_type'    => FrmFormActionsController::$action_post_type,
			'post_name'    => $this->form_id . '_' . $this->id_base . '_' . $this->number,
			'menu_order'   => $this->form_id,
		);

		return (object) $form_action;
	}

	/**
	 * @param int|string $form_id
	 *
	 * @return int|WP_Error
	 */
	public function create( $form_id ) {
		$this->form_id = $form_id;

		$action = $this->prepare_new();

		return $this->save_settings( $action );
	}

	/**
	 * @param int|string $form_id
	 * @param int|string $old_id
	 *
	 * @return void
	 */
	public function duplicate_form_actions( $form_id, $old_id ) {
		// phpcs:ignore Universal.Operators.StrictComparisons
		if ( $form_id == $old_id ) {
			// Don't duplicate the actions if this is a template getting updated
			return;
		}

		$this->form_id = $old_id;
		$actions       = $this->get_all( $old_id );

		$this->form_id = $form_id;

		foreach ( $actions as $action ) {
			$this->duplicate_one( $action, $form_id );
			unset( $action );
		}
	}

	/**
	 * Check if imported action should be created or updated.
	 *
	 * @since 2.0
	 *
	 * @param array $action
	 * @param array $forms
	 *
	 * @return int Post ID.
	 */
	public function maybe_create_action( $action, $forms ) {
		if ( isset( $action['ID'] ) && is_numeric( $action['ID'] ) && isset( $forms[ $action['menu_order'] ] ) && $forms[ $action['menu_order'] ] === 'updated' ) {
			// Update action only
			$action['post_content'] = FrmAppHelper::maybe_json_decode( $action['post_content'] );
			return $this->save_settings( $action );
		}
		// Create action
		$action['post_content'] = FrmAppHelper::maybe_json_decode( $action['post_content'] );
		return $this->duplicate_one( (object) $action, $action['menu_order'] );
	}

	/**
	 * @param object     $action
	 * @param int|string $form_id
	 *
	 * @return int|WP_Error
	 */
	public function duplicate_one( $action, $form_id ) {
		global $frm_duplicate_ids;

		$action->menu_order = $form_id;
		$switch             = $this->get_global_switch_fields();

		foreach ( (array) $action->post_content as $key => $val ) {
			if ( is_numeric( $val ) && isset( $frm_duplicate_ids[ $val ] ) ) {
				$action->post_content[ $key ] = $frm_duplicate_ids[ $val ];
			} elseif ( ! is_array( $val ) ) {
				$action->post_content[ $key ] = FrmFieldsHelper::switch_field_ids( $val );
			} elseif ( isset( $switch[ $key ] ) && is_array( $switch[ $key ] ) ) {
				// Loop through each value if empty
				if ( empty( $switch[ $key ] ) ) {
					$switch[ $key ] = array_keys( $val );
				}

				foreach ( $switch[ $key ] as $subkey ) {
					$action->post_content[ $key ] = $this->duplicate_array_walk( $action->post_content[ $key ], $subkey, $val );
				}
			}

			unset( $key, $val );
		}
		unset( $action->ID );

		return $this->save_settings( $action );
	}

	/**
	 * @param array        $action
	 * @param array|string $subkey
	 * @param mixed        $val
	 *
	 * @return array
	 */
	private function duplicate_array_walk( $action, $subkey, $val ) {
		global $frm_duplicate_ids;

		if ( is_array( $subkey ) ) {
			foreach ( $subkey as $subkey2 ) {
				foreach ( (array) $val as $ck => $cv ) {
					if ( is_array( $cv ) ) {
						$action[ $ck ] = $this->duplicate_array_walk( $action[ $ck ], $subkey2, $cv );
					} elseif ( isset( $cv[ $subkey ] ) && is_numeric( $cv[ $subkey ] ) && isset( $frm_duplicate_ids[ $cv[ $subkey ] ] ) ) {
						$action[ $ck ][ $subkey ] = $frm_duplicate_ids[ $cv[ $subkey ] ];
					}
				}
			}
		} else {
			foreach ( (array) $val as $ck => $cv ) {
				if ( is_array( $cv ) ) {
					$action[ $ck ] = $this->duplicate_array_walk( $action[ $ck ], $subkey, $cv );
				} elseif ( $ck == $subkey && isset( $frm_duplicate_ids[ $cv ] ) ) { // phpcs:ignore Universal.Operators.StrictComparisons
					$action[ $ck ] = $frm_duplicate_ids[ $cv ];
				} elseif ( $ck == $subkey ) { // phpcs:ignore Universal.Operators.StrictComparisons
					$action[ $ck ] = $this->maybe_switch_field_ids( $action[ $ck ] );
				}
			}
		}//end if

		return $action;
	}

	/**
	 * Deal with changed settings.
	 *
	 * Do NOT over-ride this function
	 *
	 * @param int|string $form_id
	 *
	 * @return array|null
	 */
	public function update_callback( $form_id ) {
		$this->form_id = $form_id;

		$all_instances = $this->get_settings();

		// We need to update the data
		if ( $this->updated ) {
			return null;
		}

		// phpcs:ignore WordPress.Security.NonceVerification.Missing
		if ( ! isset( $_POST[ $this->option_name ] ) || ! is_array( $_POST[ $this->option_name ] ) ) {
			return null;
		}

		// Sanitizing removes scripts and <email> type of values.
		// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification.Missing
		$settings = wp_unslash( $_POST[ $this->option_name ] );

		$action_ids = array();

		foreach ( $settings as $number => $new_instance ) {
			$this->_set( $number );

			$old_instance = $all_instances[ $number ] ?? array();

			if ( ! isset( $new_instance['post_status'] ) ) {
				$new_instance['post_status'] = 'draft';
			}

			// Settings were never opened, so don't update
			if ( ! isset( $new_instance['post_title'] ) ) {
				$this->maybe_update_status( $new_instance, $old_instance );
				$action_ids[]  = $new_instance['ID'];
				$this->updated = true;
				continue;
			}

			$new_instance['post_type']  = FrmFormActionsController::$action_post_type;
			$new_instance['post_name']  = $this->form_id . '_' . $this->id_base . '_' . $this->number;
			$new_instance['menu_order'] = $this->form_id;
			$new_instance['post_date']  = $old_instance->post_date ?? '';
			$instance                   = $this->update( $new_instance, $old_instance );

			/**
			 * Filter an action's settings before saving.
			 *
			 * Returning false will effectively short-circuit the widget's ability
			 * to update settings.
			 *
			 * @since 2.0
			 *
			 * @param array         $instance The current widget instance's settings.
			 * @param array         $new_instance Array of new widget settings.
			 * @param array         $old_instance Array of old widget settings.
			 * @param FrmFormAction $form_action FrmFormAction instance.
			 */
			$instance = apply_filters( 'frm_action_update_callback', $instance, $new_instance, $old_instance, $this );

			$instance['post_content'] = apply_filters( 'frm_before_save_action', $instance['post_content'], $instance, $new_instance, $old_instance, $this );
			$instance['post_content'] = apply_filters( 'frm_before_save_' . $this->id_base . '_action', $instance['post_content'], $instance, $new_instance, $old_instance, $this );

			if ( false !== $instance ) {
				$all_instances[ $number ] = $instance;
			}

			$action_ids[] = $this->save_settings( $instance );

			$this->updated = true;
		}//end foreach

		return $action_ids;
	}

	/**
	 * If the status of the action has changed, update it
	 *
	 * @since 3.04
	 *
	 * @param array          $new_instance
	 * @param array|stdClass $old_instance
	 *
	 * @return void
	 */
	protected function maybe_update_status( $new_instance, $old_instance ) {
		if ( ! is_object( $old_instance ) || $new_instance['post_status'] === $old_instance->post_status ) {
			return;
		}

		self::clear_cache();
		wp_update_post(
			array(
				'ID'          => $new_instance['ID'],
				'post_status' => $new_instance['post_status'],
			)
		);
	}

	/**
	 * @param array $settings
	 *
	 * @return int|WP_Error
	 */
	public function save_settings( $settings ) {
		self::clear_cache();
		return FrmDb::save_settings( $settings, 'frm_actions' );
	}

	/**
	 * @param int $id
	 *
	 * @return object|null
	 */
	public function get_single_action( $id ) {
		$action = get_post( $id );

		if ( $action ) {
			$action = $this->prepare_action( $action );
			$this->_set( $id );
		}

		return $action;
	}

	/**
	 * @param int|string $form_id
	 *
	 * @return array
	 */
	public function get_one( $form_id ) {
		return $this->get_all( $form_id, 1 );
	}

	/**
	 * @param int|string $form_id
	 * @param string     $type
	 * @param array      $atts
	 *
	 * @return array
	 */
	public static function get_action_for_form( $form_id, $type = 'all', $atts = array() ) {
		$action_controls = FrmFormActionsController::get_form_actions( $type );

		if ( ! $action_controls ) {
			// Don't continue if there are no available actions
			return array();
		}

		if ( 'all' !== $type ) {
			if ( is_array( $action_controls ) ) {
				return array();
			}

			return $action_controls->get_all( $form_id, $atts );
		}

		self::prepare_get_action( $atts );

		$limit               = self::get_action_limit( $form_id, $atts['limit'] );
		$args                = self::action_args( $form_id, $limit );
		$args['post_status'] = $atts['post_status'];
		$actions             = FrmDb::check_cache( json_encode( $args ), 'frm_actions', $args, 'get_posts' );

		if ( ! $actions ) {
			return array();
		}

		$settings = array();

		foreach ( $actions as $action ) {
			// Some plugins/themes are formatting the post_excerpt
			$action->post_excerpt = sanitize_title( $action->post_excerpt );

			if ( ! isset( $action_controls[ $action->post_excerpt ] ) ) {
				continue;
			}

			$action                  = $action_controls[ $action->post_excerpt ]->prepare_action( $action );
			$settings[ $action->ID ] = $action;

			if ( count( $settings ) >= $limit ) {
				break;
			}
		}

		return 1 === $limit ? reset( $settings ) : $settings;
	}

	/**
	 * Get the limit for the number of actions for a single form. By default, this is 99, but
	 * it can be modified with a code snippet.
	 *
	 * @since 6.17 This logic from moved from FrmFormAction::get_action_for_form.
	 *
	 * @param int|string $form_id
	 * @param int|string $limit   The unfiltered limit value.
	 *
	 * @return int The filtered limit value.
	 */
	public static function get_action_limit( $form_id, $limit = 99 ) {
		$type = 'all';
		return (int) apply_filters( 'frm_form_action_limit', (int) $limit, compact( 'type', 'form_id' ) );
	}

	/**
	 * @since 3.04
	 *
	 * @param array|string $args
	 * @param string       $default_status
	 *
	 * @return void
	 */
	protected static function prepare_get_action( &$args, $default_status = 'publish' ) {
		if ( is_numeric( $args ) ) {
			// For reverse compatibility. $limit was changed to $args
			$args = array(
				'limit' => $args,
			);
		}

		$defaults = array(
			'limit'       => 99,
			'post_status' => $default_status,
		);
		$args     = wp_parse_args( $args, $defaults );
	}

	/**
	 * @param int    $action_id
	 * @param string $type
	 *
	 * @return bool|object
	 */
	public static function get_single_action_type( $action_id, $type ) {
		if ( ! $type ) {
			return false;
		}

		/**
		 * @var FrmFormAction
		 */
		$action_control = FrmFormActionsController::get_form_actions( $type );

		return $action_control->get_single_action( $action_id );
	}

	/**
	 * @param int    $form_id
	 * @param string $type
	 *
	 * @return bool
	 */
	public static function form_has_action_type( $form_id, $type ) {
		$actions = self::get_action_for_form( $form_id, $type );
		return ! empty( $actions );
	}

	/**
	 * @param false|int|string $form_id
	 * @param array            $atts
	 *
	 * @return array
	 */
	public function get_all( $form_id = false, $atts = array() ) {
		if ( is_array( $atts ) && ! isset( $atts['limit'] ) && $this->action_options['limit'] > 99 ) {
			$atts['limit'] = $this->action_options['limit'];
		}

		self::prepare_get_action( $atts, 'any' );

		$limit = $atts['limit'];

		if ( $form_id ) {
			$this->form_id = $form_id;
		}

		$type = $this->id_base;

		global $frm_vars;
		$frm_vars['action_type'] = $type;

		add_filter( 'posts_where', 'FrmFormActionsController::limit_by_type' );
		$query                     = self::action_args( $form_id, $limit );
		$query['post_status']      = $atts['post_status'];
		$query['suppress_filters'] = false;

		$actions = FrmDb::check_cache( json_encode( $query ) . '_type_' . $type, 'frm_actions', $query, 'get_posts' );
		unset( $query );

		remove_filter( 'posts_where', 'FrmFormActionsController::limit_by_type' );

		if ( ! $actions ) {
			return array();
		}

		$settings = array();

		foreach ( $actions as $action ) {
			if ( count( $settings ) >= $limit ) {
				continue;
			}

			$action                  = $this->prepare_action( $action );
			$settings[ $action->ID ] = $action;
		}

		return 1 === $limit ? reset( $settings ) : $settings;
	}

	/**
	 * @param int|string $form_id
	 * @param int        $limit
	 *
	 * @return array
	 */
	public static function action_args( $form_id = 0, $limit = 99 ) {
		$args = array(
			'post_type'   => FrmFormActionsController::$action_post_type,
			'post_status' => 'publish',
			'numberposts' => $limit,
			'orderby'     => 'title',
			'order'       => 'ASC',
		);

		if ( $form_id && $form_id !== 'all' ) {
			$args['menu_order'] = $form_id;
		}

		return $args;
	}

	/**
	 * @param WP_Post $action
	 *
	 * @return WP_Post
	 */
	public function prepare_action( $action ) {
		$action->post_content = (array) FrmAppHelper::maybe_json_decode( $action->post_content );
		$action->post_excerpt = sanitize_title( $action->post_excerpt );

		$default_values = $this->get_global_defaults();

		// Fill default values
		$action->post_content += $default_values;

		foreach ( $default_values as $k => $vals ) {
			if ( ! is_array( $vals ) || ! $vals ) {
				continue;
			}

			if ( 'event' === $k && ! $this->action_options['force_event'] && ! empty( $action->post_content[ $k ] ) ) {
				continue;
			}
			$action->post_content[ $k ] = wp_parse_args( $action->post_content[ $k ], $vals );
		}

		if ( ! is_array( $action->post_content['event'] ) ) {
			$action->post_content['event'] = explode( ',', $action->post_content['event'] );
		}

		return $action;
	}

	/**
	 * @param false|int|string $form_id
	 * @param string           $type
	 *
	 * @return void
	 */
	public function destroy( $form_id = false, $type = 'default' ) {
		global $wpdb;

		$this->form_id = $form_id;

		$query = array( 'post_type' => FrmFormActionsController::$action_post_type );

		if ( $form_id ) {
			$query['menu_order'] = $form_id;
		}

		if ( 'all' !== $type ) {
			$query['post_excerpt'] = $this->id_base;
		}

		$post_ids = FrmDb::get_col( $wpdb->posts, $query, 'ID' );

		foreach ( $post_ids as $id ) {
			wp_delete_post( $id );
		}
		self::clear_cache();
	}

	/**
	 * Delete the action cache when a form action is created, deleted, or updated
	 *
	 * @since 2.0.5
	 *
	 * @return void
	 */
	public static function clear_cache() {
		FrmDb::cache_delete_group( 'frm_actions' );
	}

	/**
	 * @return array
	 */
	public function get_settings() {
		return self::get_action_for_form( $this->form_id, $this->id_base );
	}

	/**
	 * @return array
	 */
	public function get_global_defaults() {
		$defaults = $this->get_defaults();

		if ( ! isset( $defaults['event'] ) ) {
			$defaults['event'] = array( 'create' );
		}

		if ( ! isset( $defaults['conditions'] ) ) {
			$defaults['conditions'] = array(
				'send_stop' => '',
				'any_all'   => '',
			);
		}

		return $defaults;
	}

	/**
	 * @return array
	 */
	public function get_global_switch_fields() {
		$switch               = $this->get_switch_fields();
		$switch['conditions'] = array( 'hide_field' );

		return apply_filters( 'frm_global_switch_fields', $switch );
	}

	/**
	 * Migrate settings from form->options into new action.
	 *
	 * @param object $form
	 * @param string $update
	 *
	 * @return int|WP_Error
	 */
	public function migrate_to_2( $form, $update = 'update' ) {
		$action = $this->prepare_new( $form->id );
		FrmAppHelper::unserialize_or_decode( $form->options );

		// Fill with existing options
		foreach ( $action->post_content as $name => $val ) {
			if ( ! isset( $form->options[ $name ] ) ) {
				continue;
			}

			$action->post_content[ $name ] = $form->options[ $name ];
			unset( $form->options[ $name ] );
		}

		$action = $this->migrate_values( $action, $form );

		// Check if action already exists
		$post_id = get_posts(
			array(
				'name'        => $action->post_name,
				'post_type'   => FrmFormActionsController::$action_post_type,
				'post_status' => $action->post_status,
				'numberposts' => 1,
			)
		);

		if ( ! $post_id ) {
			// Create action now
			$post_id = $this->save_settings( $action );
		}

		if ( ! $post_id || 'update' !== $update ) {
			return $post_id;
		}

		global $wpdb;
		$form->options = maybe_serialize( $form->options );

		// Update form options
		$wpdb->update( $wpdb->prefix . 'frm_forms', array( 'options' => $form->options ), array( 'id' => $form->id ) );
		FrmForm::clear_form_cache();

		return $post_id;
	}

	/**
	 * @param WP_Post  $action
	 * @param stdClass $entry
	 *
	 * @return bool
	 */
	public static function action_conditions_met( $action, $entry ) {
		if ( is_callable( 'FrmProFormActionsController::action_conditions_met' ) ) {
			return FrmProFormActionsController::action_conditions_met( $action, $entry );
		}
		return false;
	}

	/**
	 * @param string $class
	 *
	 * @return array
	 */
	public static function default_action_opts( $class = '' ) {
		return array(
			'classes'     => 'frmfont ' . $class,
			'active'      => false,
			'limit'       => 0,
			'description' => '',
		);
	}

	/**
	 * @return array
	 */
	public static function trigger_labels() {
		$triggers = array(
			'draft'  => __( 'Draft is saved', 'formidable' ),
			'create' => __( 'Entry is created', 'formidable' ),
			'update' => __( 'Entry is updated', 'formidable' ),
			'delete' => __( 'Entry is deleted', 'formidable' ),
			'import' => __( 'Entry is imported', 'formidable' ),
		);

		return apply_filters( 'frm_action_triggers', $triggers );
	}

	/**
	 * @param string $action_key The unique key for this action instance.
	 *
	 * @return void
	 */
	public function render_conditional_logic_call_to_action( $action_key = '' ) {
		$params = array(
			'class'        => 'frm-h-stack-xs frm-bt-200 frm-py-md frm_show_upgrade',
			'data-upgrade' => $this->get_upgrade_text(),
			'data-medium'  => 'conditional-' . $this->id_base,
		);
		// phpcs:disable Generic.WhiteSpace.ScopeIndent
		?>
		<div <?php FrmAppHelper::array_to_html_params( $params, true ); ?>>
			<?php
			FrmHtmlHelper::toggle(
				'frm_logic_cta_' . $action_key,
				'frm_logic_cta_' . $action_key,
				array(
					'div_class' => 'with_frm_style frm_toggle',
					'checked'   => false,
					'echo'      => true,
					'disabled'  => true,
				)
			);
			?>
			<label for="frm_logic_cta_<?php echo esc_attr( $action_key ); ?>" class="frm_noallow">
				<?php esc_html_e( 'Use Conditional Logic', 'formidable' ); ?>
			</label>
		</div>
		<?php
		// phpcs:enable Generic.WhiteSpace.ScopeIndent
	}

	/**
	 * @return string
	 */
	protected function get_upgrade_text() {
		return __( 'Conditional form actions', 'formidable' );
	}

	/**
	 * Gets form fields for form action settings.
	 *
	 * @since 6.10
	 *
	 * @param int $form_id Form ID.
	 *
	 * @return object[]
	 */
	protected function get_form_fields( $form_id ) {
		// Get form fields, include embedded and repeater child fields.
		$form_fields = FrmField::get_all_for_form( $form_id, '', 'include' );
		return array_filter(
			$form_fields,
			function ( $form_field ) {
				return ! FrmField::is_no_save_field( $form_field->type );
			}
		);
	}
}
