<?php
/**
 * Thrive Themes - https://thrivethemes.com
 *
 * @package thrive-ultimatum
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit; // No direct access
}

/**
 * Functions which operate with DB
 *
 * e.g.: CRUD functions
 */

/**
 * Save a campaign
 *
 * @param $model array
 *
 * @return false|int id of model or false on error
 */
function tve_ult_save_campaign( $model ) {
	if ( ! empty( $model['ID'] ) ) {
		unset( $model[ $model['ID'] ] );
		$item = get_post( $model['ID'] );
		if ( $item && get_post_type( $item ) === TVE_Ult_Const::POST_TYPE_NAME_FOR_CAMPAIGN ) {
			$id = wp_update_post( $model );
		}
	} else {
		$default = array(
			'post_type'   => TVE_Ult_Const::POST_TYPE_NAME_FOR_CAMPAIGN,
			'post_status' => 'publish',
			'status'      => TVE_Ult_Const::CAMPAIGN_STATUS_PAUSED,
		);
		if ( ! empty( $model['copy'] ) ) {
			$model['post_title'] = __( 'Copy of ', 'thrive-ult' ) . $model['post_title'];
		}
		$id = wp_insert_post( array_merge( $default, $model ) );
	}

	if ( empty( $id ) || is_wp_error( $id ) || $id == 0 ) {
		return false;
	}

	if ( isset( $model['order'] ) ) {
		update_post_meta( $id, TVE_Ult_Const::META_NAME_FOR_CAMPAIGN_ORDER, (int) $model['order'] );
	}

	/**
	 * adds campaign designs/states/events if current item is copy of another campaign
	 */
	if ( ! empty( $model['copy'] ) ) {
		$model['ID']     = $id;
		$model['status'] = TVE_Ult_Const::CAMPAIGN_STATUS_PAUSED;
		tve_ult_copy_campaign_attributes( $model );
	}

	/**
	 * adds campaign values from attribute template
	 */
	if ( isset( $model['template_values'] ) && $model['template_values'] ) {
		$campaign_template     = TVE_Ult_Const::campaign_template_details( $model['tpl'] );
		$model['type']         = $campaign_template['type'];
		$model['status']       = $campaign_template['status'];
		$model['rolling_type'] = $campaign_template['rolling_type'];
		$model['settings']     = $campaign_template['settings'];
		tve_ult_update_campaign_from_template( $campaign_template, $id );
		unset( $model['template_values'] );
	}
	if ( isset( $model['status'] ) ) {
		update_post_meta( $id, TVE_Ult_Const::META_NAME_FOR_STATUS, $model['status'] );
	}

	/**
	 * save campaign type
	 */

	if ( ! empty( $model['type'] ) ) {
		update_post_meta( $id, TVE_Ult_Const::META_NAME_FOR_CAMPAIGN_TYPE, $model['type'] );
		update_post_meta( $id, TVE_Ult_Const::META_NAME_FOR_ROLLING_TYPE, $model['rolling_type'] );
		update_post_meta( $id, TVE_Ult_Const::META_NAME_FOR_CAMPAIGN_SETTINGS, $model['settings'] );
		$start_event = tve_ult_save_start_event( $id );
		/**
		 * delete out-ranged events
		 */
		tve_ult_clear_timeline( $start_event['campaign_id'], $start_event['days'] * 24 + $start_event['hours'] );

		if ( ! empty( $model['settings']['trigger']['ids'] ) ) {
			if ( function_exists( 'tve_flush_cache' ) ) {
				tve_flush_cache( $model['settings']['trigger']['ids'] );
			}
		}
	}

	/**
	 * Save Lockdown options
	 */

	if ( isset( $model['lockdown'] ) ) {
		update_post_meta( $id, TVE_Ult_Const::META_NAME_FOR_LOCKDOWN, $model['lockdown'] );
		if ( $model['lockdown'] == true ) {
			update_post_meta( $id, TVE_Ult_Const::META_NAME_FOR_LOCKDOWN_SETTINGS, $model['lockdown_settings'] );

			/* When saving a campaign with promotion pages we need to flush the  cache on them */
			$promotion_pages = array_column( $model['lockdown_settings']['promotion'], 'id' );

			foreach ( $promotion_pages as $promotion_page_id ) {
				if ( function_exists( 'tve_flush_cache' ) ) {
					tve_flush_cache( $promotion_page_id );
				}
			}
		}
	}

	return $id;
}

/**
 * Saves the date settings
 *
 * @param $model
 *
 * @return bool
 */
function tve_ult_save_date_settings( $model ) {
	if ( $model ) {
		update_option( TVE_Ult_Const::SETTINGS_TIME_ZONE, $model['timezone'] );
		update_option( TVE_Ult_Const::SETTINGS_DATE_FORMAT, $model['date_format'] );
		update_option( TVE_Ult_Const::SETTINGS_TIME_FORMAT, $model['time_format'] );
		/* Also updates the gmt_offset value */
		$gmt_offset = tve_ult_gmt_offset_from_tzstring( $model['timezone'] );
		update_option( TVE_Ult_Const::SETTINGS_TIME_ZONE_OFFSET, $gmt_offset );

		return true;
	}

	return false;
}

/**
 * Copies events, designs and states from campaign
 *
 * @param array $model
 *
 * @return true/false
 */
function tve_ult_copy_campaign_attributes( $model ) {
	if ( empty( $model ) ) {
		return false;
	}
	$original = tve_ult_get_campaign( $model['copy'] );
	if ( empty( $original ) ) {
		return false;
	}

	$designs = tve_ult_get_designs( $model['copy'], array( 'parent_id' => - 1 ) );

	foreach ( $designs as $design ) {
		if ( $design['parent_id'] == 0 ) {
			$design['post_parent'] = $model['ID'];
			$old_design_id         = $design['id'];
			$design['id']          = '';
			$design_id             = tve_ult_save_design( $design );
			foreach ( $designs as $state ) {
				if ( $state['parent_id'] == $old_design_id ) {
					$state['parent_id']   = $design_id['id'];
					$state['post_parent'] = $model['ID'];
					$state['id']          = '';
					tve_ult_save_design( $state );
				}
			}
		}
	}

	require_once plugin_dir_path( __FILE__ ) . 'classes/display_settings/class-thrive-ult-campaign-options.php';
	$campaign_options = new Thrive_Ult_Campaign_Options( $model['ID'] );
	$campaign_options->copyOptions( $model['copy'] );

	return true;
}

/**
 * Saves events, designs and states for campaign created from attribute template
 *
 * @param array $campaign_template
 * @param mixed $id
 *
 * @return true/false
 */
function tve_ult_update_campaign_from_template( $campaign_template, $id ) {
	if ( empty( $campaign_template ) || empty( $id ) ) {
		return false;
	}

	if ( isset( $campaign_template['designs'] ) ) {
		$campaign_template_designs = $campaign_template['designs'];
		$designs_created           = array();
		$states_created            = array();
		foreach ( $campaign_template_designs as $design_key => $design ) {
			$design['post_parent']                  = $id;
			$design[ TVE_Ult_Const::FIELD_CONTENT ] = tve_ult_editor_get_template_content( $design );
			$added_design                           = tve_ult_save_design( $design );
			$states                                 = $design['states'];
			$designs_created[ $design_key ]         = $added_design['id'];

			foreach ( $states as $state_key => $state ) {
				$state['post_parent']                  = $id;
				$state['parent_id']                    = $added_design['id'];
				$state[ TVE_Ult_Const::FIELD_CONTENT ] = tve_ult_editor_get_template_content( $state );
				$added_state                           = tve_ult_save_design( $state );
				$states_created[ $state_key ]          = $added_state['id'];
			}
		}
		if ( isset( $campaign_template['events'] ) ) {
			$campaign_template_events = $campaign_template['events'];
			foreach ( $campaign_template_events as $state_key => $event ) {
				$event['campaign_id'] = $id;
				$event_actions        = $event['actions'];
				foreach ( $event_actions as $action_key => $action ) {
					$event['actions'][ $action_key ]['design'] = isset( $designs_created[ $action['design'] ] ) ? $designs_created[ $action['design'] ] : '';
					$event['actions'][ $action_key ]['state']  = isset( $states_created[ $action['state'] ] ) ? $states_created[ $action['state'] ] : '';
				}
				tve_ult_save_event( $event );
			}
		}
	}

	return true;

}

/**
 * Get the list of campaigns based on filters param
 *
 * @param array $filters allows passing query values to the get_posts function, and some extra values
 *
 * @return array $posts
 */
function tve_ult_get_campaigns( $filters = array() ) {
	$defaults = array(
		'posts_per_page' => - 1,
		'post_type'      => TVE_Ult_Const::POST_TYPE_NAME_FOR_CAMPAIGN,
		'meta_key'       => TVE_Ult_Const::META_NAME_FOR_CAMPAIGN_ORDER,
		'orderby'        => 'meta_value_num',
		'order'          => 'ASC',
		'get_designs'    => true,
		'get_events'     => true,
		'get_settings'   => true,
		'get_logs'       => false,
		'only_running'   => false,
		'lockdown'       => false,
	);

	$filters = array_merge( $defaults, $filters );

	if ( isset( $filters['campaign_type'] ) ) {
		/* specifically overwrite the meta_query options */
		$filters['meta_query'] = array(
			array(
				'key'     => TVE_Ult_Const::META_NAME_FOR_CAMPAIGN_TYPE,
				'value'   => $filters['campaign_type'],
				'compare' => ' = ',
			),
		);
	}

	/**
	 * only retrieve started campaigns
	 */
	if ( ! empty( $filters['only_running'] ) ) {
		$filters['meta_query']    = isset( $filters['meta_query'] ) ? $filters['meta_query'] : array();
		$filters['meta_query'] [] = array(
			'key'   => TVE_Ult_Const::META_NAME_FOR_STATUS,
			'value' => TVE_Ult_Const::CAMPAIGN_STATUS_RUNNING,
		);
	}

	/**
	 * SUPP-5262 stupid conflict with s2Member - this filter is causing the page to blank out
	 * Their code is completely un readable so we're just gonna remove the filter
	 */
	remove_filter( 'pre_get_posts', 'c_ws_plugin__s2member_security::security_gate_query', 100 );

	$posts = get_posts( $filters );

	require_once TVE_Ult_Const::plugin_path() . 'inc/classes/display_settings/class-thrive-display-settings-manager.php';

	foreach ( $posts as $post ) {
		$post->type         = get_post_meta( $post->ID, TVE_Ult_Const::META_NAME_FOR_CAMPAIGN_TYPE, true );
		$post->rolling_type = get_post_meta( $post->ID, TVE_Ult_Const::META_NAME_FOR_ROLLING_TYPE, true );
		$post->status       = get_post_meta( $post->ID, TVE_Ult_Const::META_NAME_FOR_STATUS, true );
		$post->order        = (int) get_post_meta( $post->ID, TVE_Ult_Const::META_NAME_FOR_CAMPAIGN_ORDER, true );
		if ( ! $post->status ) {
			$post->status = TVE_Ult_Const::CAMPAIGN_STATUS_PAUSED;
		}
		$post->settings  = tve_ult_get_campaign_settings( $post->ID );
		$post->linked_to = get_post_meta( $post->ID, TVE_Ult_Const::META_NAME_FOR_CAMPAIGN_LINK, true );
		if ( ! empty( $filters['get_logs'] ) ) {
			$post->impressions     = tve_ult_count_campaign_logs( $post );
			$post->conversions     = 0;
			$post->conversion_rate = 0;
			if ( $post->impressions && tve_ult_campaign_has_conversions( $post ) ) {
				$post->conversions     = tve_ult_count_campaign_logs( $post, TVE_Ult_Const::LOG_TYPE_CONVERSION );
				$post->conversion_rate = sprintf( '%.2f', 100 * $post->conversions / $post->impressions );
			}
			$post->has_event_logs = ( $post->impressions > 1 || $post->conversions );
		}

		/** also append the designs to the post */
		$post->designs = array();
		if ( ! empty( $filters['get_designs'] ) ) {
			$post->designs = tve_ult_get_designs( $post->ID );
		}

		require_once TVE_Ult_Const::plugin_path( 'inc/classes/display_settings/class-thrive-ult-campaign-options.php' );
		$display_settings = new Thrive_Ult_Campaign_Options( $post->ID );
		$display_settings->initOptions();

		$post->has_display_settings = $display_settings->checkForAnyOptionChecked();

		/** also append the events to the post */
		if ( ! empty( $filters['get_events'] ) ) {
			$post->timeline          = array();
			$post->conversion_events = array();

			$events = tve_ult_get_events( array(
				'campaign_id' => $post->ID,
				'type'        => array(
					TVE_Ult_Const::EVENT_TYPE_START,
					TVE_Ult_Const::EVENT_TYPE_TIME,
					TVE_Ult_Const::EVENT_TYPE_CONV,
				),
				'order'       => array(
					'days'  => 'desc',
					'hours' => 'desc',
				),
			) );

			foreach ( $events as $event ) {
				if ( $event['type'] === TVE_Ult_Const::EVENT_TYPE_CONV ) {
					$post->conversion_events[] = $event;
				} else {
					$post->timeline[] = $event;
				}
			}
		}
		if ( ! empty( $filters['lockdown'] ) ) {
			$post->lockdown          = get_post_meta( $post->ID, TVE_Ult_Const::META_NAME_FOR_LOCKDOWN, true );
			$post->lockdown_settings = tve_ult_get_lockdown_settings( $post->ID );

		}
	}

	if ( ! empty( $filters['get_settings'] ) ) {
		foreach ( $posts as $post ) {
			$post->tu_schedule_instance = TU_Schedule_Abstract::factory( $post->ID );
			if ( $post->type === TVE_Ult_Const::CAMPAIGN_TYPE_ROLLING ) {
				$post->settings['rolling_type'] = $post->rolling_type;
			}
			$post->tu_schedule_instance->set( $post->settings );
			$post->tu_schedule_instance->set_conversion_events( $post->conversion_events );
			$post->tu_schedule_instance->set_lockdown( $post->lockdown );
		}
	}

	return $posts;
}

/**
 * Set post's status on trash
 *
 * @param      $id
 * @param bool $force_delete whether or not to bypass trash and delete the campaign permanently
 *
 * @return false | int number of deleted rows or false on error
 */
function tve_ult_delete_campaign( $id, $force_delete = true ) {
	global $tve_ult_db;

	$post = get_post( $id );

	if ( empty( $post ) || $post->post_type !== TVE_Ult_Const::POST_TYPE_NAME_FOR_CAMPAIGN ) {
		return false;
	}

	if ( $force_delete ) {
		/**
		 * also delete designs, events, logs, saved emails and display settings
		 */
		$tve_ult_db->delete_designs( $post->ID );
		$tve_ult_db->delete_events( $post->ID );
		$tve_ult_db->delete_display_settings( $post->ID );
		$tve_ult_db->delete_event_logs( $post->ID );
		$tve_ult_db->delete_email_logs( $post->ID );
	}

	$linked_ids = get_post_meta( $id, TVE_Ult_Const::META_NAME_FOR_CAMPAIGN_LINK, true );

	if ( ! empty( $linked_ids ) ) {
		foreach ( $linked_ids as $link_id ) {
			$events = tve_ult_get_events( array(
				'campaign_id' => $link_id,
				'type'        => TVE_Ult_Const::EVENT_TYPE_CONV,
				'order'       => array(
					'days'  => 'desc',
					'hours' => 'desc',
				),
			) );

			foreach ( $events as $event ) {
				if ( $event['trigger_options']['event'] === TVE_Ult_Const::TRIGGER_OPTION_MOVE && $event['trigger_options']['end_id'] === $id ) {
					$event['trigger_options']['event']  = TVE_Ult_Const::TRIGGER_OPTION_END;
					$event['trigger_options']['end_id'] = '';

					$result = tve_ult_save_event( $event );

					if ( ! isset( $result ) ) {
						return false;
					}
				}
			}
		}
	}

	if ( $force_delete ) {
		$deleted = wp_delete_post( $post->ID, true );
	} else {
		$post->post_status = 'trash';
		$deleted           = wp_update_post( $post );
	}

	if ( $deleted === 0 || is_wp_error( $deleted ) ) {
		return false;
	}

	return $deleted;
}

/**
 * Get campaign based on filters
 *
 * @param       $id
 * @param array $filters
 *      get_designs => false by default
 *
 * @return false|WP_Post on success or false on error
 */
function tve_ult_get_campaign( $id, $filters = array() ) {
	$defaults = array(
		'get_designs'       => false,
		'designs_hierarchy' => false, // this allows getting all the designs
		'get_events'        => false,
		'get_settings'      => false,
		'get_logs'          => true,
	);
	$filters  = array_merge( $defaults, $filters );

	$item = get_post( $id );

	if ( empty( $item ) || ! in_array( $item->post_type, array( TVE_Ult_Const::POST_TYPE_NAME_FOR_CAMPAIGN ) ) ) {
		return false;
	}

	/** also append the designs to the post */
	$item->designs = array();
	if ( ! empty( $filters['get_designs'] ) ) {
		$item->designs = empty( $filters['designs_hierarchy'] ) ? tve_ult_get_designs( $id ) : tve_ult_get_designs_hierarchy( $id );
	}

	$item->type         = get_post_meta( $id, TVE_Ult_Const::META_NAME_FOR_CAMPAIGN_TYPE, true );
	$item->rolling_type = get_post_meta( $id, TVE_Ult_Const::META_NAME_FOR_ROLLING_TYPE, true );
	$item->status       = get_post_meta( $id, TVE_Ult_Const::META_NAME_FOR_STATUS, true );
	$item->linked_to    = get_post_meta( $id, TVE_Ult_Const::META_NAME_FOR_CAMPAIGN_LINK, true );
	$item->settings     = tve_ult_get_campaign_settings( $id );

	if ( ! empty( $filters['get_logs'] ) ) {
		$item->impressions     = tve_ult_count_campaign_logs( $id );
		$item->conversions     = 0;
		$item->conversion_rate = 0;
		if ( $item->impressions && tve_ult_campaign_has_conversions( $id ) ) {
			$item->conversions     = tve_ult_count_campaign_logs( $id, TVE_Ult_Const::LOG_TYPE_CONVERSION );
			$item->conversion_rate = sprintf( '%.2f', 100 * $item->conversions / $item->impressions );
		}
		$item->has_event_logs = ( $item->impressions > 1 || $item->conversions );
	}

	$item->lockdown          = get_post_meta( $id, TVE_Ult_Const::META_NAME_FOR_LOCKDOWN, true );
	$item->lockdown_settings = tve_ult_get_lockdown_settings( $id );

	/** also append the events to the post */
	if ( ! empty( $filters['get_events'] ) ) {
		$item->timeline          = array();
		$item->conversion_events = array();

		$events = tve_ult_get_events( array(
			'campaign_id' => $item->ID,
			'type'        => array(
				TVE_Ult_Const::EVENT_TYPE_START,
				TVE_Ult_Const::EVENT_TYPE_TIME,
				TVE_Ult_Const::EVENT_TYPE_CONV,
			),
			'order'       => array(
				'days'  => 'desc',
				'hours' => 'desc',
			),
		) );

		foreach ( $events as $event ) {
			if ( $event['type'] === TVE_Ult_Const::EVENT_TYPE_CONV ) {
				$item->conversion_events[] = $event;
			} else {
				$item->timeline[] = $event;
			}
		}
	}

	if ( ! empty( $filters['get_settings'] ) ) {
		$item->tu_schedule_instance = TU_Schedule_Abstract::factory( $item->ID );
		if ( $item->type === TVE_Ult_Const::CAMPAIGN_TYPE_ROLLING ) {
			$item->settings['rolling_type'] = $item->rolling_type;
		}
		$item->tu_schedule_instance->set( $item->settings );
		$item->tu_schedule_instance->set_conversion_events( $item->conversion_events );
	}

	return $item;
}

/**
 * Save campaign status
 *
 * @param $id     int
 * @param $status string
 *
 * @return false|int|array id of model or false on error
 */
function tve_ult_save_campaign_status( $id, $status ) {

	if ( empty( $id ) || empty( $status ) ) {
		return array( 'success' => false, 'message' => 'invalid_call' );
	}
	$item = tve_ult_get_campaign( $id );
	if ( $item->status === $status ) {
		return array( 'success' => true, 'data' => $item->ID );
	}

	if ( empty( $item ) ) {
		return array( 'success' => false, 'message' => 'invalid_id' );
	}
	if ( $status === TVE_Ult_Const::CAMPAIGN_STATUS_RUNNING ) {
		/**
		 * step 1 check campaign duration / type settings
		 */
		$campaign_type     = $item->type;
		$campaign_settings = $item->settings;
		if ( empty( $campaign_type ) || empty( $campaign_settings ) ) {
			return array( 'success' => false, 'message' => 'settings_error' );
		}

		if ( $campaign_type == TVE_Ult_Const::CAMPAIGN_TYPE_EVERGREEN && empty( $item->linked_to ) && empty( $campaign_settings['trigger']['type'] ) ) {
			return array( 'success' => false, 'message' => 'evergreen_linked' );
		}

		if ( $campaign_type == TVE_Ult_Const::CAMPAIGN_TYPE_ABSOLUTE ) {
			$current_time = tve_ult_current_time( 'timestamp' );
			$enddate      = strtotime( $campaign_settings['end']['date'] . ' ' . $campaign_settings['end']['time'] );
			if ( $current_time > $enddate ) {
				return array( 'success' => false, 'message' => 'end_date_in_past' );
			}
		}

		/**
		 * step 2 check if the user configured display settings for the campaign
		 */
		require_once TVE_Ult_Const::plugin_path( 'inc/classes/display_settings/class-thrive-ult-campaign-options.php' );
		$manager = new Thrive_Ult_Campaign_Options( $id );
		if ( ! $manager->checkForAnyOptionChecked() ) {
			return array( 'success' => false, 'message' => 'display_settings_error' );
		}

		/**
		 * step 3 check if the user has a lockdown campaign and all the pages set
		 */
		if ( ! empty( $item->lockdown ) && ( empty( $item->lockdown_settings['preaccess'] ) || empty( $item->lockdown_settings['expired'] ) || empty( $item->lockdown_settings['promotion'] ) ) ) {
			return array( 'success' => false, 'message' => 'lockdown' );
		}

		if ( empty( $item->lockdown ) && $campaign_settings['trigger']['type'] == TVE_Ult_Const::TRIGGER_TYPE_PROMOTION ) {
			return array( 'success' => false, 'message' => 'invalid_trigger' );
		}

		/**
		 * step 4. check if the campaign has at least one design and that design has a template selected
		 */
		$designs = tve_ult_get_designs( $id );
		if ( count( $designs ) < 1 ) {
			return array( 'success' => false, 'message' => 'design_error' );
		}
		$has_template = false;
		foreach ( $designs as $d ) {
			if ( ! empty( $d[ TVE_Ult_Const::FIELD_TEMPLATE ] ) ) {
				$has_template = true;
				break;
			}
		}
		if ( ! $has_template ) {
			return array( 'success' => false, 'message' => 'design_tpl_error' );
		}

		if ( ! function_exists( 'tve_leads_get_groups' ) && $campaign_settings['trigger']['type'] == TVE_Ult_Const::TRIGGER_TYPE_LEADS_CONVERSION ) {
			return array( 'success' => false, 'message' => 'invalid_leads_trigger' );
		}
	}

	update_post_meta( $id, TVE_Ult_Const::META_NAME_FOR_STATUS, $status );
	wp_update_post( $item );

	return array( 'success' => true, 'data' => $item->ID );

}

/**
 *
 * Gets the campaign settings by id, checks if we have them saved if not creates empty values
 *
 * @param $id
 *
 * @return mixed
 */
function tve_ult_get_campaign_settings( $id ) {
	$settings = get_post_meta( $id, TVE_Ult_Const::META_NAME_FOR_CAMPAIGN_SETTINGS, true );

	if ( empty( $settings ) ) {
		$settings = array(
			'duration'         => 1,
			'repeat'           => 1,
			'evergreen_repeat' => 0,
			'real'             => 0,
			'realtime'         => '00:00',
			'start'            => array(
				'date' => '',
				'time' => '00:00',
			),
			'end'              => array(
				'date' => '',
				'time' => '00:00',
			),
			'trigger'          => array(
				'type' => '',
				'ids'  => '',
			),
		);
	}

	return $settings;
}

/**
 * Get the lockdown settings or get the default ones
 *
 * @param $id
 *
 * @return mixed
 */
function tve_ult_get_lockdown_settings( $id ) {

	$defaults = array(
		'preaccess' => array(),
		'promotion' => array(
			array(
				'id'    => '',
				'label' => '',
				'type'  => '',
				'value' => '',
				'link'  => '',
			),
		),
		'expired'   => array(),
		'service'   => array(),
	);

	$settings = get_post_meta( $id, TVE_Ult_Const::META_NAME_FOR_LOCKDOWN_SETTINGS, true );
	$settings = empty( $settings ) ? array() : $settings;
	$settings = array_merge( $defaults, $settings );

	foreach ( $settings as $page => &$set ) {
		if ( $page === 'service' ) {
			continue;
		}

		if ( ! empty( $set['id'] ) ) {
			$object       = get_post( $set['id'] );
			$set['value'] = is_object( $object ) ? $object->post_title : null;
		}
	}

	//backwards compatibility for promotion
	if ( ! empty( $settings['promotion'] ) && array_key_exists( 'value', $settings['promotion'] ) ) {

		$old_settings         = $settings['promotion'];
		$old_settings['link'] = $settings['service']['value'];
		unset( $settings['service']['value'] );

		$settings['promotion']   = array();
		$settings['promotion'][] = $old_settings;
	}

	return $settings;
}

/**
 * Get the timezone string setup from WP admin settings screen.
 *
 * @return string the value setup from WP admin general settings
 */
function tve_ult_default_tzstring() {
	$tzstring = get_option( 'timezone_string' );
	if ( ! empty( $tzstring ) ) {
		return $tzstring;
	}

	$offset = get_option( 'gmt_offset' );
	if ( $offset == 0 ) {
		return 'UTC+0';
	}

	return ( $offset < 0 ? 'UTC' : 'UTC+' ) . $offset;
}

/**
 * Get global settings
 *
 * @return array
 */
function tve_ult_get_date_settings() {
	$settings = array(
		'date_format' => get_option( TVE_Ult_Const::SETTINGS_DATE_FORMAT ),
		'time_format' => get_option( TVE_Ult_Const::SETTINGS_TIME_FORMAT ),
		'timezone'    => get_option( TVE_Ult_Const::SETTINGS_TIME_ZONE ),
	);
	if ( ! empty( $settings['timezone'] ) && ! empty( $settings['time_format'] ) && ! empty( $settings['date_format'] ) ) {
		return $settings;
	}

	$default_settings = array(
		'date_format' => 'dS F Y',
		'time_format' => '24',
		'timezone'    => tve_ult_default_tzstring(),
	);

	return $default_settings;
}

/**
 * Get the GMT offset setup from TU settings.
 * The setting can also be saved as a timezone string.
 *
 * By default, it returns the wp gmt_offset option
 *
 *
 * @return float|false Timezone GMT offset, false otherwise.
 */
function tve_ult_gmt_offset() {
	$settings = tve_ult_get_date_settings();

	/**
	 * We need to take into account Daylight savings time - this is applied for city-based timezones
	 */
	if ( ! empty( $settings['timezone'] ) ) {
		$gmt_offset = tve_ult_gmt_offset_from_tzstring( $settings['timezone'] );
	} else {
		$gmt_offset = get_option( TVE_Ult_Const::SETTINGS_TIME_ZONE_OFFSET );
	}

	return false === $gmt_offset ? get_option( 'gmt_offset' ) : $gmt_offset;
}

/**
 * Save design based on $model sent as parameter
 *
 * @param $model
 *
 * @return false|array updated design or false on error
 */
function tve_ult_save_design( $model ) {
	global $tve_ult_db;

	if ( empty( $model['post_parent'] ) ) {
		return false;
	}

	$campaign = get_post( $model['post_parent'] );
	if ( empty( $campaign ) || is_wp_error( $campaign ) ) {
		return false;
	}

	$type = get_post_type( $campaign );
	if ( ! $type || ! in_array( $type, array( TVE_Ult_Const::POST_TYPE_NAME_FOR_CAMPAIGN ) ) ) {
		return false;
	}

	if ( empty( $model['post_title'] ) ) {
		$design_details      = TVE_Ult_Const::design_details( $model['post_type'] );
		$model['post_title'] = $design_details['name'];
	}

	foreach ( TVE_Ult_Const::editor_fields() as $field ) {
		$model['tcb_fields'][ $field ] = isset( $model[ $field ] ) ? $model[ $field ] : '';
	}

	if ( ! ( $id = $tve_ult_db->save_design( $model ) ) ) {
		return false;
	}

	/** when the 1st design is added */
	$designs = tve_ult_get_designs( $model['post_parent'] );
	if ( count( $designs ) == 1 && empty( $model['parent_id'] ) ) {
		$model['id'] = (string) $id;

		$events = tve_ult_get_events( array(
			'campaign_id' => $model['post_parent'],
			'type'        => TVE_Ult_Const::EVENT_TYPE_START,
		) );

		$start_event = reset( $events );

		tve_ult_add_design_to_event( $start_event, $model );
	}

	return tve_ult_get_design( $id );
}

/**
 * Reads designs from DB based on $campaignID and $filters
 *
 * @param       $campaign_id
 * @param array $filters
 *      post_status default is publish
 *
 * @return array
 */
function tve_ult_get_designs( $campaign_id, $filters = array() ) {

	global $tve_ult_db;

	$defaults = array(
		'post_parent' => $campaign_id,
		'post_status' => TVE_Ult_Const::STATUS_PUBLISH,
		'parent_id'   => 0,
		'edit_links'  => true,
	);

	$filters = array_merge( $defaults, $filters );

	if ( $filters['parent_id'] === - 1 ) {
		unset( $filters['parent_id'] );
	}

	$designs = $tve_ult_db->get_designs( $filters );

	foreach ( $designs as $key => $design ) {
		if ( ! empty( $filters['edit_links'] ) ) {
			$designs[ $key ]['tcb_edit_url']    = tve_ult_get_editor_url( $campaign_id, $design['id'], false );
			$designs[ $key ]['tcb_preview_url'] = tve_ult_get_preview_url( $campaign_id, $design['id'], false );
		}

		if ( ! empty( $design[ TVE_Ult_Const::FIELD_TEMPLATE ] ) ) {
			list( $type, $name ) = TU_Template_Manager::tpl_type_key( $design[ TVE_Ult_Const::FIELD_TEMPLATE ] );
			if ( $name === 'cloud' ) {
				$designs[ $key ]['thumb_url'] = tve_ult_get_design_thumbnail( $design['id'] );
			} else {
				$designs[ $key ]['thumb_url'] = TVE_Ult_Const::plugin_url( 'tcb-bridge/editor-templates/' . $type . '/thumbnails/admin/' . $name . '.png' );
			}
		}

		$type                              = TVE_Ult_Const::design_details( $design['post_type'] );
		$designs[ $key ]['type_nice_name'] = $type['name'];

		if ( ! empty( $design['post_type'] ) && $design['post_type'] === TVE_Ult_Const::DESIGN_TYPE_SHORTCODE ) {
			$designs[ $key ]['shortcode'] = TU_Shortcodes::get_countdown_shortcode( $campaign_id, $design['id'] );
		}
	}

	/**
	 * Call also a filter function from dashboard before showing the designs
	 */
	return tve_filter_intrusive_forms( 'tu', $designs );
}


function tve_ult_get_design_thumbnail( $design_id ) {
	$url           = null;
	$wp_upload_dir = wp_get_upload_dir();
	$filename      = $design_id . '.png';
	$filename      = sanitize_file_name( $filename );
	$file_path     = $wp_upload_dir['basedir'] . '/thrive-ultimatum/thumbnails/' . $filename;

	if ( is_file( $file_path ) ) {
		$url = $wp_upload_dir['baseurl'] . '/thrive-ultimatum/thumbnails/' . $filename;
	}

	return $url;
}

/**
 * Gets designs based on its id
 *
 * @param $design_id
 *
 * @return false|array with design's properties or false on error or not found
 */
function tve_ult_get_design( $design_id ) {
	global $tve_ult_db;

	$design = $tve_ult_db->get_design( $design_id );

	if ( empty( $design ) ) {
		return false;
	}

	$design['tcb_edit_url']                         = tve_ult_get_editor_url( $design['post_parent'], $design['id'], false );
	$design['tcb_preview_url']                      = tve_ult_get_preview_url( $design['post_parent'], $design['id'], false );
	$design[ TVE_Ult_Const::DESIGN_QUERY_KEY_NAME ] = $design['id'];

	if ( ! empty( $design[ TVE_Ult_Const::FIELD_TEMPLATE ] ) ) {
		list( $type, $name ) = TU_Template_Manager::tpl_type_key( $design[ TVE_Ult_Const::FIELD_TEMPLATE ] );
		if ( $name === 'cloud' ) {
			$design['thumb_url'] = tve_ult_get_design_thumbnail( $design['id'] );
		} else {
			$design['thumb_url'] = TVE_Ult_Const::plugin_url( 'tcb-bridge/editor-templates/' . $type . '/thumbnails/admin/' . $name . '.png' );
		}
	}

	$type                     = TVE_Ult_Const::design_details( $design['post_type'] );
	$design['type_nice_name'] = $type['name'];

	return $design;
}


function tve_ult_get_template_name( $type ) {

	switch ( $type ) {
		case 'header-bar':
		case 'footer-bar':
			$name = 'bar';
			break;
		default:
			$name = $type;

	}

	return $name;
}

/**
 * fetches and returns all states related to a $design
 * $design can either be the main state (parent_id = 0) or a sub-state
 *
 * @param array|int $design
 *
 * @return array[] list of states
 */
function tve_ult_get_related_states( $design ) {

	if ( is_numeric( $design ) ) {
		$design = tve_ult_get_design( $design );
	}

	$parent = empty( $design['parent_id'] ) ? $design : tve_ult_get_design( $design['parent_id'] );

	return array_merge( array( $parent ), tve_ult_get_child_states( $parent ) );
}

/**
 * fetches and returns all children (child states) of the $parent design
 * $parent is the main state of the design
 *
 * @param array|int $parent
 *
 * @return array[] array of designs
 */
function tve_ult_get_child_states( $parent ) {

	global $tve_ult_db;

	return $tve_ult_db->get_designs( array(
		'parent_id' => (int) ( is_array( $parent ) ? $parent['id'] : $parent ),
		'order'     => 'id ASC',
	) );
}

/**
 * Delete Design from designs tables
 *
 * @param $design
 *
 * @return false|array
 */
function tve_ult_delete_design( $design ) {
	if ( is_array( $design ) ) {
		$design = $design['id'];
	}
	$design_model = tve_ult_get_design( $design );
	if ( empty( $design_model ) ) {
		return false;
	} else {
		tve_ult_cleanup_event_actions( $design_model );
	}

	global $tve_ult_db;

	$result = $tve_ult_db->delete_design( $design );
	if ( empty( $result ) ) {
		return false;
	}

	$response = array(
		'deleted' => $result,
	);
	/**
	 * Checks if the campaign is running and there are no more designs. If this is the case, pauses the campaign and notifies the user about it.
	 */
	$campaign_id     = $design_model['post_parent'];
	$campaign_status = get_post_meta( $campaign_id, TVE_Ult_Const::META_NAME_FOR_STATUS, true );
	if ( $campaign_status === TVE_Ult_Const::CAMPAIGN_STATUS_RUNNING ) {
		$remaining_designs = tve_ult_get_designs( $campaign_id );
		if ( empty( $remaining_designs ) ) {
			$response['campaign_paused'] = __( 'This campaign has been automatically paused because all designs have been deleted', 'thrive-ult' );
			$response['campaign_status'] = TVE_Ult_Const::CAMPAIGN_STATUS_PAUSED;
			tve_ult_save_campaign_status( $campaign_id, TVE_Ult_Const::CAMPAIGN_STATUS_PAUSED );
		}
	}

	return $response;
}

/**
 * Cleanup actions from events that use deleted design
 *
 * @param $design
 *
 * @return false|true
 */
function tve_ult_cleanup_event_actions( $design ) {
	if ( empty( $design ) ) {
		return false;
	}
	$filters = array( 'campaign_id' => $design['post_parent'] );
	$events  = tve_ult_get_events( $filters );
	foreach ( $events as $event ) {
		if ( empty( $event['actions'] ) ) {
			continue;
		}
		$actions = $event['actions'];
		foreach ( $actions as $key => $action ) {
			if ( $action['design'] == $design['id'] ) {
				/* main design gets deleted => completely remove the design from the list of actions */
				unset( $event['actions'][ $key ] );
			} elseif ( $action['state'] == $design['id'] && ! empty( $design['parent_id'] ) ) {
				/* design state gets deleted => auto-select the main state in the timeline event */
				$event['actions'][ $key ]['state'] = $design['parent_id'];
			}
		}
		$event['actions'] = array_values( $event['actions'] );
		tve_ult_save_event( $event );
	}

	return true;
}

/**
 * Get the events based on filters
 *
 * @param array $filters
 *
 * @return array $events
 */
function tve_ult_get_events( $filters = array() ) {
	$events = array();

	$defaults = array(
		'order' => array(
			'days'  => 'desc',
			'hours' => 'desc',
		),
	);

	if ( ! is_array( $filters ) ) {
		return $events;
	}

	$filters = array_merge( $defaults, $filters );

	if ( ! empty( $filters['campaign_id'] ) ) {
		global $tve_ult_db;
		$events = $tve_ult_db->get_events( $filters );
	}
	foreach ( $events as &$event ) {
		$event['actions']         = ! empty( $event['actions'] ) ? unserialize( $event['actions'] ) : array();
		$event['trigger_options'] = ! empty( $event['trigger_options'] ) ? unserialize( $event['trigger_options'] ) : array();
	}

	return $events;
}


/**
 * Insert into DB a start event if it does not already exists
 * A campaign can have only one start event
 *
 * @param int|WP_Post $campaign
 *
 * @return false|int
 */
function tve_ult_save_start_event( $campaign ) {
	if ( ! is_object( $campaign ) ) {
		$campaign = tve_ult_get_campaign( $campaign );
	}

	global $tve_ult_db;

	$item = array(
		'campaign_id' => $campaign->ID,
		'days'        => 0,
		'hours'       => 0,
		'type'        => TVE_Ult_Const::EVENT_TYPE_START,
	);

	$events = $tve_ult_db->get_events( array(
		'campaign_id' => $campaign->ID,
		'type'        => TVE_Ult_Const::EVENT_TYPE_START,
	) );

	if ( ! empty( $events ) ) {
		$start_event = $events[0];
		$item        = array_merge( $start_event, $item );
	}

	$start_date = tve_ult_pre_format_date( $campaign->settings['start']['date'], $campaign->settings['start']['time'] );

	switch ( $campaign->type ) {
		case TVE_Ult_Const::CAMPAIGN_TYPE_ABSOLUTE:
			$end           = tve_ult_pre_format_date( $campaign->settings['end']['date'], $campaign->settings['end']['time'] );
			$diff          = tve_ult_date_diff( $start_date, $end );
			$item['days']  = $diff['days'];
			$item['hours'] = $diff['hours'];
			break;
		case TVE_Ult_Const::CAMPAIGN_TYPE_ROLLING:
			if ( $campaign->rolling_type === TVE_Ult_Const::CAMPAIGN_ROLLING_TYPE_DAILY ) {
				$item['days']  = 0;
				$item['hours'] = $campaign->settings['duration'];
			} else {
				$item['days']  = $campaign->settings['duration'];
				$item['hours'] = 0;
			}
			break;
		case TVE_Ult_Const::CAMPAIGN_TYPE_EVERGREEN:
			$item['days']  = ! isset( $campaign->settings['days_duration'] ) ? $campaign->settings['duration'] : $campaign->settings['days_duration'];
			$item['hours'] = empty( $campaign->settings['hours_duration'] ) ? 0 : $campaign->settings['hours_duration'];
			break;
	}

	return tve_ult_save_event( $item );
}

/**
 * Returns an array with two elements: designs and states
 * Array contains data prepared based on $field_filter param
 *      - designs : list with all designs of campaign
 *      - states : array associative with designs IDs and their states
 *
 * @param       $campaign_id
 * @param array $fields_filter
 *
 * @return array
 */
function tve_ult_get_designs_and_states( $campaign_id, $fields_filter = array() ) {
	$designs = tve_ult_get_designs( $campaign_id );
	$states  = array();

	foreach ( $designs as $design ) {
		$children             = tve_ult_get_designs( $campaign_id, array( 'parent_id' => $design['id'] ) );
		$design['post_title'] = ' - ' . __( 'main state', 'thrive-ult' ) . ' - ';
		array_unshift( $children, $design );
		$states[ $design['id'] ] = $children;
	}

	if ( empty( $fields_filter ) ) {
		return array(
			'designs' => $designs,
			'states'  => $states,
		);
	}

	foreach ( $designs as &$design ) {
		$design = tve_ult_array_filter( $design, $fields_filter );
	}

	foreach ( $states as &$state ) {
		foreach ( $state as &$s ) {
			$s = tve_ult_array_filter( $s, $fields_filter );
		}
	}

	return array(
		'designs' => $designs,
		'states'  => $states,
	);
}

/**
 * Save an event into DB
 *
 * @param array $item
 *
 * @return int|false
 */
function tve_ult_save_event( $item ) {
	global $tve_ult_db;

	if ( isset( $item['actions'] ) && is_array( $item['actions'] ) ) {
		$item['actions'] = serialize( $item['actions'] );
	}

	if ( ! empty( $item['trigger_options'] ) ) {
		// check if we're editing the campaign and if the campaign to move to was changed
		if ( isset( $item['id'] ) && isset( $item['trigger_options']['end_id_old'] ) ) {
			tve_ult_remove_conversion_link( $item );

			unset( $item['trigger_options']['end_id_old'] );
		}
		tve_ult_set_conversion_link( $item );

		$item['trigger_options'] = serialize( $item['trigger_options'] );
		if ( is_array( $item['actions'] ) ) {
			$item['actions'] = serialize( $item['actions'] );
		}
		$item['type']  = TVE_Ult_Const::EVENT_TYPE_CONV;
		$item['days']  = 0;
		$item['hours'] = 0;

	} else {
		unset( $item['trigger_options'] );
	}

	$id = $tve_ult_db->save_event( $item );

	if ( ! empty( $item['type'] ) && $item['type'] === TVE_Ult_Const::EVENT_TYPE_START && empty( $item['actions'] ) ) {
		$designs = tve_ult_get_designs( $item['campaign_id'] );
		if ( ! empty( $designs ) ) {
			$design     = reset( $designs );
			$item['id'] = $id;
			tve_ult_add_design_to_event( $item, $design );
		}
	}

	return tve_ult_get_event( $id );
}

/**
 * Remove conversion link from a specific campaign
 *
 * @param $item
 */
function tve_ult_remove_conversion_link( $item ) {
	$linked = get_post_meta( $item['trigger_options']['end_id_old'], TVE_Ult_Const::META_NAME_FOR_CAMPAIGN_LINK, true );
	if ( ! empty( $linked ) ) {
		//we search for multiple entries because of bug that didn't allow deletion of old
		$keys = array_keys( $linked, $item['campaign_id'] );
		foreach ( $keys as $key ) {
			unset( $linked[ $key ] );
		}
	}

	update_post_meta( $item['trigger_options']['end_id_old'], TVE_Ult_Const::META_NAME_FOR_CAMPAIGN_LINK, $linked );
}

/**
 * Sets a conversion link to a specific campaign
 *
 * @param $item
 */
function tve_ult_set_conversion_link( $item ) {

	/** @var string|array $linked */
	$linked = get_post_meta( $item['trigger_options']['end_id'], TVE_Ult_Const::META_NAME_FOR_CAMPAIGN_LINK, true );

	if ( ! empty( $linked ) ) {
		$key = array_search( $item['campaign_id'], $linked );
		if ( empty( $key ) ) {
			$linked[] = $item['campaign_id'];
		}
	} else {
		$linked = array( $item['campaign_id'] );
	}

	update_post_meta( $item['trigger_options']['end_id'], TVE_Ult_Const::META_NAME_FOR_CAMPAIGN_LINK, $linked );
}

/**
 * Adds a display design action upon event
 *
 * @param array $event
 * @param array $design
 *
 * @return int|false
 */
function tve_ult_add_design_to_event( $event, $design ) {

	if ( empty( $event ) || empty( $design ) ) {
		return false;
	}

	$action_details      = TU_Event_Action::get_details( TU_Event_Action::DESIGN_SHOW );
	$event['actions'][0] = array(
		'key'         => $action_details['key'],
		'design'      => $design['id'],
		'design_name' => $design['post_title'],
		'state'       => $design['id'],
		'state_name'  => __( 'main state', 'thrive-ult' ),
		'name'        => $action_details['name'] . ' <strong>' . $design['post_title'] . ' (' . __( 'main state', 'thrive-ult' ) . ')</strong>',
	);

	return tve_ult_save_event( $event );

}

function tve_ult_get_event( $id ) {
	global $tve_ult_db;

	return $tve_ult_db->get_event( $id );
}

function tve_ult_delete_event( $id ) {
	global $tve_ult_db;

	// If we're deleting a conversion event we need to remove the link to the campaign it should move to
	$item = $tve_ult_db->get_event( $id );
	if ( ! empty( $item['trigger_options'] ) && $item['trigger_options']['event'] === TVE_Ult_Const::TRIGGER_OPTION_MOVE ) {
		$linked = get_post_meta( $item['trigger_options']['end_id'], TVE_Ult_Const::META_NAME_FOR_CAMPAIGN_LINK, true );

		if ( ! empty( $linked ) ) {
			$key = array_search( $item['campaign_id'], $linked );
			unset( $linked[ $key ] );

			update_post_meta( $item['trigger_options']['end_id'], TVE_Ult_Const::META_NAME_FOR_CAMPAIGN_LINK, $linked );
		}
	}

	return $tve_ult_db->delete_event( $id );
}


/**
 * action hook implementation - register an impression for a campaign
 *
 * @param int|WP_Post $campaign
 *
 * @return int|string the inserted ID or a string error message if the insert fails
 */
function tve_ult_register_impression( $campaign ) {

	if ( is_int( $campaign ) ) {
		$campaign = get_post( $campaign );
	}

	return tve_ult_add_event_log( $campaign );
}

/**
 * action hook implementation - register a conversion for a campaign
 *
 * @param int|WP_Post $campaign
 *
 * @return int|string the inserted ID or a string error message if the insert fails
 */
function tve_ult_register_conversion( $campaign ) {
	if ( is_int( $campaign ) ) {
		$campaign = get_post( $campaign );
	}

	return tve_ult_add_event_log( $campaign, TVE_Ult_Const::LOG_TYPE_CONVERSION );
}

/**
 * registers a campaign impression or conversion based on $type parameter - inserts a row in the event_log table
 *
 * @param WP_Post $campaign
 * @param int     $type event log type
 *
 * @return int|string the inserted ID or a string error message if the insert fails
 */
function tve_ult_add_event_log( $campaign, $type = TVE_Ult_Const::LOG_TYPE_IMPRESSION ) {
	if ( current_user_can( 'edit_posts' ) || TU_Product::has_access() ) {
		return __( 'Not logging impression for logged user', 'thrive-ult' );
	}

	global $tve_ult_db;
	/**
	 * also store a cached version of the campaign impressions / conversions in post_meta
	 */
	$impressions = intval( get_post_meta( $campaign->ID, 'tve_ult_log_data_' . $type, true ) );
	update_post_meta( $campaign->ID, 'tve_ult_log_data_' . $type, $impressions + 1 );

	return $tve_ult_db->insert_event_log( array(
		'type'        => $type,
		'campaign_id' => $campaign->ID,
	) );
}

/**
 * get the total number of impressions for a campaign
 *
 * @param WP_Post|int|string $campaign     campaign instance or campaign ID
 * @param int                $type         controls what to retrieve - conversions or impressions
 * @param bool               $bypass_cache whether or not to read in the full data from the event_log table
 *
 * @return int the number of impressions or conversions
 */
function tve_ult_count_campaign_logs( $campaign, $type = TVE_Ult_Const::LOG_TYPE_IMPRESSION, $bypass_cache = false ) {

	global $tve_ult_db;

	$campaign_id = is_numeric( $campaign ) ? $campaign : $campaign->ID;

	$count = '';

	if ( ! $bypass_cache ) {
		$count = (string) get_post_meta( $campaign_id, 'tve_ult_log_data_' . $type, true );
	}

	if ( 0 === strlen( $count ) ) {
		$count = $tve_ult_db->count_logs( array(
			'type'        => $type,
			'campaign_id' => $campaign_id,
		) );
		update_post_meta( $campaign_id, 'tve_ult_log_data_' . $type, $count );
	}

	return (int) $count;
}

/**
 * check whether or not this campaign has at least a Conversion Event defined
 *
 * @param WP_Post|int|string $campaign campaign instance or ID
 *
 * @return bool
 */
function tve_ult_campaign_has_conversions( $campaign ) {
	// TODO: implement this after Conversion Events are implemented

	$campaign_id = is_numeric( $campaign ) ? $campaign : $campaign->ID;

	return true;

}

/**
 * prepare the chart data for a campaign
 *
 * @param int $campaign_id
 *
 * @return array
 */
function tve_ult_get_chart_data( $campaign_id ) {
	global $tve_ult_db;

	$data = $tve_ult_db->count_event_logs_chart_data( $campaign_id );

	/**
	 * if there is no conversion, we do not show the conversion rate
	 */
	if ( ! array_filter( $data['conversions'] ) ) {
		unset( $data['conversions'] );

		return $data;
	}

	$data['conversion_rates'] = array_map( 'tve_ult_conversion_rate', $data['impressions'], $data['conversions'] );

	return $data;
}

/**
 * Delete events form timeline that have duration greater than campaign duration
 *
 * @param $campaign
 * @param $duration
 *
 * @return bool|false|int
 */
function tve_ult_clear_timeline( $campaign, $duration ) {

	if ( empty( $campaign ) || empty( $duration ) ) {
		return false;
	}

	global $tve_ult_db;

	return $tve_ult_db->clear_timeline( $campaign, $duration );
}

/**
 * Delete all impression/conversions post meta
 */
function tve_ult_purge_cache() {
	foreach ( TVE_Ult_Const::log_types() as $type ) {
		delete_post_meta_by_key( 'tve_ult_log_data_' . $type );
	}
}

/**
 * Inserts or updates an email log
 *
 * @param $model
 *
 * @return false|int
 */
function tve_ult_save_email_log( $model ) {

	if ( empty( $model['campaign_id'] ) ) {
		return false;
	}

	if ( empty( $model['email'] ) ) {
		return false;
	}

	if ( empty( $model['started'] ) ) {
		return false;
	}

	$campaign = tve_ult_get_campaign( $model['campaign_id'] );

	if ( empty( $campaign ) ) {
		return false;
	}

	/**
	 * encrypt email address
	 */
	$user       = null;
	$user_email = $model['email'];
	if ( is_email( $model['email'] ) ) {
		$user           = get_user_by( 'email', $model['email'] );
		$model['email'] = md5( $model['email'] );
	}

	global $tve_ult_db;
	if ( $tve_ult_db->save_email_log( $model ) && empty( $model['id'] ) ) {
		do_action( 'thrive_ultimatum_specific_user_evergreen_campaign_start', array(
			'campaign_id'           => $campaign->ID,
			'campaign_name'         => $campaign->post_title,
			'campaign_type'         => $campaign->type,
			'campaign_start_date'   => $model['started'],
			'campaign_end_date'     => '',
			'campaign_trigger_type' => $campaign->settings['trigger']['type'],
			'countdown_event_id'    => '',
			'user_email'            => $user_email,
		), $user );

		return true;
	}

	return false;
}

/**
 * Get an email log based on campaign and email address
 *
 * @param $campaign_id
 * @param $email
 *
 * @return null|array
 */
function tve_ult_get_email_log( $campaign_id, $email ) {
	global $tve_ult_db;

	if ( empty( $campaign_id ) || empty( $email ) ) {
		return null;
	}

	return $tve_ult_db->get_email_log( $campaign_id, $email );
}

/**
 * Delete an email log
 *
 * @param int    $campaign_id
 * @param string $email
 *
 * @return bool|int
 */
function tve_ult_delete_email_log( $campaign_id, $email ) {
	global $tve_ult_db;

	return $tve_ult_db->delete_single_email_log( $campaign_id, $email );
}

/**
 * get all the campaigns that have the page / post with $post_id setup as the campaign's promotion (special offer) page
 * we only need to fetch lockdown campaigns
 *
 * @param string|int $post_id
 *
 * @return WP_Post[] array of campaigns
 */
function tve_ult_get_campaigns_for_promotion_page( $post_id ) {
	if ( empty( $post_id ) ) {
		return array();
	}

	static $promotion_page_campaigns = array();

	if ( isset( $promotion_page_campaigns[ $post_id ] ) ) {
		return $promotion_page_campaigns[ $post_id ];
	}

	$campaigns = tve_ult_get_campaigns( array(
		'get_designs'  => false,
		'get_events'   => false,
		'lockdown'     => true,
		'only_running' => true,
	) );

	$permalink = get_permalink( $post_id );

	$filtered = array();
	foreach ( $campaigns as $campaign ) {
		if ( ! $campaign->lockdown ) {
			continue;
		}
		$by_post = false;
		$by_link = false;

		// backwards compatibility for promotion checks
		if ( ! empty( $campaign->lockdown_settings['promotion'] ) && ! array_key_exists( 'value', $campaign->lockdown_settings['promotion'] ) ) {
			foreach ( $campaign->lockdown_settings['promotion'] as $promotion ) {
				if ( isset( $promotion['id'] ) && $promotion['id'] == $post_id ) {
					$by_post = true;
				}
				if ( untrailingslashit( $promotion['value'] ) === untrailingslashit( $permalink ) ) {
					$by_link = true;
				}
			}
		} else {
			$by_post = isset( $campaign->lockdown_settings['promotion']['id'] ) && $campaign->lockdown_settings['promotion']['id'] == $post_id;
			$by_link = isset( $campaign->lockdown_settings['promotion']['value'] ) && untrailingslashit( $campaign->lockdown_settings['promotion']['value'] ) === untrailingslashit( $permalink );
		}

		if ( $by_post || $by_link ) {
			$filtered [] = $campaign;
		}
	}

	return $filtered;
}

/**
 * get all the campaigns that have the page / post with $post_id with redirect
 *
 * @param $post_id
 */
function tve_ult_get_campaigns_with_redirect( $post_id ) {
	if ( empty( $post_id ) ) {
		return array();
	}

	static $redirect_campaigns = [];

	if ( isset( $redirect_campaigns[ $post_id ] ) ) {
		return $redirect_campaigns[ $post_id ];
	}

	/**
	 * Only get the running evergreen campaigns
	 */
	$campaigns = tve_ult_get_campaigns( array(
		'get_designs'   => false,
		'get_events'    => false,
		'lockdown'      => false,
		'only_running'  => true,
		'campaign_type' => TVE_Ult_Const::CAMPAIGN_TYPE_EVERGREEN,
		'get_settings'  => true,
	) );

	$filtered = [];

	foreach ( $campaigns as $campaign ) {
		if (
			! empty( $campaign->settings['redirect'] ) &&
			! empty( $campaign->settings['redirect_url'] ) &&
			! empty( $campaign->settings['trigger'] ) &&
			! empty( $campaign->settings['trigger']['ids'] )
			&& $post_id === $campaign->settings['trigger']['ids']
		) {
			$filtered [] = $campaign;
		}
	}

	return $filtered;
}

/**
 * Get an email log based on the id of the log
 *
 * @param $id
 *
 * @return array
 */
function tve_ult_get_email_log_by_id( $id ) {
	global $tve_ult_db;

	return $tve_ult_db->get_email_log_by_id( $id );
}

/**
 * Return a list of all designs for a campaign, as a list with each element containing a key with its child states.
 * A sample result of this:
 * array(
 *      ID => '',
 *        post_title => '',
 *      // etc
 *      children => array( array(post_title => '') )
 * )
 *
 * @param int|string $campaign_id
 *
 * @return array
 */
function tve_ult_get_designs_hierarchy( $campaign_id ) {
	$all_designs = tve_ult_get_designs( $campaign_id, array(
		'parent_id' => null,
		'order'     => 'id ASC', // make sure we get all main states first
	) );
	$by_id       = array();
	foreach ( $all_designs as $design ) {
		$design['children'] = array();
		if ( empty( $design['parent_id'] ) ) {
			$by_id[ $design['id'] ] = $design;
			continue;
		}
		if ( ! isset( $by_id[ $design['parent_id'] ] ) ) { // invalid state
			continue;
		}
		$by_id[ $design['parent_id'] ]['children'] [] = $design;
	}

	return array_values( $by_id ); // numeric indexes, so that we can use this as a backbone collection
}

/**
 * Get all campaigns that have at least one shortcode design
 * The campaigns designs are also filtered only to shortcode designs
 *
 * @return array
 */
function tve_ult_get_campaign_with_shortcodes() {

	$campaigns = tve_ult_get_campaigns( array(
		'get_events'   => false,
		'get_settings' => false,
		'get_designs'  => false,
		'only_running' => true,
	) );

	$filtered = array();

	foreach ( $campaigns as $campaign ) {
		$campaign->designs = tve_ult_get_designs( $campaign->ID, [
			'edit_links' => false,
		] );
		if ( empty( $campaign->designs ) ) {
			continue;
		}

		foreach ( $campaign->designs as $key => &$design ) {
			if ( $design['post_type'] === TVE_Ult_Const::DESIGN_TYPE_SHORTCODE ) {
				$filtered[ $campaign->ID ] = $campaign;
			} else {
				/**
				 * unset the un-wanted designs
				 */
				unset( $campaign->designs[ $key ] );
			}
		}
	}

	return $filtered;
}

/**
 * Calculate conversion rate from impressions and conversions
 *
 * @param int $impressions
 * @param int $conversions
 *
 * @return float
 */
function tve_ult_conversion_rate( $impressions, $conversions ) {
	return round( $impressions ? ( 100 * $conversions / $impressions ) : 0.00, 2 );
}

/**
 * @param WP_Post $campaign
 *
 * @return mixed
 */
function tve_ult_campaign_id( $campaign ) {
	if ( ! $campaign ) {
		return '';
	}

	return $campaign->ID;
}

/**
 * Clear the cache if the curent page is a promotion page
 */
function tve_ult_promotion_prevent_cache() {
	$post_id = get_the_ID();

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

	/**
	 * Only get the running evergreen campaigns
	 */
	$campaigns = tve_ult_get_campaigns( array(
		'get_designs'  => false,
		'get_events'   => false,
		'lockdown'     => true,
		'only_running' => true,
		'get_settings' => true,
	) );

	$is_promotion_page = false;

	foreach ( $campaigns as $campaign ) {
		/* checks for cookie redirects */
		if (
			! empty( $campaign->settings['redirect'] ) &&
			! empty( $campaign->settings['redirect_url'] ) &&
			! empty( $campaign->settings['trigger']['ids'] )
			&& $post_id === $campaign->settings['trigger']['ids']
		) {
			$is_promotion_page = true;
			break;
		}

		/* checks for lockdown redirects */
		if ( ! empty( $campaign->lockdown_settings['promotion'] ) ) {
			$lockdown_promotions_ids = array_column( $campaign->lockdown_settings['promotion'], 'id' );

			if ( ! empty( $lockdown_promotions_ids ) && in_array( $post_id, $lockdown_promotions_ids, 'id' ) ) {
				$is_promotion_page = true;
				break;
			}
		}
	}

	/* if we are on a promotion page, do not cache it */
	if ( $is_promotion_page && function_exists( 'tve_do_not_cache_page' ) ) {
		tve_do_not_cache_page();
	}
}
