<?php
/**
 * Automatic payment reminder emails for unpaid WooCommerce orders (Pay for Order).
 *
 * @package SHC4WC
 */

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

class SHC4WC_Payment_Reminders {
	const CRON_HOOK              = 'shc4wc_payment_reminders_cron';
	const META_REMINDER_COUNT    = '_shc4wc_reminder_count';
	const META_REMINDER_ANCHOR   = '_shc4wc_reminder_anchor';
	const META_PAYMENT_LINK_SENT = '_shc4wc_payment_link_sent';

	/** @var self|null */
	private static $instance = null;

	public static function instance() {
		if ( null === self::$instance ) {
			self::$instance = new self();
			self::maybe_schedule_cron();
		}
		return self::$instance;
	}

	private function __construct() {
		if ( ! class_exists( 'WooCommerce' ) ) {
			return;
		}

		add_action( self::CRON_HOOK, array( $this, 'process_due_reminders' ) );
		add_action( 'woocommerce_checkout_order_processed', array( $this, 'maybe_anchor_new_order' ), 20, 1 );
		add_action( 'shc4wc_pay_for_order_email_sent', array( $this, 'mark_payment_link_sent' ) );
	}

	/**
	 * Schedule hourly cron.
	 */
	public static function maybe_schedule_cron() {
		if ( ! wp_next_scheduled( self::CRON_HOOK ) ) {
			wp_schedule_event( time() + 5 * MINUTE_IN_SECONDS, 'hourly', self::CRON_HOOK );
		}
	}

	/**
	 * Clear cron on plugin deactivation.
	 */
	public static function unschedule_cron() {
		$timestamp = wp_next_scheduled( self::CRON_HOOK );
		while ( $timestamp ) {
			wp_unschedule_event( $timestamp, self::CRON_HOOK );
			$timestamp = wp_next_scheduled( self::CRON_HOOK );
		}
	}

	/**
	 * @return array{enabled:bool,intervals:array<int,int>}
	 */
	public static function get_settings() {
		$raw     = get_option( 'woocommerce_shc4wc_settings', array() );
		$raw     = is_array( $raw ) ? $raw : array();
		$enabled = ! empty( $raw['payment_reminders'] ) && 'yes' === $raw['payment_reminders'];

		$defaults  = array(
			1 => 24,
			2 => 72,
			3 => 168,
		);
		$intervals = array();
		foreach ( array( 1, 2, 3 ) as $index ) {
			$key = 'payment_reminder_hours_' . $index;
			if ( array_key_exists( $key, $raw ) ) {
				$hrs = absint( $raw[ $key ] );
			} else {
				$hrs = $defaults[ $index ];
			}
			if ( $hrs > 0 ) {
				$intervals[] = $hrs;
			}
		}

		return array(
			'enabled'   => $enabled,
			'intervals' => $intervals,
		);
	}

	/**
	 * @return bool
	 */
	public static function is_enabled() {
		$settings = self::get_settings();
		return $settings['enabled'] && ! empty( $settings['intervals'] );
	}

	/**
	 * @param int $order_id Order ID.
	 */
	public function maybe_anchor_new_order( $order_id ) {
		$order = wc_get_order( $order_id );
		if ( ! $order instanceof WC_Order || ! $order->needs_payment() ) {
			return;
		}

		if ( 'shc4wc' !== $order->get_payment_method() ) {
			return;
		}

		self::ensure_reminder_anchor( $order );
	}

	/**
	 * @param WC_Order $order WooCommerce order.
	 */
	public function mark_payment_link_sent( $order ) {
		if ( ! $order instanceof WC_Order ) {
			return;
		}

		$order->update_meta_data( self::META_PAYMENT_LINK_SENT, 'yes' );
		self::ensure_reminder_anchor( $order );
		$order->save();
	}

	/**
	 * @param WC_Order $order WooCommerce order.
	 */
	public static function ensure_reminder_anchor( WC_Order $order ) {
		$anchor = (int) $order->get_meta( self::META_REMINDER_ANCHOR );
		if ( $anchor > 0 ) {
			return;
		}

		$created = $order->get_date_created();
		$anchor  = $created ? $created->getTimestamp() : time();
		$order->update_meta_data( self::META_REMINDER_ANCHOR, (string) $anchor );
		$order->save();
	}

	/**
	 * Hourly cron: send due payment reminders.
	 */
	public function process_due_reminders() {
		if ( ! self::is_enabled() || ! SHC4WC_Plugin::is_connected() ) {
			return;
		}

		$gateway_settings = get_option( 'woocommerce_shc4wc_settings', array() );
		if ( empty( $gateway_settings['enabled'] ) || 'yes' !== $gateway_settings['enabled'] ) {
			return;
		}

		$config = self::get_settings();
		$max    = count( $config['intervals'] );
		if ( $max <= 0 ) {
			return;
		}

		$max_hours = (int) max( $config['intervals'] );
		$since_ts  = time() - ( ( $max_hours * 3 ) + ( 48 * HOUR_IN_SECONDS ) );
		$since     = gmdate( 'Y-m-d H:i:s', $since_ts );

		$base_query = array(
			'limit'      => 100,
			'status'     => array( 'pending', 'on-hold' ),
			'date_after' => $since,
			'return'     => 'ids',
			'orderby'    => 'date',
			'order'      => 'ASC',
		);

		$order_ids = wc_get_orders(
			array_merge(
				$base_query,
				array(
					'payment_method' => 'shc4wc',
				)
			)
		);

		if ( empty( $order_ids ) ) {
			$order_ids = array();
		}

		// Admin-created orders may use another method until the payment link is sent.
		$link_sent_ids = wc_get_orders(
			array_merge(
				$base_query,
				array(
					'meta_key'   => self::META_PAYMENT_LINK_SENT,
					'meta_value' => 'yes',
				)
			)
		);

		foreach ( array_unique( array_merge( $order_ids, is_array( $link_sent_ids ) ? $link_sent_ids : array() ) ) as $order_id ) {
			$order = wc_get_order( (int) $order_id );
			if ( ! $order instanceof WC_Order ) {
				continue;
			}
			$this->maybe_send_reminder_for_order( $order, $config );
		}
	}

	/**
	 * @param WC_Order $order  WooCommerce order.
	 * @param array    $config Reminder settings.
	 */
	private function maybe_send_reminder_for_order( WC_Order $order, array $config ) {
		if ( ! $order->needs_payment() ) {
			return;
		}

		if ( '' === trim( (string) $order->get_billing_email() ) ) {
			return;
		}

		if ( 'shc4wc' !== $order->get_payment_method() && 'yes' !== (string) $order->get_meta( self::META_PAYMENT_LINK_SENT ) ) {
			return;
		}

		$sent_count = (int) $order->get_meta( self::META_REMINDER_COUNT );
		$intervals  = isset( $config['intervals'] ) && is_array( $config['intervals'] ) ? $config['intervals'] : array();
		if ( $sent_count >= count( $intervals ) ) {
			return;
		}

		self::ensure_reminder_anchor( $order );
		$anchor = (int) $order->get_meta( self::META_REMINDER_ANCHOR );
		if ( $anchor <= 0 ) {
			return;
		}

		$due_at = $anchor + ( (int) $intervals[ $sent_count ] * HOUR_IN_SECONDS );
		if ( time() < $due_at ) {
			return;
		}

		if ( 'shc4wc' !== $order->get_payment_method() ) {
			$order->set_payment_method( 'shc4wc' );
			$order->save();
		}

		$sent = SHC4WC_Pay_For_Order::email_payment_link_to_customer(
			$order,
			array(
				'is_reminder'      => true,
				'reminder_number'  => $sent_count + 1,
			)
		);

		if ( ! $sent ) {
			return;
		}

		$order->update_meta_data( self::META_REMINDER_COUNT, (string) ( $sent_count + 1 ) );
		$order->update_meta_data( self::META_REMINDER_ANCHOR, (string) time() );
		$order->add_order_note(
			sprintf(
				/* translators: %d: reminder sequence number. */
				__( 'Automatic Square payment reminder #%d emailed to customer.', 'payments-connect-square' ),
				$sent_count + 1
			)
		);
		$order->save();

		/**
		 * Fires after an automatic payment reminder email is sent.
		 *
		 * @param WC_Order $order           WooCommerce order.
		 * @param int      $reminder_number Reminder sequence (1-based).
		 */
		do_action( 'shc4wc_payment_reminder_sent', $order, $sent_count + 1 );
	}
}
