<?php
/**
 * Abandoned Cart Notifications Class.
 *
 * @package automation-web-platform
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}


/**
 * Class WAWP_Abandoned_Cart_Notifications
 * Handles sending emails, WhatsApp, and Meta API notifications for abandoned carts.
 */
class WAWP_Abandoned_Cart_Notifications {
	use WAWP_Security_Trait;
	use WAWP_Settings_Handler;

	/**
	 * Option name.
	 *
	 * @var string
	 */
	private $option_name = WAWP_Settings_Registry::ABANDONED_CART_NOTIF_SETTINGS;

	/**
	 * Singleton instance.
	 *
	 * @var WAWP_Abandoned_Cart_Notifications|null
	 */
	private static $instance = null;

	/**
	 * Constructor.
	 */
	private function __construct() {
		add_filter( 'woocommerce_coupon_get_discount_amount', array( $this, 'cap_coupon_discount' ), 10, 5 );
	}

	/**
	 * Get singleton instance.
	 *
	 * @return WAWP_Abandoned_Cart_Notifications
	 */
	public static function get_instance() {
		if ( null === self::$instance ) {
			self::$instance = new self();
		}

		return self::$instance;
	}

	/**
	 * Get data for React settings.
	 *
	 * @return array Settings data.
	 */
	public function get_react_settings_data() {
		static $cached_result = null;
		if ( null !== $cached_result ) {
			return $cached_result;
		}

		$result = array(
			'settings'     => array(),
			'placeholders' => $this->get_all_placeholders(),
		);

		$cached_result = $result;
		return $result;
	}

	/**
	 * Sanitize and filter saved settings.
	 *
	 * @param array $input Input settings.
	 * @return array Sanitized settings.
	 */
	public function sanitize_settings( $input ) {
		return $input;
	}

	/**
	 * Schedule notifications for a cart.
	 *
	 * @param int    $cart_id Cart ID.
	 * @param string $type    Notification type.
	 */
	public function schedule_notifications_for_cart( $cart_id, $type ) {}

	/**
	 * Send a single notification step.
	 *
	 * @param int    $cart_id Cart ID.
	 * @param string $type    Notification type.
	 * @param int    $index   Notification index.
	 */
	public function send_notification_step( $cart_id, $type, $index ) {}

	/**
	 * Send Meta WhatsApp notification.
	 *
	 * @param string $template_info Template string.
	 * @param string $phone         Phone number.
	 * @param object $cart          Cart object.
	 * @param string $coupon_code   Coupon code.
	 * @param string $type          Notification type.
	 * @param int    $index         Notification index.
	 */
	private function send_meta_whatsapp_notification( $template_info, $phone, $cart, $coupon_code, $type, $index ) {
		if ( false === strpos( $template_info, '|' ) ) {
			return;
		}
		list( $template_name, $language_code ) = explode( '|', $template_info );
		$contact_details                       = maybe_unserialize( $cart->contact_details );
		$customer_name                         = $contact_details['billing_first_name'] ?? 'Valued Customer';

		$components = array(
			array(
				'type'       => 'header',
				'parameters' => array(
					array(
						'type' => 'text',
						'text' => $customer_name,
					),
				),
			),
			array(
				'type'       => 'body',
				'parameters' => array(
					array(
						'type' => 'text',
						'text' => function_exists( 'wc_price' ) ? wc_price( $cart->cart_total ) : $cart->cart_total,
					),
					array(
						'type' => 'text',
						'text' => $coupon_code,
					),
				),
			),
		);

		$response = wawp_send_message(
			$phone,
			'',
			array(
				'channel'       => 'meta_api',
				'context'       => 'abandoned_cart_' . $type . '_meta',
				'user_id'       => $cart->user_id,
				'meta_type'     => 'template',
				'template_name' => $template_name,
				'template_lang' => $language_code,
				'components'    => $components,
				'related_id'    => $cart->id,
			)
		);
		$this->log_internal_notification( $cart->id, $type, $index, 'meta_whatsapp', $phone, ( 'success' === $response['status'] ? 'sent' : 'failed' ), null, wp_json_encode( $response ) );
	}

	/**
	 * Cancel scheduled notifications for a cart.
	 *
	 * @param int $cart_id Cart ID.
	 */
	public function cancel_all_scheduled_notifications_for_cart( $cart_id ) {
		global $wpdb;
		$log_table        = $wpdb->prefix . 'wawp_abandoned_cart_notifications_log';
		$scheduled_events = WAWP()->db->get_results_cached( $wpdb->prepare( 'SELECT * FROM %i WHERE cart_id = %d AND status = %s', $log_table, $cart_id, 'scheduled' ), "wawp_ac_sched_{$cart_id}", 'wawp_ac', 60 );

		foreach ( $scheduled_events as $event ) {
			$event     = (object) $event;
			$timestamp = strtotime( $event->scheduled_at );
			$hook      = 'wawp_send_abandoned_cart_notification_step';
			$args      = array( $cart_id, $event->notification_type, (int) $event->notification_index );
			WAWP_Task_Scheduler::unschedule_at( $timestamp, $hook, $args );
			WAWP()->db->update_row( 'abandoned_cart_notifications_log', array( 'status' => 'cancelled' ), array( 'id' => $event->id ) );
			wp_cache_delete( "wawp_ac_sent_{$cart_id}_{$event->notification_type}_{$event->notification_index}", 'wawp_ac' );
		}
	}

	/**
	 * Log internal notification.
	 *
	 * @param int         $cart_id      Cart ID.
	 * @param string      $type         Type.
	 * @param int         $index        Index.
	 * @param string      $channel      Channel.
	 * @param string      $recipient    Recipient.
	 * @param string      $status       Status.
	 * @param string|null $scheduled_at Scheduled at.
	 * @param string      $api_response API response.
	 */
	private function log_internal_notification( $cart_id, $type, $index, $channel, $recipient, $status, $scheduled_at = null, $api_response = '' ) {
		global $wpdb;
		$table = $wpdb->prefix . 'wawp_abandoned_cart_notifications_log';
		$data  = array(
			'channel'      => $channel,
			'recipient'    => $recipient,
			'status'       => $status,
			'api_response' => $api_response,
		);

		if ( 'scheduled' === $status ) {
			$data['scheduled_at']       = $scheduled_at;
			$data['cart_id']            = $cart_id;
			$data['notification_type']  = $type;
			$data['notification_index'] = $index;
			WAWP()->db->insert( 'abandoned_cart_notifications_log', $data );
		} else {
			$data['sent_at'] = current_time( 'mysql', true );
			$existing_id     = (int) WAWP()->db->get_results_cached( $wpdb->prepare( 'SELECT id FROM %i WHERE cart_id = %d AND notification_type = %s AND notification_index = %d AND status = %s LIMIT 1', $table, $cart_id, $type, $index, 'scheduled' ), "wawp_ac_log_id_{$cart_id}_{$type}_{$index}", 'wawp_ac', 60 )[0]['id'] ?? 0;
			if ( $existing_id ) {
				WAWP()->db->update_row( 'abandoned_cart_notifications_log', $data, array( 'id' => $existing_id ) );
			} else {
				$data['cart_id']            = $cart_id;
				$data['notification_type']  = $type;
				$data['notification_index'] = $index;
				WAWP()->db->insert( 'abandoned_cart_notifications_log', $data );
			}
			wp_cache_delete( 'wac_notifications_' . $cart_id, 'wawp_abandoned_carts' );
		}
	}

	/**
	 * Generate a coupon code.
	 *
	 * @param int   $cart_id  Cart ID.
	 * @param array $settings Settings.
	 * @return string
	 */
	public function generate_coupon_code( $cart_id, $settings ) {
		if ( ! function_exists( 'wc_get_coupon_id_by_code' ) ) {
			return '';
		}

		$prefix      = ! empty( $settings['coupon_prefix'] ) ? sanitize_text_field( $settings['coupon_prefix'] ) : 'REC';
		$coupon_code = strtoupper( $prefix ) . '-' . $cart_id . '-' . strtoupper( wp_generate_password( 6, false ) );
		if ( function_exists( 'wc_get_coupon_id_by_code' ) && wc_get_coupon_id_by_code( $coupon_code ) ) {
			$coupon_code = $coupon_code . '-' . wp_rand( 10, 99 );
		}

		if ( ! class_exists( 'WC_Coupon' ) ) {
			return $coupon_code;
		}

		$coupon = new WC_Coupon();
		$coupon->set_code( $coupon_code );
		$coupon->set_discount_type( $settings['discount_type'] ?? 'percent' );
		$coupon->set_amount( $settings['amount'] ?? 10 );
		$coupon->set_free_shipping( ! empty( $settings['free_shipping'] ) );
		$coupon->set_individual_use( ! empty( $settings['individual_use'] ) );
		$coupon->set_minimum_amount( ! empty( $settings['minimum_spend'] ) ? floatval( $settings['minimum_spend'] ) : '' );
		$coupon->set_exclude_sale_items( ! empty( $settings['exclude_sale_items'] ) );
		$coupon->set_usage_limit( 1 );
		$coupon->set_description( esc_html__( 'Generated by Wawp Abandoned Cart Recovery', 'automation-web-platform' ) );

		// Email restrictions.
		if ( ! empty( $settings['email_restrict'] ) ) {
			global $wpdb;
			$table    = $wpdb->prefix . 'wawp_abandoned_carts';
			$cart_row = WAWP()->db->get_results_cached( $wpdb->prepare( 'SELECT contact_details FROM %i WHERE id = %d', $table, $cart_id ), "wawp_ac_restore_{$cart_id}", 'wawp_ac', 300 );
			if ( ! empty( $cart_row ) ) {
				$contact = maybe_unserialize( $cart_row[0]['contact_details'] );
				if ( is_array( $contact ) && ! empty( $contact['billing_email'] ) ) {
					$coupon->set_email_restrictions( array( $contact['billing_email'] ) );
				}
			}
		}

		// Product restrictions.
		if ( ! empty( $settings['product_restrict'] ) ) {
			$product_ids = array_filter( array_map( 'intval', explode( ',', $settings['product_restrict'] ) ) );
			if ( ! empty( $product_ids ) ) {
				$coupon->set_product_ids( $product_ids );
			}
		}

		// Category restrictions.
		if ( ! empty( $settings['category_restrict'] ) ) {
			$category_ids = array_filter( array_map( 'intval', explode( ',', $settings['category_restrict'] ) ) );
			if ( ! empty( $category_ids ) ) {
				$coupon->set_product_categories( $category_ids );
			}
		}

		$expiry_value = (int) ( $settings['expiry_value'] ?? 7 );
		$expiry_unit  = $settings['expiry_unit'] ?? 'days';
		$expiry_date  = strtotime( "+$expiry_value $expiry_unit" );
		$coupon->set_date_expires( $expiry_date );
		$coupon->save();

		return $coupon_code;
	}

	/**
	 * Cap coupon discount amount.
	 *
	 * @param float     $discount           Discount amount.
	 * @param float     $discounting_amount Discounting amount.
	 * @param array     $cart_item          Cart item.
	 * @param bool      $single             Single.
	 * @param WC_Coupon $coupon             Coupon object.
	 * @return float
	 */
	public function cap_coupon_discount( $discount, $discounting_amount, $cart_item, $single, $coupon ) {
		$notif_settings     = $this->get_wawp_setting( WAWP_Settings_Registry::ABANDONED_CART_NOTIFICATIONS_SETTINGS );
		$coupon_settings    = isset( $notif_settings['coupon_settings'] ) ? $notif_settings['coupon_settings'] : array();
		$prefix             = ! empty( $coupon_settings['coupon_prefix'] ) ? sanitize_text_field( $coupon_settings['coupon_prefix'] ) : 'REC';
		$prefix_with_hyphen = strtoupper( $prefix ) . '-';

		if ( strpos( strtoupper( $coupon->get_code() ), $prefix_with_hyphen ) === 0 ) {
			$max_discount = isset( $coupon_settings['max_discount'] ) ? floatval( $coupon_settings['max_discount'] ) : 0;
			if ( $max_discount > 0 && $discount > $max_discount ) {
				return $max_discount;
			}
		}
		return $discount;
	}

	/**
	 * Replace placeholders in template.
	 *
	 * @param string $template    Template string.
	 * @param object $cart        Cart object.
	 * @param string $coupon_code Coupon code.
	 * @return string
	 */
	private function replace_placeholders( $template, $cart, $coupon_code = '' ) {
		$contact_details = maybe_unserialize( $cart->contact_details );
		$cart_contents   = maybe_unserialize( $cart->cart_contents );
		$first_name      = $contact_details['billing_first_name'] ?? '';
		$last_name       = $contact_details['billing_last_name'] ?? '';
		$full_name       = trim( $first_name . ' ' . $last_name ) ? trim( $first_name . ' ' . $last_name ) : 'Valued Customer';

		$product_list_html = '<ul>';
		$product_list_text = '';
		if ( is_array( $cart_contents ) ) {
			foreach ( $cart_contents as $item ) {
				$product = function_exists( 'wc_get_product' ) ? wc_get_product( $item['variation_id'] ? $item['variation_id'] : $item['product_id'] ) : null;
				if ( $product ) {
					$formatted_price    = function_exists( 'wc_price' ) ? wc_price( $product->get_price() * $item['quantity'] ) : ( $product->get_price() * $item['quantity'] );
					$product_list_html .= sprintf( '<li><a href="%s">%s</a> x %d - %s</li>', esc_url( $product->get_permalink() ), esc_html( $product->get_name() ), $item['quantity'], $formatted_price );
					$product_list_text .= sprintf( "%s x %d - %s\n", $product->get_name(), $item['quantity'], $formatted_price );
				}
			}
		}
		$product_list_html .= '</ul>';

		$replacements = array(
			'{{first_name}}'                => $first_name,
			'{{last_name}}'                 => $last_name,
			'{{name}}'                      => $full_name,
			'{{email}}'                     => $contact_details['billing_email'] ?? '',
			'{{phone_number}}'              => $contact_details['billing_phone'] ?? '',
			'{{billing_address_1}}'         => $contact_details['billing_address_1'] ?? '',
			'{{billing_city}}'              => $contact_details['billing_city'] ?? '',
			'{{billing_postcode}}'          => $contact_details['billing_postcode'] ?? '',
			'{{billing_country}}'           => $contact_details['billing_country'] ?? '',
			'{{cart_total}}'                => function_exists( 'wc_price' ) ? wc_price( $cart->cart_total ) : $cart->cart_total,
			'{{product_in_cart_list_html}}' => $product_list_html,
			'{{product_in_cart_list}}'      => trim( $product_list_text ),
			'{{coupon_code}}'               => $coupon_code,
			'{{site_title}}'                => get_bloginfo( 'name' ),
			'{{site_url}}'                  => home_url(),
			'{{cart_recovery_url}}'         => add_query_arg(
				array(
					'wawp_restore_cart' => 1,
					'wac_id'            => $cart->id,
				),
				home_url( '/' )
			),
		);

		return str_replace( array_keys( $replacements ), array_values( $replacements ), $template );
	}

	/**
	 * Get all placeholders.
	 *
	 * @return array
	 */
	public function get_all_placeholders() {
		return array(
			'{{name}}'                      => 'Customer full name',
			'{{first_name}}'                => 'Customer first name',
			'{{last_name}}'                 => 'Customer last name',
			'{{email}}'                     => 'Customer email',
			'{{phone_number}}'              => 'Customer phone number',
			'{{cart_total}}'                => 'Total value of the cart',
			'{{product_in_cart_list}}'      => 'A plain text list of products in the cart',
			'{{product_in_cart_list_html}}' => 'An HTML list of products for emails',
			'{{coupon_code}}'               => 'The generated unique coupon code',
			'{{site_title}}'                => 'Your website title',
			'{{site_url}}'                  => 'Your website URL',
			'{{cart_recovery_url}}'         => 'Direct link to recover/restore the customer\'s cart',
		);
	}
}
