<?php
/**
 * Single Alert handler.
 *
 * @package WP_MainWP_Stream
 */

namespace WP_MainWP_Stream;

/**
 * Class Alert
 *
 * @package WP_MainWP_Stream
 */
class Alert {

	/**
	 * Alert post ID
	 *
	 * @var int
	 */
	public $ID;

	/**
	 * Creation date
	 *
	 * @var string
	 */
	public $date;

	/**
	 * Status
	 *
	 * @var string
	 */
	public $status;

	/**
	 * Alert author ID
	 *
	 * @var int
	 */
	public $author;

	/**
	 * Alert type
	 *
	 * @var string
	 */
	public $alert_type;

	/**
	 * Alert meta data
	 *
	 * @var int
	 */
	public $alert_meta;

	/**
	 * Hold Plugin class
	 *
	 * @var Plugin
	 */
	public $plugin;

	/**
	 * Class constructor
	 *
	 * @param object $item Alert data.
	 * @param Plugin $plugin Plugin class.
	 * @return void
	 */
	public function __construct( $item, $plugin ) {
		$this->plugin = $plugin;

		$this->ID     = isset( $item->ID ) ? $item->ID : null;
		$this->status = isset( $item->status ) ? $item->status : 'wp_mainwp_stream_disabled';
		$this->date   = isset( $item->date ) ? $item->date : null;
		$this->author = isset( $item->author ) ? $item->author : null;

		$this->alert_type = isset( $item->alert_type ) ? $item->alert_type : null;
		$this->alert_meta = isset( $item->alert_meta ) ? $item->alert_meta : array();
	}

	/**
	 * Save state of the Alert to database
	 *
	 * @return int The Post ID of the alert.
	 */
	public function save() {

		$args = array(
			'ID'           => $this->ID,
			'post_date'    => $this->date,
			'post_status'  => $this->status,
			'post_content' => '',
			'post_title'   => $this->get_title(),
			'post_author'  => $this->author,
			'post_type'    => Alerts::POST_TYPE,
		);

		if ( empty( $args['ID'] ) ) {
			unset( $args['ID'] );
		}

		$post_id = wp_insert_post( $args );
		if ( empty( $args['ID'] ) ) {
			$this->ID = $post_id;
		}

		$meta = array(
			'alert_type' => $this->alert_type,
			'alert_meta' => $this->alert_meta,
		);

		foreach ( $meta as $key => $value ) {
			$this->update_meta( $key, $value );
		}

		return $post_id;
	}

	/**
	 * Process settings form data
	 *
	 * @param array $data Processed post object data.
	 * @return array New post object data.
	 */
	public function process_settings_form( $data ) {

		$args = array(
			'post_date'   => $this->date,
			'post_status' => $this->status,
			'post_title'  => $this->get_title(),
			'post_author' => $this->author,
			'post_type'   => Alerts::POST_TYPE,
		);

		foreach ( $args as $key => $value ) {
			$data[ $key ] = $value;
		}

		$meta_input = array(
			'alert_type' => $this->alert_type,
			'alert_meta' => $this->alert_meta,
		);

		foreach ( $meta_input as $key => $value ) {
			$this->update_meta( $key, $value );
		}

		return $data;
	}

	/**
	 * Query record meta
	 *
	 * @param string $meta_key Meta key to retrieve (optional). Otherwise will
	 *  grab all meta data for the ID.
	 * @param bool   $single Whether to only retrieve the first value (optional).
	 *
	 * @return mixed Single value if $single is true, array if false.
	 */
	public function get_meta( $meta_key = '', $single = false ) {
		return get_post_meta( $this->ID, $meta_key, $single );
	}

	/**
	 * Update record meta
	 *
	 * @param string $meta_key Meta key to update.
	 * @param string $meta_value Value to update with.
	 * @param string $prev_value Previous value to change (optional).
	 * @return array
	 */
	public function update_meta( $meta_key, $meta_value, $prev_value = '' ) {
		return update_post_meta( $this->ID, $meta_key, $meta_value, $prev_value );
	}

	/**
	 * Determine the title of the alert.
	 *
	 * @todo enhance human readibility
	 * @return string The title of the alert
	 */
	public function get_title() {

		$alert_type = $this->get_alert_type_obj()->name;

		$output = array();
		foreach ( array( 'action', 'author', 'context' ) as $trigger_type ) {
			$output[ $trigger_type ] = $this->plugin->alerts->alert_triggers[ $trigger_type ]->get_display_value( 'list_table', $this );
		}
		$title = '';
		foreach ( $this->plugin->alerts->alert_triggers as $trigger_type => $trigger_obj ) {
			$value  = $trigger_obj->get_display_value( 'list_table', $this );
			$title .= $value . ' > ';
		}
		$title = rtrim( $title, ' > ' );
		return $title;
	}

	/**
	 * Retrive current alert type object
	 *
	 * @return Alert_Type
	 */
	public function get_alert_type_obj() {
		if ( array_key_exists( $this->alert_type, $this->plugin->alerts->alert_types ) ) {
			$obj = $this->plugin->alerts->alert_types[ $this->alert_type ];
		} else {
			$obj = new Alert_Type_None( $this->plugin );
		}
		return $obj;
	}

	/**
	 * Check if record matches trigger criteria.
	 *
	 * @param int   $record_id Record ID.
	 * @param array $recordarr Record data.
	 * @return bool True if a positive match. False otherwise.
	 */
	public function check_record( $record_id, $recordarr ) {
		return apply_filters( 'wp_mainwp_stream_alert_trigger_check', true, $record_id, $recordarr, $this );
	}

	/**
	 * Trigger alert for a specific record.
	 *
	 * @param int $record_id Record ID.
	 * @param int $recordarr Record Data.
	 * @return void
	 */
	public function send_alert( $record_id, $recordarr ) {
		$this->get_alert_type_obj()->alert( $record_id, $recordarr, $this );
	}

	/**
	 * Record Alerts triggered by a Record.
	 *
	 * This should be used any time an alert is triggered.
	 *
	 * Stores the post ID of an Alert triggered by a record.
	 *
	 * As an example, this exists so that its value(s) can then be used
	 * to fetch meta from that Alert in later operations.
	 *
	 * This also creates the Alert triggered meta if not found.
	 *
	 * @see Alert_Type_Highlight::alert() for an example.
	 *
	 * @param object $record     The Record.
	 * @param string $alert_slug The Alert Type slug.
	 * @param array  $alert_meta Alert meta.
	 *
	 * @return bool If the meta was updated successfully.
	 */
	public static function update_record_triggered_alerts( $record, $alert_slug, $alert_meta ) {
		if ( ! is_string( $alert_slug ) ) {
			return false;
		}

		if ( is_array( $record ) ) {
			$record = (object) $record;
		}
		if ( empty( $record->ID ) ) {
			return false;
		}
		$record           = new Record( $record );
		$alerts_triggered = $record->get_meta( Alerts::ALERTS_TRIGGERED_META_KEY, true );

		if ( empty( $alerts_triggered ) || ! is_array( $alerts_triggered ) ) {
			$alerts_triggered = array(
				$alert_slug => $alert_meta,
			);
		} elseif ( ! array_key_exists( $alert_slug, $alerts_triggered ) || ! is_array( $alerts_triggered[ $alert_slug ] ) ) {
			$alerts_triggered[ $alert_slug ] = $alert_meta;
		}
		return $record->update_meta( Alerts::ALERTS_TRIGGERED_META_KEY, $alerts_triggered );
	}

	/**
	 * Get a meta value from the Alert that a Record has triggered.
	 *
	 * If a Record has triggered an Alert (post), this fetches a specific
	 * Alert meta (i.e., "post meta") value from that Alert.
	 *
	 * First, it gets the array of Alerts that the Record has triggered.
	 * Then, using the requested Alert Type, it grabs the first item (post ID) in
	 * that Type.
	 *
	 * Using that ID, it fetches that Alert post's meta, then
	 * returns the value of the requested setting (ie., "post meta" field).
	 *
	 * @see Alert_Type_Highlight::post_class() for an example.
	 *
	 * @param object $record The Record object.
	 * @param string $alert_slug The slug of the Alert Type.
	 * @param string $setting The requested meta value of the Alert.
	 * @param mixed  $default The default value if no value is found.
	 *
	 * @return mixed
	 */
	public function get_single_alert_setting_from_record( $record, $alert_slug, $setting, $default = false ) {
		if ( ! is_object( $record ) || ! is_string( $alert_slug ) || ! is_string( $setting ) ) {
			return false;
		}
		$record           = new Record( $record );
		$alerts_triggered = $record->get_meta( Alerts::ALERTS_TRIGGERED_META_KEY, true );

		// Ensure we have a meta array and that this record has triggered a highlight alert.
		if ( empty( $alerts_triggered ) || ! is_array( $alerts_triggered ) || ! array_key_exists( $alert_slug, $alerts_triggered ) ) {
			return false;
		}

		$values = $alerts_triggered[ $alert_slug ];
		if ( empty( $values ) ) {
			return false;
		}

		// Grab an Alert post ID.
		// @todo determine which Alert post takes priority.
		if ( is_array( $values ) ) {
			$post_id = $values[0];
		} else {
			$post_id = $values;
		}

		if ( ! is_numeric( $post_id ) ) {
			return false;
		}

		$alert = $this->plugin->alerts->get_alert( $post_id );

		$value = ! empty( $alert->alert_meta[ $setting ] ) ? $alert->alert_meta[ $setting ] : $default;
		return $value;
	}
}
