<?php

// Exit if accessed directly
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

class ES_DB_Mailing_Queue {

	public static $table_name = IG_MAILING_QUEUE_TABLE;

	public static $primary_key = 'id';

	public static $version = '1.0';

	/**
	 * Get columns and formats
	 *
	 * @since   2.1
	 */
	public static function get_columns() {
		return array(
			'id'          => '%d',
			'hash'        => '%s',
			'campaign_id' => '%d',
			'subject'     => '%s',
			'body'        => '%s',
			'count'       => '%d',
			'status'      => '%s',
			'start_at'    => '%s',
			'finish_at'   => '%s',
			'created_at'  => '%s',
			'updated_at'  => '%s',
			'meta'        => '%s',
		);
	}

	public static function get_column_defaults() {
		return array(
			'hash'        => null,
			'campaign_id' => 0,
			'subject'     => '',
			'body'        => '',
			'count'       => 0,
			'status'      => 'In Queue',
			'start_at'    => null,
			'finish_at'   => null,
			'created_at'  => ig_get_current_date_time(),
			'updated_at'  => null,
			'meta'        => null,
		);
	}

	public static function get_notification_hash_to_be_sent() {
		global $wpdb;

		$hash = $wpdb->get_var(
			$wpdb->prepare(
				"SELECT hash FROM {$wpdb->prefix}ig_mailing_queue WHERE status = %s ORDER BY id LIMIT 0, 1",
				'In Queue'
			)
		);

		// TODO :: update start date

		return $hash;

	}

	public static function get_notification_to_be_sent( $campaign_hash = '' ) {
		global $wpdb;

		$notification = array();

		$ig_mailing_queue_table = IG_MAILING_QUEUE_TABLE;

		$results = array();
		if ( ! empty( $campaign_hash ) ) {
			$results = $wpdb->get_results(
				$wpdb->prepare(
					"SELECT * FROM {$wpdb->prefix}ig_mailing_queue WHERE hash = %s",
					array( $campaign_hash )
				),
				ARRAY_A
			);
		} else {
			$current_time = ig_get_current_date_time();
			
			$results      = $wpdb->get_results(
				$wpdb->prepare(
					"SELECT * FROM {$wpdb->prefix}ig_mailing_queue WHERE status IN ('Sending', 'In Queue') AND start_at <= %s ORDER BY 
					CASE 
						WHEN start_at = '0000-00-00 00:00:00' THEN %s
						ELSE start_at
					END, id LIMIT 0, 1",
					$current_time,
					$current_time
				),
				ARRAY_A
			);
		}

		if ( count( $results ) > 0 ) {
			$notification = array_shift( $results );

		}

		return $notification;

	}

	/**
	 * Sync mailing queue content with campaign content
	 *
	 * @param array $notification
	 *
	 * @since 4.7.3
	 */
	public static function sync_content( $notification = array() ) {

		if ( ! empty( $notification ) ) {

			$meta = maybe_unserialize( $notification['meta'] );
			if ( ! empty( $meta ) ) {

				$filter  = 'ig_es_refresh_' . $meta['type'] . '_content';
				$post_id = ! empty( $meta['post_id'] ) ? $meta['post_id'] : 0;
				$content = array();
				$content = apply_filters(
					$filter,
					$content,
					array(
						'campaign_id' => $notification['campaign_id'],
						'post_id'     => $post_id,
					)
				);

				// Update mailing queue with updated content data.
				if ( ! empty( $content ) ) {
					global $wpdb;

					$notification['subject'] = ! empty( $content['subject'] ) ? $content['subject'] : $notification['subject'];
					$notification['body']    = ! empty( $content['body'] ) ? $content['body'] : $notification['body'];

					$wpdb->query(
						$wpdb->prepare(
							"UPDATE {$wpdb->prefix}ig_mailing_queue SET subject = %s, body = %s WHERE hash = %s",
							array(
								$notification['subject'],
								$notification['body'],
								$notification['hash'],
							)
						)
					);
				}
			}
		}

		return $notification;
	}

	// Query to insert sent emails (cron) records in table: es_sentdetails
	public static function update_sent_status( $hash = '', $status = 'In Queue' ) {

		global $wpdb;

		// If status is sent then add finish_at time as well.
		if ( 'Sent' === $status ) {
			$current_date_time = ig_get_current_date_time();
			$return_id         = $wpdb->query(
				$wpdb->prepare(
					"UPDATE {$wpdb->prefix}ig_mailing_queue SET status = %s, finish_at = %s WHERE hash = %s",
					$status,
					$current_date_time,
					$hash
				)
			);
		} elseif ( 'Sending' === $status ) {
			$current_date_time = ig_get_current_date_time();
			$return_id         = $wpdb->query(
				$wpdb->prepare(
					"UPDATE {$wpdb->prefix}ig_mailing_queue SET status = %s, start_at = %s WHERE hash = %s",
					$status,
					$current_date_time,
					$hash
				)
			);
		} else {
			$return_id = $wpdb->query(
				$wpdb->prepare(
					"UPDATE {$wpdb->prefix}ig_mailing_queue SET status = %s WHERE hash = %s",
					$status,
					$hash
				)
			);
		}

		return $return_id;
	}

	/* Get sent email count */
	public static function get_sent_email_count( $notification_hash ) {
		global $wpdb;
		$email_count = $wpdb->get_col(
			$wpdb->prepare(
				"SELECT count FROM {$wpdb->prefix}ig_mailing_queue WHERE hash = %s ",
				array( $notification_hash )
			)
		);
		$email_count = array_shift( $email_count );

		return $email_count;
	}

	public static function get_notification_by_hash( $notification_hash ) {
		global $wpbd;

		$notification = array();
		$query        = $wpbd->prepare(
			"SELECT * FROM {$wpbd->prefix}ig_mailing_queue WHERE hash = %s",
			$notification_hash
		);

		$cache_key       = ES_Cache::generate_key( $query );
		$exists_in_cache = ES_Cache::is_exists( $cache_key, 'query' );
		if ( ! $exists_in_cache ) {
			$results = $wpbd->get_results(
				$query,
				ARRAY_A
			);
			ES_Cache::set( $cache_key, $results, 'query' );
		} else {
			$results = ES_Cache::get( $cache_key, 'query' );
		}

		if ( count( $results ) > 0 ) {
			$notification = array_shift( $results );
		}

		return $notification;
	}

	public static function get_notification_by_campaign_id( $campaign_id ) {
		global $wpbd;

		$notification = array();
		$query        = $wpbd->prepare( "SELECT * FROM {$wpbd->prefix}ig_mailing_queue WHERE campaign_id = %d", $campaign_id );

		$cache_key       = ES_Cache::generate_key( $query );
		$exists_in_cache = ES_Cache::is_exists( $cache_key, 'query' );
		if ( ! $exists_in_cache ) {
			$results = $wpbd->get_results(
				$query,
				ARRAY_A
			);
			ES_Cache::set( $cache_key, $results, 'query' );
		} else {
			$results = ES_Cache::get( $cache_key, 'query' );
		}

		if ( is_array( $results ) && count( $results ) > 0 ) {
			$notification = array_shift( $results );
		}

		return $notification;
	}

	public static function get_notifications( $per_page = 5, $page_number = 1 ) {
		global $wpdb;

		if ( ! empty( $per_page ) && ! empty( $page_number ) ) {
			$start_limit = ( $page_number - 1 ) * $per_page;
			$result      = $wpdb->get_results(
				$wpdb->prepare(
					"SELECT * FROM {$wpdb->prefix}ig_mailing_queue ORDER BY created_at DESC LIMIT %d, %d",
					$start_limit,
					$per_page
				),
				ARRAY_A
			);
		} else {
			$result = $wpdb->get_results(
				$wpdb->prepare(
					"SELECT * FROM {$wpdb->prefix}ig_mailing_queue ORDER BY created_at DESC "
				),
				ARRAY_A
			);
		}

		return $result;
	}

	public static function get_notifications_count() {
		global $wpdb;

		$result = $wpdb->get_col(
			$wpdb->prepare(
				"SELECT count(*) as total_notifications FROM {$wpdb->prefix}ig_mailing_queue WHERE %d",
				1
			)
		);

		return $result[0];
	}

	public static function delete( $ids ) {
		global $wpbd;

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

		$ids_count        = count( $ids );
		$ids_placeholders = array_fill( 0, $ids_count, '%d' );

		// Delete notification.
		$wpbd->query(
			$wpbd->prepare(
				"DELETE FROM `{$wpbd->prefix}ig_mailing_queue` WHERE id IN( " . implode( ',', $ids_placeholders ) . ' );',
				$ids
			)
		);
	}


	public static function delete_notifications( $ids ) {
		global $wpbd;

		$ids_count        = count( $ids );
		$ids_placeholders = array_fill( 0, $ids_count, '%d' );

		$campaign_query_args = array(
			IG_ES_CAMPAIGN_STATUS_IN_ACTIVE, // First arguement for $wpbd->prepare
		);
		$campaign_query_args = array_merge( $campaign_query_args, $ids ); // Merge ids with other $wpbd->prepare arguements

		// Update related broadcast campaign status to draft.
		$wpbd->query(
			$wpbd->prepare(
				"UPDATE `{$wpbd->prefix}ig_campaigns` SET `status`= %d WHERE 
				id IN( SELECT `campaign_id` FROM `{$wpbd->prefix}ig_mailing_queue` WHERE 
					id IN( " . implode( ',', $ids_placeholders ) . " ) 
				) AND type = 'newsletter';",
				$campaign_query_args
			)
		);

		// Delete notification.
		$wpbd->query(
			$wpbd->prepare(
				"DELETE FROM `{$wpbd->prefix}ig_mailing_queue` WHERE id IN( " . implode( ',', $ids_placeholders ) . ' );',
				$ids
			)
		);
	}

	public static function add_notification( $data ) {
		global $wpdb;

		$column_formats  = self::get_columns();
		$column_defaults = self::get_column_defaults();
		$prepared_data   = ES_DB::prepare_data( $data, $column_formats, $column_defaults, true );

		$data           = $prepared_data['data'];
		$column_formats = $prepared_data['column_formats'];

		$inserted = $wpdb->insert( IG_MAILING_QUEUE_TABLE, $data, $column_formats );

		$last_report_id = 0;
		if ( $inserted ) {
			$last_report_id = $wpdb->insert_id;
		}

		return $last_report_id;
	}

	public static function update_notification( $notification_id, $data ) {
		global $wpdb;

		$column_formats  = self::get_columns();
		$column_defaults = self::get_column_defaults();
		$prepared_data   = ES_DB::prepare_data( $data, $column_formats, $column_defaults, true );

		$data           = $prepared_data['data'];
		$column_formats = $prepared_data['column_formats'];

		$wpdb->update( IG_MAILING_QUEUE_TABLE, $data, array( 'id' => $notification_id ), $column_formats );

	}

	public static function get_id_details_map() {
		global $wpdb;

		$query   = 'SELECT id, start_at, hash FROM ' . IG_MAILING_QUEUE_TABLE;
		$results = $wpdb->get_results(
			$wpdb->prepare(
				"SELECT id, start_at, hash FROM {$wpdb->prefix}ig_mailing_queue WHERE %d",
				1
			),
			ARRAY_A
		);
		$details = array();
		if ( count( $results ) > 0 ) {
			foreach ( $results as $result ) {
				$details[ $result['hash'] ]['id']       = $result['id'];
				$details[ $result['hash'] ]['start_at'] = $result['start_at'];
			}
		}

		return $details;
	}

	public static function get_mailing_queue_by_id( $mailing_queue_id ) {
		global $wpdb;

		$report  = array();
		$results = $wpdb->get_results(
			$wpdb->prepare(
				"SELECT * FROM {$wpdb->prefix}ig_mailing_queue WHERE id = %s",
				$mailing_queue_id
			),
			ARRAY_A
		);

		if ( count( $results ) > 0 ) {
			$report = array_shift( $results );
		}

		return $report;
	}

	/**
	 * Get recent campaigns data
	 *
	 * @param int $count
	 *
	 * @return array|object|null
	 *
	 * @since 4.4.0
	 */
	public static function get_recent_campaigns( $count = 5 ) {
		global $wpdb;

		if ( ! is_numeric( $count ) ) {
			$count = 5;
		}

		return $wpdb->get_results(
			$wpdb->prepare(
				"SELECT id, hash, campaign_id, subject, start_at, status, finish_at FROM {$wpdb->prefix}ig_mailing_queue order by created_at DESC LIMIT 0, %d",
				$count
			),
			ARRAY_A
		);
	}

	public static function do_insert( $place_holders, $values ) {
		global $wpdb, $wpbd;

		$query  = "INSERT INTO {$wpdb->prefix}ig_mailing_queue (`hash`, `campaign_id`, `subject`, `body`, `count`, `status`, `start_at`, `finish_at`, `created_at`, `updated_at`) VALUES ";
		$query .= implode( ', ', $place_holders );
		$sql    = $wpbd->prepare( $query, $values );

		$logger = get_ig_logger();
		$logger->info( 'Query....<<<<<' . $sql );

		if ( $wpbd->query( $sql ) ) {
			return true;
		} else {
			return false;
		}

	}

	public static function migrate_notifications() {
		global $wpdb;

		$total = $wpdb->get_var(
			$wpdb->prepare(
				"SELECT count(*) as total FROM {$wpdb->prefix}es_notification WHERE %d",
				1
			)
		);

		if ( $total > 0 ) {
			$columns = self::get_columns();
			unset( $columns['id'] );
			$fields = array_keys( $columns );

			$batch_size     = IG_DEFAULT_BATCH_SIZE;
			$total_bataches = ( $total > IG_DEFAULT_BATCH_SIZE ) ? ceil( $total / $batch_size ) : 1;

			for ( $i = 0; $i < $total_bataches; $i ++ ) {
				$batch_start = $i * $batch_size;

				$results = $wpdb->get_results(
					$wpdb->prepare(
						"SELECT * FROM {$wpdb->prefix}es_sentdetails LIMIT %d, %d",
						$batch_start,
						$batch_size
					),
					ARRAY_A
				);

				$values        = array();
				$place_holders = array();
				foreach ( $results as $key => $result ) {
					$queue_data['hash']        = $result['es_sent_guid'];
					$queue_data['campaign_id'] = 0;
					$queue_data['subject']     = $result['es_sent_subject'];
					$queue_data['body']        = $result['es_sent_preview'];
					$queue_data['count']       = $result['es_sent_count'];
					$queue_data['status']      = $result['es_sent_status'];
					$queue_data['start_at']    = $result['es_sent_starttime'];
					$queue_data['finish_at']   = $result['es_sent_endtime'];
					$queue_data['created_at']  = $result['es_sent_starttime'];

					$queue_data = wp_parse_args( $queue_data, self::get_column_defaults() );

					$formats = array();
					foreach ( $columns as $column => $format ) {
						$values[]  = $queue_data[ $column ];
						$formats[] = $format;
					}

					$place_holders[] = '( ' . implode( ', ', $formats ) . ' )';
				}

				ES_DB::do_insert( IG_MAILING_QUEUE_TABLE, $fields, $place_holders, $values );
			}
		}
	}

	/**
	 * Method to update subscribers count in mailing queue table.
	 *
	 * @param string $hash Mailing queue hash.
	 * @param int    $count Subscribers count.
	 *
	 * @since 4.6.3
	 */
	public static function update_mailing_queue( $mailing_queue_id = 0, $data = array() ) {

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

		global $wpdb;

		// Row ID must be positive integer
		$mailing_queue_id = absint( $mailing_queue_id );

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

		if ( empty( $where ) ) {
			$where = self::$primary_key;
		}

		// Initialise column format array
		$column_formats = self::get_columns();

		// Force fields to lower case
		$data = array_change_key_case( $data );

		// White list columns
		$data = array_intersect_key( $data, $column_formats );

		// Reorder $column_formats to match the order of columns given in $data
		$data_keys      = array_keys( $data );
		$column_formats = array_merge( array_flip( $data_keys ), $column_formats );

		if ( false === $wpdb->update( self::$table_name, $data, array( $where => $mailing_queue_id ), $column_formats ) ) {
			return false;
		}

		return true;
	}

	/**
	 * Decrease subscribers count by given amount.
	 *
	 * @param int $mailing_queue_id Mailing queue id.
	 * @param int $decrease_by Subscribers count.
	 *
	 * @since 4.7.6
	 */
	public static function decrease_subscribers_count( $mailing_queue_id, $decrease_by = 0 ) {

		global $wpdb;

		if ( empty( $mailing_queue_id ) || empty( $decrease_by ) ) {
			return;
		}

		$wpdb->query(
			$wpdb->prepare(
				"UPDATE {$wpdb->prefix}ig_mailing_queue SET count = count - %d WHERE id = %d",
				$decrease_by,
				$mailing_queue_id
			)
		);
	}

	/**
	 * Get frequency of sending recent newsletter campaigns.
	 *
	 * @param int $max_campaigns_count fetch the recent n number of campaigns
	 *
	 * @since 5.5.7
	 */
	public static function get_campaign_sending_frequency( $max_campaigns_count = 10 ) {

		$campaigns            = self::get_recent_campaigns( $max_campaigns_count );
		$campaigns_count      = count($campaigns);
		$total_interval       = 0;
		$avg_sending_interval = 0;

		if ($campaigns_count > 1) {
			for ($index=0; $index < $campaigns_count; $index++) {
				if ( $index < $campaigns_count-1) {

					$first_date  = !empty($campaigns[$index]['start_at']) ? strtotime($campaigns[$index]['start_at']) : null;
					$second_date = !empty($campaigns[$index+1]['start_at']) ? strtotime($campaigns[$index+1]['start_at']) : null;

					if ( $first_date && $second_date ) {
						$total_interval = $total_interval + ( $first_date-$second_date );
					}
				}
			}
			$avg_sending_interval = $total_interval / $campaigns_count;
		} 
		return $avg_sending_interval;
	}

	public static function get( $args = array() ) {
		global $wpbd;
		$fields         = ! empty( $args['fields'] ) ? $args['fields']                 : array();
		$date_query     = ! empty( $args['date_query'] ) ? $args['date_query']         : array();
		$campaign_types = ! empty( $args['campaign_types'] ) ? $args['campaign_types'] : array();
		$statuses       = ! empty( $args['statuses'] ) ? $args['statuses'      ] : array();
		$orders         = ! empty( $args['orders'] ) ? $args['orders']: array();

		$select = 'SELECT';

		if ( ! empty( $fields ) ) {
			$select .= ' ' . implode( ', ', $fields );
		} else {
			$select .= ' * ';
		}

		$from = "FROM `{$wpbd->prefix}ig_mailing_queue`";
		
		$wheres = array();

		if ( ! empty( $campaign_types ) ) {
			$campaign_type_where = array();
			foreach ( $campaign_types as $campaign_type ) {
				$regex    = '.*"type";s:[0-9]+:"' . $campaign_type . '".*';
				$campaign_type_where[] = $wpbd->prepare( '`meta` REGEXP %s', $regex );
			}
			$campaign_type_where = implode( ' OR ', array_unique( $campaign_type_where ) );
			$wheres[] = 'AND ( ' . $campaign_type_where . ' )';
		}

		if ( ! empty( $statuses ) ) {
			$status_count        = count( $statuses );
			$status_placeholders = array_fill( 0, $status_count, '%s' );
			$wheres[]           .= $wpbd->prepare( 'AND status IN( ' . implode( ',', $status_placeholders ) . ' )', $statuses );
		}
		
		if ( ! empty( $date_query ) ) {
			foreach ( $date_query as $query ) {
				if ( ! empty( $query['column'] ) && ! empty( $query['operator'] ) && ! empty( $query['value'] ) ) {
					$query_column   = $query['column'];
					$query_operator = $query['operator'];
					$query_value    = $query['value'];
					$wheres[]       = $wpbd->prepare( 'AND ' . $query_column . ' ' . $query_operator . ' %s', $query_value );
				}
			}
		}

		$where = '';
		if ( ! empty( $wheres ) ) {
			$where = 'WHERE 1=1 ' . implode( "\n  ", array_unique( $wheres ) );
		}

		$order = '';
		if ( ! empty( $orders ) ) {
			$order = 'ORDER BY ' . implode( ', ', array_unique( $orders ) );
		}

		$query = $select . ' ' . $from . ' ' . $where . ' ' . $order;

		if ( count( $fields ) === 1 ) {
			$result = $wpbd->get_var(
					$query
			);
		} else {
			$result = $wpbd->get_results(
				$query,
				ARRAY_A
			);
		}

		return $result;
	}
}
