<?php
/**
 * Campaigns Controller Class
 */
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Class BWFCRM_Campaigns
 */
#[AllowDynamicProperties]
class BWFCRM_Campaigns {
	public static $CAMPAIGN_DRAFT = 1;
	public static $CAMPAIGN_SCHEDULED = 2;
	public static $CAMPAIGN_RUNNING = 3;
	public static $CAMPAIGN_COMPLETED = 4;
	public static $CAMPAIGN_HALT = 5;
	public static $CAMPAIGN_PAUSED = 6;
	public static $CAMPAIGN_CANCELLED = 7;

	public static $CAMPAIGN_EMAIL = 1;
	public static $CAMPAIGN_SMS = 2;
	public static $CAMPAIGN_WHATSAPP = 3;

	private static $ins = null;

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

		return self::$ins;
	}

	/** @var BWFCRM_Broadcast_Processing */
	private $broadcast_as_ins = null;

	public function __construct() {
		include_once __DIR__ . '/class-bwfcrm-broadcast-processing.php';
		$this->broadcast_as_ins = BWFCRM_Broadcast_Processing::get_instance();
	}

	public function get_campaign_open_click_analytics( $oid ) {
		$start_date = BWFAN_Model_Engagement_Tracking::get_first_conversation_date( absint( $oid ), BWFAN_Email_Conversations::$TYPE_CAMPAIGN );
		if ( empty( $start_date ) ) {
			$start_date = new DateTime();
		} else {
			$start_date = new DateTime( $start_date );
		}

		$start_date->setTimezone( wp_timezone() );
		$end_date = clone $start_date;
		$end_date->add( new DateInterval( 'P4D' ) );

		/* Add current hour interval */
		$current_date = new DateTime( 'now' );
		$current_date->setTimezone( wp_timezone() );
		$current_date->add( new DateInterval( 'PT1H' ) );
		if ( $current_date < $end_date ) {
			$end_date = $current_date;
		}

		$intervals      = $this->intervals_between( $start_date->format( 'Y-m-d H:i:s' ), $end_date->format( 'Y-m-d H:i:s' ) );
		$time_intervals = empty( $intervals ) ? [] : array_column( $intervals, 'time_interval' );
		$data           = BWFAN_Model_Broadcast::get_interaction_stats_by_date_range( $time_intervals, $oid );

		$final_data = array();
		foreach ( $intervals as $interval ) {
			$opens        = empty( $data['open'] ) || ! is_array( $data['open'] ) || ! isset( $data['open'][0][ $interval['time_interval'] ] ) ? 0 : $data['open'][0][ $interval['time_interval'] ];
			$clicks       = empty( $data['click'] ) || ! is_array( $data['click'] ) || ! isset( $data['click'][0][ $interval['time_interval'] ] ) ? 0 : $data['click'][0][ $interval['time_interval'] ];
			$final_data[] = $this->get_interval_array( $interval, $opens, $clicks );
		}

		return $final_data;
	}

	public function get_interval_array( $interval, $opens, $clicks ) {
		$interval_data                   = array();
		$interval_data['interval']       = $interval['time_interval'];
		$interval_data['start_date']     = $interval['start_date'];
		$interval_data['date_start_gmt'] = $this->convert_local_datetime_to_gmt( $interval['start_date'] )->format( 'Y-m-d H:i:s' );
		$interval_data['end_date']       = $interval['end_date'];
		$interval_data['date_end_gmt']   = $this->convert_local_datetime_to_gmt( $interval['end_date'] )->format( 'Y-m-d H:i:s' );

		$interval_data['subtotals'] = array(
			'opens'    => absint( $opens ),
			'clicks'   => absint( $clicks ),
			'segments' => array(),
		);

		return $interval_data;
	}

	public function convert_local_datetime_to_gmt( $datetime_string ) {
		$datetime = new DateTime( $datetime_string, new \DateTimeZone( wp_timezone_string() ) );
		$datetime->setTimezone( new DateTimeZone( 'GMT' ) );

		return $datetime;
	}

	public function intervals_between( $start, $end ) {
		$interval_type = 'PT60M';
		$format        = 'Y-m-d H';
		$result        = array();

		// Variable that store the date interval
		// of period 1 day
		$period  = new DateInterval( $interval_type );
		$realEnd = new DateTime( $end );
		$period  = new DatePeriod( new DateTime( $start ), $period, $realEnd );
		$count   = iterator_count( $period );

		foreach ( $period as $date ) {
			if ( $count >= 1 ) {

				$new_interval                  = array();
				$new_interval['start_date']    = $date->format( 'Y-m-d H:i:s' );
				$new_interval['end_date']      = $date->format( 'Y-m-d 23:59:59' );
				$new_interval['time_interval'] = $date->format( $format );

				$result[] = $new_interval;
			}
			$count --;
		}

		return $result;
	}

	public function get_conversions( $campaign_id, $offset = 0, $limit = 25 ) {
		if ( empty( $campaign_id ) ) {
			return array(
				'conversions' => array(),
				'total'       => 0,
			);
		}

		return BWFAN_Model_Conversions::get_conversions_by_source_type( $campaign_id, BWFAN_Email_Conversations::$TYPE_CAMPAIGN, $limit, $offset );
	}

	/**
	 * @return mixed
	 */
	public static function get_top_broadcast( $type = 1 ) {
		$broadcasts = BWFAN_Model_Broadcast::get_top_broadcast( $type );

		$top_broadcast['top_broadcast'] = $broadcasts;

		return $top_broadcast;
	}

	public function save_editor_content( $broadcast_id, $content_number, $design, $html ) {
		$data = BWFAN_Model_Broadcast::get_broadcast_data( $broadcast_id );

		$editor = array(
			'body'   => $html,
			'design' => $design,
		);

		$content_data = ! empty( $data ) && isset( $data['content'] ) && ! empty( $data['content'] ) ? $data['content'] : array();
		if ( empty( $content_data ) || ! is_array( $content_data ) ) {
			$content_data[]['editor']                = $editor;
			$content_data[ $content_number ]['type'] = 'editor';
		} else {
			$content_number                            = absint( $content_number );
			$content_data[ $content_number ]['editor'] = $editor;
			$content_data[ $content_number ]['type']   = 'editor';
		}

		$data            = ! is_array( $data ) ? array() : $data;
		$data['content'] = $content_data;

		BWFAN_Model_Broadcast::update_broadcast_data( $broadcast_id, $data );

		return true;
	}

	public function get_editor_design( $broadcast_id, $content_number ) {
		$content    = $this->get_editor_content( $broadcast_id, $content_number, true );
		$merge_tags = $this->get_merge_tags_for_editor();
		if ( empty( $content ) ) {
			return array(
				'design'     => '',
				'merge_tags' => $merge_tags,
				'subject'    => '',
			);
		}

		$editor_content = ! isset( $content['content'] ) || ! is_array( $content['content'] ) ? array() : $content['content'];
		$subject        = ! isset( $content['subject'] ) ? '' : $content['subject'];
		if ( ! is_array( $editor_content ) || ! isset( $editor_content['design'] ) || empty( $editor_content['design'] ) ) {
			return array(
				'design'     => '',
				'merge_tags' => $merge_tags,
				'subject'    => $subject,
			);
		}

		return array(
			'design'     => $editor_content['design'],
			'merge_tags' => $merge_tags,
			'subject'    => $subject,
		);
	}

	public function get_editor_content( $broadcast_id, $content_number, $get_subject = false ) {
		if ( empty( $content_number ) && 0 !== absint( $content_number ) ) {
			return false;
		}

		$data = BWFAN_Model_Broadcast::get_broadcast_data( $broadcast_id );
		if ( ! is_array( $data ) || empty( $data['content'] ) || ! is_array( $data['content'] ) || ! isset( $data['content'][ $content_number ] ) ) {
			return false;
		}

		$content = $data['content'][ $content_number ];
		if ( ! is_array( $content ) ) {
			return false;
		}

		$editor_content = empty( $content['editor'] ) || ! is_array( $content['editor'] ) ? array() : $content['editor'];
		if ( false === $get_subject ) {
			return $editor_content;
		}

		$subject = isset( $content['subject'] ) && ! empty( $content['subject'] ) ? $content['subject'] : '';

		return array(
			'subject' => $subject,
			'content' => $editor_content,
		);
	}

	public function get_merge_tags_for_editor() {
		$tags   = BWFCRM_Core()->merge_tags->get_registered_grouped_tags( true );
		$return = array();
		foreach ( $tags as $slug => $m_tags ) {
			$group_tags = array();
			foreach ( $m_tags as $tag_slug => $tag_name ) {
				$group_tags[ sanitize_title( $tag_slug ) ] = array(
					'name'  => $tag_name,
					'value' => '{{' . $tag_slug . '}}',
				);
			}

			$group_name = '';
			switch ( $slug ) {
				case 'contact':
					$group_name = 'Contact';
					break;
				case 'contact_fields':
					$group_name = 'Fields';
					break;
				case 'general':
					$group_name = 'General';
					break;
			}

			$return[ $slug ] = array(
				'name'      => $group_name,
				'mergeTags' => $group_tags,
			);
		}

		return $return;
	}

	public function save_broadcast_content( $broadcast_id, $content ) {
		if ( empty( $broadcast_id ) || empty( $content ) || ! is_array( $content ) ) {
			return BWFCRM_Common::crm_error( __( 'Broadcast ID or Content is not valid / empty', 'wp-marketing-automations-pro' ), null, 400 );
		}

		$data = BWFAN_Model_Broadcast::get_broadcast_data( absint( $broadcast_id ) );
		if ( empty( $data ) || ! is_array( $data ) ) {
			return BWFCRM_Common::crm_error( __( 'Broadcast not found OR Invalid Broadcast Data', 'wp-marketing-automations-pro' ), null, 400 );
		}

		$data['content'] = ! empty( $content ) ? self::bwf_validate_anchor_tag( $content ) : array();

		BWFAN_Model_Broadcast::update_broadcast_data( absint( $broadcast_id ), $data );

		return true;
	}

	/**
	 * Remove undefined anchor tags
	 *
	 * @param $content
	 *
	 * @return array
	 */
	public static function bwf_validate_anchor_tag( $content ) {
		$content_arr = [];
		foreach ( $content as $data ) {
			if ( isset( $data['editor'] ) && isset( $data['editor']['body'] ) ) {
				$data['editor']['body'] = preg_replace_callback( '%(<a href="undefined".*?>)+?\s*(?P<link>\S+)\s*+(<\/a.*?>)%is', function ( $matches ) {
					$string = $matches[0];
					if ( isset( $matches['link'] ) && wp_http_validate_url( $matches['link'] ) ) {
						$string = preg_replace( '/href="undefined"/i', 'href="' . $matches['link'] . '"', $string );
					} else {
						$string = preg_replace( '/href="undefined"/i', 'href="#"', $string );
					}

					return $string;
				}, $data['editor']['body'] );
			}
			$content_arr[] = $data;
		}

		return $content_arr;
	}

	public function maybe_daily_limit_reached( $type = 1 ) {
		return $this->broadcast_as_ins->maybe_daily_limit_reached( $type );
	}

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

	public function process_single_scheduled_broadcasts( $campaign_data ) {
		$this->broadcast_as_ins->process_single_scheduled_broadcasts( $campaign_data );
	}

	public function get_unopen_broadcast_contacts( $broadcast_id, $args = array(), $return_type = ARRAY_N ) {
		global $wpdb;

		/** Pagination Query */
		$limit            = isset( $args['limit'] ) ? absint( $args['limit'] ) : 0;
		$offset           = isset( $args['offset'] ) ? absint( $args['offset'] ) : 0;
		$pagination_query = '';
		if ( ! empty( $limit ) ) {
			$pagination_query = "LIMIT $offset, $limit";
		}

		/** Order By Query */
		$order          = isset( $args['order'] ) && ! empty( $args['order'] ) ? $args['order'] : 'ASC';
		$order_by_query = "ORDER BY cid $order";

		/** END ID Query */
		$end_id       = isset( $args['end_id'] ) ? absint( $args['end_id'] ) : 0;
		$end_id_query = '';
		if ( ! empty( $end_id ) ) {
			$end_id_query = "AND cid < $end_id";
		}

		/** Exclude Contact IDs */
		$exclude       = isset( $args['exclude_ids'] ) && is_array( $args['exclude_ids'] ) ? implode( ',', $args['exclude_ids'] ) : array();
		$exclude_query = '';
		if ( ! empty( $exclude ) ) {
			$exclude_query = "AND cid NOT IN ($exclude)";
		}
		/** Get parent broadcast's data */
		$broadcast_data = BWFAN_Model_Broadcast::get_broadcast_data( $broadcast_id );
		$exclude_unsubs = isset( $broadcast_data['is_promotional'] ) && 1 === intval( $broadcast_data['is_promotional'] );

		/** Engagement Query for Contact IDs */
		$sql  = $wpdb->prepare( "SELECT cid from {$wpdb->prefix}bwfan_engagement_tracking WHERE type=2 AND oid=%d AND (cid!='' OR cid IS NOT NULL) AND open=0 $end_id_query $exclude_query $order_by_query $pagination_query", $broadcast_id );
		$cids = $wpdb->get_results( $sql );

		if ( empty( $cids ) ) {
			return array(
				'contacts'    => array(),
				'total_count' => 0,
			);
		}

		/** Total Contacts */
		$sql          = $wpdb->prepare( "SELECT count(cid) from {$wpdb->prefix}bwfan_engagement_tracking WHERE type=2 AND oid=%d AND (cid!='' OR cid IS NOT NULL) AND open=0 $end_id_query $exclude_query", $broadcast_id );
		$total_counts = $wpdb->get_var( $sql );

		/** Contact Query */
		$cids               = array_column( $cids, 'cid' );
		$contact_query_args = array(
			'customer_data'  => true,
			'include_ids'    => $cids,
			'grab_totals'    => isset( $args['grab_totals'] ) && $args['grab_totals'],
			'only_count'     => isset( $args['only_count'] ) && $args['only_count'],
			'exclude_unsubs' => $exclude_unsubs,

		);
		$filters            = isset( $args['filters'] ) ? $args['filters'] : array();
		$contacts           = BWFCRM_Contact::get_contacts( '', 0, $limit, $filters, $contact_query_args, $return_type );
		$contacts           = is_array( $contacts ) && ! empty( $contacts['contacts'] ) ? $contacts['contacts'] : [];

		return array(
			'contacts'    => $contacts,
			'total_count' => empty( $contacts ) ? 0 : $total_counts,
		);
	}

	public function get_broadcast_lookup( $args ) {
		global $wpdb;

		$args = wp_parse_args( $args, array(
			'ids'    => array(),
			'type'   => 0,
			'limit'  => 25,
			'offset' => 0,
			'search' => '',
		) );

		$pagination_query = '';
		if ( ! empty( $args['offset'] ) || ! empty( $args['limit'] ) ) {
			$pagination_query = 'LIMIT ' . $args['offset'] . ', ' . $args['limit'];
		}

		$ids         = $args['ids'];
		$where_query = 'WHERE 1 = 1 ';
		if ( is_array( $ids ) && ! empty( $ids ) ) {
			$ids         = implode( ',', $ids );
			$where_query .= "AND id IN ($ids)";
		}

		$type = $args['type'];
		if ( ! empty( $type ) ) {
			$where_query .= "AND type = $type";
		}

		$db_broadcasts = $wpdb->get_results( "SELECT id, title from {$wpdb->prefix}bwfan_broadcast $where_query $pagination_query", ARRAY_A );
		$broadcasts    = array();
		foreach ( $db_broadcasts as $broadcast ) {
			$broadcasts[ absint( $broadcast['id'] ) ] = array(
				'id'    => absint( $broadcast['id'] ),
				'title' => $broadcast['title'],
			);
		}

		return $broadcasts;
	}

	/**
	 * If broadcast is in scheduled and paused status then get updated contact's count
	 *
	 * @param $broadcast
	 *
	 * @return array|mixed
	 */
	public static function get_broadcast_updated_contact_count( $broadcast ) {
		/** If broadcast status is not scheduled and paused */
		$allowed_status = [ BWFCRM_Broadcast_Processing::$CAMPAIGN_SCHEDULED, BWFCRM_Broadcast_Processing::$CAMPAIGN_PAUSED ];
		if ( ! in_array( intval( $broadcast['status'] ), $allowed_status, true ) ) {
			return $broadcast['count'];
		}

		$data            = isset( $broadcast['data'] ) && isset( $broadcast['data']['filters'] ) ? $broadcast['data'] : BWFAN_Model_Broadcast::get_broadcast_data( $broadcast['id'] );
		$filters         = isset( $data['filters'] ) ? $data['filters'] : [];
		$additional_info = [
			'grab_totals'   => true,
			'only_count'    => true,
			'customer_data' => false,
		];
		if ( isset( $data['includeSoftBounce'] ) ) {
			$additional_info['include_soft_bounce'] = $data['includeSoftBounce'];
		}
		if ( isset( $data['includeUnverified'] ) ) {
			$additional_info['include_unverified'] = $data['includeUnverified'];
		}
		if ( empty( $data['is_promotional'] ) ) {
			$additional_info['include_unsubscribe'] = true;
		}
		$filters['status_is'] = 1;

		$count = BWFCRM_Contact::get_contacts( '', 0, 0, $filters, $additional_info );

		return isset( $count['total_count'] ) ? $count['total_count'] : $broadcast['count'];
	}
}

if ( class_exists( 'BWFCRM_Campaigns' ) ) {
	BWFCRM_Core::register( 'campaigns', 'BWFCRM_Campaigns' );
}
