<?php
/**
 * Email Triggers.
 *
 * Hooks into WooCommerce and UGC Commerce events to trigger emails.
 *
 * @package Ugcify\Email
 */

namespace Ugcify\Email;

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

/**
 * Class EmailTriggers
 */
class EmailTriggers {
	/**
	 * Daily counter option key for successful order-complete feedback request emails.
	 *
	 * @var string
	 */
	private const ORDER_COMPLETE_DAILY_COUNT_OPTION = 'ugcify_order_complete_email_daily_counts';

	/**
	 * Number of daily buckets to keep in option storage.
	 *
	 * @var int
	 */
	private const ORDER_COMPLETE_DAILY_RETENTION_DAYS = 730;

	/**
	 * Constructor — registers all email trigger hooks.
	 */
	public function __construct() {
		// WooCommerce: Order completed trigger.
		add_action( 'woocommerce_order_status_completed', array( $this, 'on_order_complete' ), 10, 1 );

		// UGC Commerce: Review submitted trigger.
		add_action( 'ugcify_review_submitted', array( $this, 'on_review_submit' ), 10, 2 );

		// UGC Commerce: Review status changed trigger.
		add_action( 'ugcify_review_status_changed', array( $this, 'on_review_status_changed' ), 10, 3 );
		add_action( 'ugcify_reward_review_approved', array( $this, 'on_reward_review_approved' ), 10, 1 );
		add_action( 'ugcify_reward_review_featured', array( $this, 'on_reward_review_featured' ), 10, 1 );
		add_action( 'ugcify_reward_lightbox_purchase', array( $this, 'on_reward_lightbox_purchase' ), 10, 1 );
		add_action( 'ugcify_reward_points_redeemed', array( $this, 'on_reward_points_redeemed' ), 10, 1 );
		add_action( 'ugcify_badge_updated', array( $this, 'on_badge_updated' ), 10, 1 );
	}

	/**
	 * Handle order completion — send email to customer.
	 *
	 * @param int $order_id WooCommerce order ID.
	 * @return void
	 */
	public function on_order_complete( $order_id ) {
		$order = wc_get_order( $order_id );
		if ( ! $order ) {
			return;
		}

		$recipient = $order->get_billing_email();
		if ( empty( $recipient ) ) {
			return;
		}

		// Build placeholder data from order.
		$data = EmailPlaceholders::build_order_data( $order );

		$sent = EmailSender::send( 'order_complete', $recipient, $data );
		if ( true === $sent ) {
			$this->increment_order_complete_email_daily_count();
		}
	}

	/**
	 * Increment the daily count of successfully sent order-complete request emails.
	 *
	 * @return void
	 */
	private function increment_order_complete_email_daily_count() {
		$counts = get_option( self::ORDER_COMPLETE_DAILY_COUNT_OPTION, array() );
		if ( ! is_array( $counts ) ) {
			$counts = array();
		}

		$today_key = $this->get_today_site_date_key();
		$current   = isset( $counts[ $today_key ] ) ? absint( $counts[ $today_key ] ) : 0;
		$counts[ $today_key ] = $current + 1;

		$counts = $this->prune_old_daily_count_keys( $counts, self::ORDER_COMPLETE_DAILY_RETENTION_DAYS );

		update_option( self::ORDER_COMPLETE_DAILY_COUNT_OPTION, $counts, false );
	}

	/**
	 * Get today's date key (Y-m-d) in WordPress site timezone.
	 *
	 * @return string
	 */
	private function get_today_site_date_key() {
		try {
			$now = new \DateTimeImmutable( 'now', wp_timezone() );
			return $now->format( 'Y-m-d' );
		} catch ( \Exception $exception ) {
			unset( $exception );
			return gmdate( 'Y-m-d' );
		}
	}

	/**
	 * Prune daily count buckets older than configured retention.
	 *
	 * @param array $counts Counts map by date key.
	 * @param int   $days_to_keep Retention in days.
	 * @return array
	 */
	private function prune_old_daily_count_keys( $counts, $days_to_keep = 730 ) {
		if ( empty( $counts ) || $days_to_keep <= 0 ) {
			return $counts;
		}

		try {
			$cutoff = ( new \DateTimeImmutable( 'now', wp_timezone() ) )
				->sub( new \DateInterval( 'P' . absint( $days_to_keep ) . 'D' ) )
				->format( 'Y-m-d' );
		} catch ( \Exception $exception ) {
			unset( $exception );
			return $counts;
		}

		$filtered = array();
		foreach ( $counts as $date_key => $count ) {
			if ( ! is_string( $date_key ) || ! preg_match( '/^\d{4}-\d{2}-\d{2}$/', $date_key ) ) {
				continue;
			}

			if ( $date_key < $cutoff ) {
				continue;
			}

			$filtered[ $date_key ] = absint( $count );
		}

		return $filtered;
	}

	/**
	 * Handle review submission — send notification to admin.
	 *
	 * @param int   $review_id   The review ID.
	 * @param array $review_data The review data array.
	 * @return void
	 */
	public function on_review_submit( $review_id, $review_data ) {
		// Send to site admin email.
		$admin_email = get_option( 'admin_email' );
		if ( empty( $admin_email ) ) {
			return;
		}

		// Build placeholder data from review.
		$data = EmailPlaceholders::build_review_data( $review_data, $review_id );

		EmailSender::send( 'review_submit', $admin_email, $data );
	}

	/**
	 * Handle review status change — send approve/reject email to user.
	 *
	 * @param int    $review_id  The review ID.
	 * @param string $new_status The new status (approved, rejected, pending).
	 * @param string $old_status The previous status.
	 * @return void
	 */
	public function on_review_status_changed( $review_id, $new_status, $old_status ) {
		// Only send on approval or rejection.
		if ( ! in_array( $new_status, array( 'approved', 'rejected' ), true ) ) {
			return;
		}

		// Skip if status didn't actually change.
		if ( $new_status === $old_status ) {
			return;
		}

		// Load the review to get user data.
		$repository = new \Ugcify\Database\ReviewRepository();
		$review     = $repository->find( $review_id );

		if ( ! $review ) {
			return;
		}

		$review_data = $review->to_array();

		// Determine recipient email.
		$recipient = '';
		if ( ! empty( $review_data['user_id'] ) ) {
			$user = get_user_by( 'id', $review_data['user_id'] );
			if ( $user ) {
				$recipient = $user->user_email;
			}
		}

		// Fallback to guest email.
		if ( empty( $recipient ) && ! empty( $review_data['guest_email'] ) ) {
			$recipient = $review_data['guest_email'];
		}

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

		if (
			'approved' === $new_status
			&& ! empty( $review_data['user_id'] )
			&& class_exists( '\\Ugcify\\Rewards\\RewardTrigger' )
			&& \Ugcify\Rewards\RewardTrigger::did_emit_review_approval_event( (int) $review_id )
		) {
			return;
		}

		// Build placeholder data.
		$data = EmailPlaceholders::build_review_data( $review_data, $review_id );
		$data['reward_message'] = '';

		// Determine which email type to send.
		$email_type = ( 'approved' === $new_status ) ? 'review_approve' : 'review_reject';

		EmailSender::send( $email_type, $recipient, $data );
	}

	/**
	 * Send a reward-bearing review approval email.
	 *
	 * @param array $payload Reward payload.
	 * @return void
	 */
	public function on_reward_review_approved( $payload ) {
		$payload       = is_array( $payload ) ? $payload : array();
		$user_id       = absint( $payload['user_id'] ?? 0 );
		$review_id     = absint( $payload['review_id'] ?? 0 );
		$points_awarded = absint( $payload['points_awarded'] ?? 0 );
		$recipient     = $this->get_registered_user_email( $user_id );

		if ( $user_id <= 0 || $review_id <= 0 || $points_awarded <= 0 || '' === $recipient ) {
			return;
		}

		$review = $this->get_review_data_from_payload( $payload, $review_id );
		if ( empty( $review ) ) {
			return;
		}

		$data = EmailPlaceholders::build_review_reward_data( $review, $review_id, $user_id, $points_awarded );
		EmailSender::send( 'review_approve', $recipient, $data );
	}

	/**
	 * Send a featured review reward email.
	 *
	 * @param array $payload Reward payload.
	 * @return void
	 */
	public function on_reward_review_featured( $payload ) {
		$payload       = is_array( $payload ) ? $payload : array();
		$user_id       = absint( $payload['user_id'] ?? 0 );
		$review_id     = absint( $payload['review_id'] ?? 0 );
		$points_awarded = absint( $payload['points_awarded'] ?? 0 );
		$recipient     = $this->get_registered_user_email( $user_id );

		if ( $user_id <= 0 || $review_id <= 0 || $points_awarded <= 0 || '' === $recipient ) {
			return;
		}

		$review = $this->get_review_data_from_payload( $payload, $review_id );
		if ( empty( $review ) ) {
			return;
		}

		$data = EmailPlaceholders::build_featured_reward_data( $review, $review_id, $user_id, $points_awarded );
		EmailSender::send( 'review_featured', $recipient, $data );
	}

	/**
	 * Send a lightbox purchase reward email.
	 *
	 * @param array $payload Reward payload.
	 * @return void
	 */
	public function on_reward_lightbox_purchase( $payload ) {
		$payload       = is_array( $payload ) ? $payload : array();
		$user_id       = absint( $payload['user_id'] ?? 0 );
		$review_id     = absint( $payload['review_id'] ?? 0 );
		$order_id      = absint( $payload['order_id'] ?? 0 );
		$points_awarded = absint( $payload['points_awarded'] ?? 0 );
		$recipient     = $this->get_registered_user_email( $user_id );

		if ( $user_id <= 0 || $review_id <= 0 || $points_awarded <= 0 || '' === $recipient ) {
			return;
		}

		$review = $this->get_review_data_from_payload( $payload, $review_id );
		if ( empty( $review ) ) {
			return;
		}

		$data = EmailPlaceholders::build_lightbox_purchase_reward_data( $review, $review_id, $user_id, $order_id, $points_awarded );
		EmailSender::send( 'lightbox_purchase', $recipient, $data );
	}

	/**
	 * Send a points redeemed email.
	 *
	 * @param array $payload Redemption payload.
	 * @return void
	 */
	public function on_reward_points_redeemed( $payload ) {
		$payload         = is_array( $payload ) ? $payload : array();
		$user_id         = absint( $payload['user_id'] ?? 0 );
		$points_redeemed = absint( $payload['points_redeemed'] ?? 0 );
		$description     = (string) ( $payload['description'] ?? '' );
		$meta            = isset( $payload['meta'] ) && is_array( $payload['meta'] ) ? $payload['meta'] : array();
		$recipient       = $this->get_registered_user_email( $user_id );

		if ( $user_id <= 0 || $points_redeemed <= 0 || '' === $recipient ) {
			return;
		}

		$data = EmailPlaceholders::build_points_redeemed_data( $user_id, $points_redeemed, $description, $meta );
		EmailSender::send( 'points_redeemed', $recipient, $data );
	}

	/**
	 * Send a badge gain or upgrade email.
	 *
	 * @param array $payload Badge update payload.
	 * @return void
	 */
	public function on_badge_updated( $payload ) {
		$payload   = is_array( $payload ) ? $payload : array();
		$user_id   = absint( $payload['user_id'] ?? 0 );
		$recipient = $this->get_registered_user_email( $user_id );
		$change    = strtolower( (string) ( $payload['change_type'] ?? '' ) );

		if ( $user_id <= 0 || '' === $recipient || ! in_array( $change, array( 'gained', 'upgraded' ), true ) ) {
			return;
		}

		if ( '' === trim( (string) ( $payload['current_badge'] ?? '' ) ) ) {
			return;
		}

		$data = EmailPlaceholders::build_badge_update_data( $user_id, $payload );
		EmailSender::send( 'badge_update', $recipient, $data );
	}

	/**
	 * Load review data from an event payload or repository fallback.
	 *
	 * @param array $payload   Event payload.
	 * @param int   $review_id Review ID.
	 * @return array
	 */
	private function get_review_data_from_payload( array $payload, int $review_id ): array {
		if ( ! empty( $payload['review'] ) && is_array( $payload['review'] ) ) {
			return $payload['review'];
		}

		$repository = new \Ugcify\Database\ReviewRepository();
		$review     = $repository->find( $review_id );

		return $review ? $review->to_array() : array();
	}

	/**
	 * Resolve a registered user's email address.
	 *
	 * @param int $user_id WordPress user ID.
	 * @return string
	 */
	private function get_registered_user_email( int $user_id ): string {
		if ( $user_id <= 0 ) {
			return '';
		}

		$user = get_user_by( 'id', $user_id );
		return $user ? (string) $user->user_email : '';
	}

}
