<?php
/**
 * Pro automation, coupons, reports, and exports.
 *
 * @package FailedOrderRescueForWooCommerce
 */

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

class FORD_Pro {
	const HOOK_RECOVERY = 'ford_pro_run_recovery_sequence';
	const HOOK_REPORT   = 'ford_pro_send_weekly_report';

	/**
	 * Initialize Pro hooks.
	 *
	 * @return void
	 */
	public static function init() {
		add_filter( 'cron_schedules', array( __CLASS__, 'add_cron_schedules' ) );
		add_action( self::HOOK_RECOVERY, array( __CLASS__, 'run_recovery_sequence' ) );
		add_action( self::HOOK_REPORT, array( __CLASS__, 'send_weekly_report' ) );
		add_action( 'admin_post_ford_export_orders', array( __CLASS__, 'handle_export' ) );
		add_action( 'woocommerce_order_status_changed', array( __CLASS__, 'maybe_send_high_value_alert' ), 20, 4 );
	}

	/**
	 * Add weekly cron schedule.
	 *
	 * @param array $schedules Existing schedules.
	 * @return array
	 */
	public static function add_cron_schedules( $schedules ) {
		if ( ! isset( $schedules['weekly'] ) ) {
			$schedules['weekly'] = array(
				'interval' => WEEK_IN_SECONDS,
				'display'  => __( 'Once Weekly', 'failed-order-rescue-for-woocommerce' ),
			);
		}

		return $schedules;
	}

	/**
	 * Schedule cron jobs.
	 *
	 * @return void
	 */
	public static function activate() {
		add_filter( 'cron_schedules', array( __CLASS__, 'add_cron_schedules' ) );

		if ( ! wp_next_scheduled( self::HOOK_RECOVERY ) ) {
			wp_schedule_event( time() + HOUR_IN_SECONDS, 'hourly', self::HOOK_RECOVERY );
		}

		if ( ! wp_next_scheduled( self::HOOK_REPORT ) ) {
			wp_schedule_event( time() + DAY_IN_SECONDS, 'weekly', self::HOOK_REPORT );
		}
	}

	/**
	 * Clear cron jobs.
	 *
	 * @return void
	 */
	public static function deactivate() {
		wp_clear_scheduled_hook( self::HOOK_RECOVERY );
		wp_clear_scheduled_hook( self::HOOK_REPORT );
	}

	/**
	 * Whether Pro features are unlocked.
	 *
	 * @return bool
	 */
	public static function can_use() {
		return function_exists( 'ford_is_pro_active' ) && ford_is_pro_active();
	}

	/**
	 * Pro default settings.
	 *
	 * @return array
	 */
	public static function defaults() {
		return array(
			'pro_automation_enabled'       => 'no',
			'pro_sequence_1_delay'         => 30,
			'pro_sequence_2_delay'         => 360,
			'pro_sequence_3_delay'         => 1440,
			'pro_allowed_gateways'         => array(),
			'pro_coupon_enabled'           => 'no',
			'pro_coupon_percent'           => 5,
			'pro_coupon_min_total'         => 50,
			'pro_high_value_alert_enabled' => 'yes',
			'pro_high_value_threshold'     => 200,
			'pro_weekly_report_enabled'    => 'yes',
			'pro_report_email'             => get_option( 'admin_email' ),
		);
	}

	/**
	 * Sanitize Pro settings.
	 *
	 * @param array $output Existing sanitized output.
	 * @param array  $input Unsanitized input.
	 * @param string $context Settings form context.
	 * @return array
	 */
	public static function sanitize_settings( $output, $input, $context = 'general' ) {
		$defaults = self::defaults();

		if ( 'automation' === $context ) {
			$output['pro_automation_enabled'] = isset( $input['pro_automation_enabled'] ) && 'yes' === $input['pro_automation_enabled'] ? 'yes' : 'no';
			$output['pro_sequence_1_delay']   = isset( $input['pro_sequence_1_delay'] ) ? max( 5, absint( $input['pro_sequence_1_delay'] ) ) : $defaults['pro_sequence_1_delay'];
			$output['pro_sequence_2_delay']   = isset( $input['pro_sequence_2_delay'] ) ? max( 10, absint( $input['pro_sequence_2_delay'] ) ) : $defaults['pro_sequence_2_delay'];
			$output['pro_sequence_3_delay']   = isset( $input['pro_sequence_3_delay'] ) ? max( 15, absint( $input['pro_sequence_3_delay'] ) ) : $defaults['pro_sequence_3_delay'];

			$gateways = isset( $input['pro_allowed_gateways'] ) && is_array( $input['pro_allowed_gateways'] ) ? $input['pro_allowed_gateways'] : array();
			$output['pro_allowed_gateways'] = array_values( array_filter( array_map( 'sanitize_key', $gateways ) ) );

			$output['pro_coupon_enabled']   = isset( $input['pro_coupon_enabled'] ) && 'yes' === $input['pro_coupon_enabled'] ? 'yes' : 'no';
			$output['pro_coupon_percent']   = isset( $input['pro_coupon_percent'] ) ? min( 50, max( 1, absint( $input['pro_coupon_percent'] ) ) ) : $defaults['pro_coupon_percent'];
			$output['pro_coupon_min_total'] = isset( $input['pro_coupon_min_total'] ) ? max( 0, floatval( $input['pro_coupon_min_total'] ) ) : $defaults['pro_coupon_min_total'];
		}

		if ( 'reports' === $context ) {
			$output['pro_high_value_alert_enabled'] = isset( $input['pro_high_value_alert_enabled'] ) && 'yes' === $input['pro_high_value_alert_enabled'] ? 'yes' : 'no';
			$output['pro_high_value_threshold']     = isset( $input['pro_high_value_threshold'] ) ? max( 0, floatval( $input['pro_high_value_threshold'] ) ) : $defaults['pro_high_value_threshold'];
			$output['pro_weekly_report_enabled']    = isset( $input['pro_weekly_report_enabled'] ) && 'yes' === $input['pro_weekly_report_enabled'] ? 'yes' : 'no';
			$output['pro_report_email']             = isset( $input['pro_report_email'] ) ? sanitize_email( wp_unslash( $input['pro_report_email'] ) ) : $defaults['pro_report_email'];
		}

		return $output;
	}

	/**
	 * Run scheduled recovery automation.
	 *
	 * @return void
	 */
	public static function run_recovery_sequence() {
		if ( ! self::can_use() || 'yes' !== FORD_Settings::get( 'pro_automation_enabled' ) ) {
			return;
		}

		$orders = FORD_Orders::get_recoverable_orders( 100 );

		foreach ( $orders as $order ) {
			if ( ! $order instanceof WC_Order ) {
				continue;
			}

			if ( self::has_successful_retry( $order ) || ! self::gateway_allowed( $order ) ) {
				continue;
			}

			self::maybe_apply_coupon( $order );
			self::send_due_sequence_email( $order );
		}
	}

	/**
	 * Send due sequence email.
	 *
	 * @param WC_Order $order Order.
	 * @return void
	 */
	private static function send_due_sequence_email( $order ) {
		$created = $order->get_date_created();

		if ( ! $created ) {
			return;
		}

		$age_minutes = ( time() - $created->getTimestamp() ) / MINUTE_IN_SECONDS;
		$steps = array(
			1 => absint( FORD_Settings::get( 'pro_sequence_1_delay' ) ),
			2 => absint( FORD_Settings::get( 'pro_sequence_2_delay' ) ),
			3 => absint( FORD_Settings::get( 'pro_sequence_3_delay' ) ),
		);

		foreach ( $steps as $step => $delay ) {
			$meta_key = '_ford_pro_sequence_' . $step . '_sent_at';

			if ( $age_minutes >= $delay && ! $order->get_meta( $meta_key, true ) ) {
				$sent = FORD_Email::send_recovery_email( $order->get_id(), 'automation', $step );

				if ( $sent ) {
					$order->update_meta_data( $meta_key, current_time( 'mysql' ) );
					$order->save();
				}

				break;
			}
		}
	}

	/**
	 * Check whether the order payment gateway is enabled for automation.
	 *
	 * @param WC_Order $order Order.
	 * @return bool
	 */
	private static function gateway_allowed( $order ) {
		$allowed = (array) FORD_Settings::get( 'pro_allowed_gateways' );

		return empty( $allowed ) || in_array( $order->get_payment_method(), $allowed, true );
	}

	/**
	 * Detect whether customer already completed another order after this one.
	 *
	 * @param WC_Order $order Order.
	 * @return bool
	 */
	private static function has_successful_retry( $order ) {
		$email = $order->get_billing_email();

		if ( ! is_email( $email ) || ! function_exists( 'wc_get_orders' ) ) {
			return false;
		}

		$created = $order->get_date_created();
		$orders  = wc_get_orders(
			array(
				'limit'         => 1,
				'status'        => array( 'processing', 'completed' ),
				'billing_email' => $email,
				'exclude'       => array( $order->get_id() ),
				'date_created'  => $created ? '>' . gmdate( 'Y-m-d H:i:s', $created->getTimestamp() ) : '',
				'return'        => 'ids',
			)
		);

		return ! empty( $orders );
	}

	/**
	 * Apply recovery coupon to an order when configured.
	 *
	 * @param WC_Order $order Order.
	 * @return void
	 */
	private static function maybe_apply_coupon( $order ) {
		if ( 'yes' !== FORD_Settings::get( 'pro_coupon_enabled' ) ) {
			return;
		}

		if ( $order->get_meta( '_ford_pro_coupon_code', true ) || (float) $order->get_total() < (float) FORD_Settings::get( 'pro_coupon_min_total' ) ) {
			return;
		}

		$percent = absint( FORD_Settings::get( 'pro_coupon_percent' ) );
		$code    = 'FORD-' . $order->get_id() . '-' . wp_generate_password( 6, false, false );
		$coupon  = new WC_Coupon();

		$coupon->set_code( $code );
		$coupon->set_discount_type( 'percent' );
		$coupon->set_amount( $percent );
		$coupon->set_usage_limit( 1 );
		$coupon->set_email_restrictions( array_filter( array( $order->get_billing_email() ) ) );
		$coupon->save();

		try {
			$order->apply_coupon( $code );
			$order->calculate_totals( false );
			$order->update_meta_data( '_ford_pro_coupon_code', $code );
			$order->add_order_note( sprintf( 'Failed Order Rescue Pro applied recovery coupon %s.', $code ) );
			$order->save();
		} catch ( Exception $exception ) {
			$order->add_order_note( 'Failed Order Rescue Pro could not apply recovery coupon: ' . $exception->getMessage() );
			$order->save();
		}
	}

	/**
	 * Send admin alert for high-value failed or pending orders.
	 *
	 * @param int      $order_id Order ID.
	 * @param string   $old_status Old status.
	 * @param string   $new_status New status.
	 * @param WC_Order $order Order.
	 * @return void
	 */
	public static function maybe_send_high_value_alert( $order_id, $old_status, $new_status, $order ) {
		if ( ! self::can_use() || 'yes' !== FORD_Settings::get( 'pro_high_value_alert_enabled' ) || ! $order instanceof WC_Order ) {
			return;
		}

		if ( ! in_array( $new_status, FORD_Orders::recoverable_statuses(), true ) || $order->get_meta( '_ford_pro_high_value_alert_sent', true ) ) {
			return;
		}

		if ( (float) $order->get_total() < (float) FORD_Settings::get( 'pro_high_value_threshold' ) ) {
			return;
		}

		$to      = self::report_email();
		$subject = sprintf( __( 'High-value order needs recovery: #%s', 'failed-order-rescue-for-woocommerce' ), $order->get_order_number() );
		$message = sprintf(
			"Order #%s is now %s.\n\nTotal: %s\nCustomer: %s\nEdit order: %s",
			$order->get_order_number(),
			wc_get_order_status_name( $new_status ),
			wp_strip_all_tags( $order->get_formatted_order_total() ),
			$order->get_billing_email(),
			$order->get_edit_order_url()
		);

		if ( wp_mail( $to, $subject, $message ) ) {
			$order->update_meta_data( '_ford_pro_high_value_alert_sent', current_time( 'mysql' ) );
			$order->save();
		}
	}

	/**
	 * Send weekly admin report.
	 *
	 * @return void
	 */
	public static function send_weekly_report() {
		if ( ! self::can_use() || 'yes' !== FORD_Settings::get( 'pro_weekly_report_enabled' ) ) {
			return;
		}

		$stats = FORD_Orders::get_dashboard_stats();
		$body  = "Failed Order Rescue Pro weekly report\n\n";
		$body .= 'Recoverable orders: ' . number_format_i18n( $stats['recoverable_count'] ) . "\n";
		$body .= 'Lost revenue: ' . wp_strip_all_tags( wc_price( $stats['lost_revenue'] ) ) . "\n";
		$body .= 'Recovered orders: ' . number_format_i18n( $stats['recovered_count'] ) . "\n";
		$body .= 'Recovered revenue: ' . wp_strip_all_tags( wc_price( $stats['recovered_revenue'] ) ) . "\n";

		wp_mail( self::report_email(), __( 'Failed Order Rescue Pro weekly report', 'failed-order-rescue-for-woocommerce' ), $body );
	}

	/**
	 * Export orders CSV.
	 *
	 * @return void
	 */
	public static function handle_export() {
		if ( ! current_user_can( 'manage_woocommerce' ) ) {
			wp_die( esc_html__( 'You do not have permission to export orders.', 'failed-order-rescue-for-woocommerce' ) );
		}

		check_admin_referer( 'ford_export_orders' );

		if ( ! self::can_use() ) {
			wp_die( esc_html__( 'A valid Pro license or trial is required to export orders.', 'failed-order-rescue-for-woocommerce' ) );
		}

		$orders = FORD_Orders::get_recoverable_orders( 500 );

		nocache_headers();
		header( 'Content-Type: text/csv; charset=utf-8' );
		header( 'Content-Disposition: attachment; filename=failed-order-rescue-export-' . gmdate( 'Y-m-d' ) . '.csv' );

		$out = fopen( 'php://output', 'w' );
		fputcsv( $out, array( 'Order', 'Email', 'Status', 'Total', 'Payment Method', 'Last Recovery Email', 'Recovered' ) );

		foreach ( $orders as $order ) {
			if ( $order instanceof WC_Order ) {
				fputcsv(
					$out,
					array(
						$order->get_order_number(),
						$order->get_billing_email(),
						$order->get_status(),
						$order->get_total(),
						$order->get_payment_method_title(),
						$order->get_meta( '_ford_recovery_email_sent_at', true ),
						$order->get_meta( '_ford_recovered_via_plugin', true ),
					)
				);
			}
		}

		fclose( $out );
		exit;
	}

	/**
	 * Render locked Pro panel.
	 *
	 * @return void
	 */
	public static function render_locked_panel() {
		echo '<div class="ford-panel ford-pro-locked">';
		echo '<h2>' . esc_html__( 'Pro features are locked', 'failed-order-rescue-for-woocommerce' ) . '</h2>';
		echo '<p>' . esc_html__( 'Start a 7-day trial or activate a Pro license to use automation, coupons, reports, and exports.', 'failed-order-rescue-for-woocommerce' ) . '</p>';
		echo '<p><a class="button button-primary" href="' . esc_url( ford_get_upgrade_url() ) . '">' . esc_html__( 'Start Pro Trial', 'failed-order-rescue-for-woocommerce' ) . '</a></p>';
		echo '</div>';
	}

	/**
	 * Render automation settings.
	 *
	 * @return void
	 */
	public static function render_automation_settings() {
		if ( ! self::can_use() ) {
			self::render_locked_panel();
			return;
		}

		$settings = FORD_Settings::get_all();
		$gateways = WC()->payment_gateways() ? WC()->payment_gateways()->payment_gateways() : array();

		echo '<form method="post" action="' . esc_url( admin_url( 'options.php' ) ) . '" class="ford-settings-form">';
		settings_fields( 'ford_settings_group' );
		echo '<input type="hidden" name="ford_settings[settings_context]" value="automation">';
		echo '<table class="form-table" role="presentation"><tbody>';
		echo '<tr><th scope="row">' . esc_html__( 'Automation', 'failed-order-rescue-for-woocommerce' ) . '</th><td><label><input type="checkbox" name="ford_settings[pro_automation_enabled]" value="yes" ' . checked( 'yes', $settings['pro_automation_enabled'], false ) . '> ' . esc_html__( 'Enable automatic recovery sequence', 'failed-order-rescue-for-woocommerce' ) . '</label></td></tr>';
		echo '<tr><th scope="row">' . esc_html__( 'Email sequence delays', 'failed-order-rescue-for-woocommerce' ) . '</th><td>';
		echo '<label>' . esc_html__( 'Email 1 minutes', 'failed-order-rescue-for-woocommerce' ) . ' <input type="number" min="5" name="ford_settings[pro_sequence_1_delay]" value="' . esc_attr( $settings['pro_sequence_1_delay'] ) . '"></label> ';
		echo '<label>' . esc_html__( 'Email 2 minutes', 'failed-order-rescue-for-woocommerce' ) . ' <input type="number" min="10" name="ford_settings[pro_sequence_2_delay]" value="' . esc_attr( $settings['pro_sequence_2_delay'] ) . '"></label> ';
		echo '<label>' . esc_html__( 'Email 3 minutes', 'failed-order-rescue-for-woocommerce' ) . ' <input type="number" min="15" name="ford_settings[pro_sequence_3_delay]" value="' . esc_attr( $settings['pro_sequence_3_delay'] ) . '"></label>';
		echo '</td></tr>';
		echo '<tr><th scope="row">' . esc_html__( 'Payment gateways', 'failed-order-rescue-for-woocommerce' ) . '</th><td>';
		foreach ( $gateways as $gateway ) {
			echo '<label class="ford-checkbox"><input type="checkbox" name="ford_settings[pro_allowed_gateways][]" value="' . esc_attr( $gateway->id ) . '" ' . checked( in_array( $gateway->id, (array) $settings['pro_allowed_gateways'], true ), true, false ) . '> ' . esc_html( $gateway->get_title() ) . '</label>';
		}
		echo '<p class="description">' . esc_html__( 'Leave all unchecked to allow every payment gateway.', 'failed-order-rescue-for-woocommerce' ) . '</p></td></tr>';
		echo '<tr><th scope="row">' . esc_html__( 'Recovery coupon', 'failed-order-rescue-for-woocommerce' ) . '</th><td><label><input type="checkbox" name="ford_settings[pro_coupon_enabled]" value="yes" ' . checked( 'yes', $settings['pro_coupon_enabled'], false ) . '> ' . esc_html__( 'Apply one-time percent coupon before automated recovery email', 'failed-order-rescue-for-woocommerce' ) . '</label><br>';
		echo '<label>' . esc_html__( 'Discount percent', 'failed-order-rescue-for-woocommerce' ) . ' <input type="number" min="1" max="50" name="ford_settings[pro_coupon_percent]" value="' . esc_attr( $settings['pro_coupon_percent'] ) . '"></label> ';
		echo '<label>' . esc_html__( 'Minimum order total', 'failed-order-rescue-for-woocommerce' ) . ' <input type="number" min="0" step="0.01" name="ford_settings[pro_coupon_min_total]" value="' . esc_attr( $settings['pro_coupon_min_total'] ) . '"></label></td></tr>';
		echo '</tbody></table>';
		submit_button();
		echo '</form>';
	}

	/**
	 * Render reports settings and summary.
	 *
	 * @return void
	 */
	public static function render_reports() {
		if ( ! self::can_use() ) {
			self::render_locked_panel();
			return;
		}

		$settings = FORD_Settings::get_all();
		$stats    = FORD_Orders::get_dashboard_stats();

		echo '<div class="ford-stat-grid">';
		FORD_Admin::render_public_stat_card( __( 'Recovered Revenue', 'failed-order-rescue-for-woocommerce' ), wc_price( $stats['recovered_revenue'] ), __( 'Revenue recovered by recovery workflows.', 'failed-order-rescue-for-woocommerce' ) );
		FORD_Admin::render_public_stat_card( __( 'Recoverable Orders', 'failed-order-rescue-for-woocommerce' ), number_format_i18n( $stats['recoverable_count'] ), __( 'Orders still waiting for recovery.', 'failed-order-rescue-for-woocommerce' ) );
		FORD_Admin::render_public_stat_card( __( 'Recovered Count', 'failed-order-rescue-for-woocommerce' ), number_format_i18n( $stats['recovered_count'] ), __( 'Recovered orders in the last 30 days.', 'failed-order-rescue-for-woocommerce' ) );
		echo '</div>';

		echo '<form method="post" action="' . esc_url( admin_url( 'options.php' ) ) . '" class="ford-settings-form ford-panel">';
		settings_fields( 'ford_settings_group' );
		echo '<input type="hidden" name="ford_settings[settings_context]" value="reports">';
		echo '<h2>' . esc_html__( 'Weekly report', 'failed-order-rescue-for-woocommerce' ) . '</h2>';
		echo '<p><label><input type="checkbox" name="ford_settings[pro_weekly_report_enabled]" value="yes" ' . checked( 'yes', $settings['pro_weekly_report_enabled'], false ) . '> ' . esc_html__( 'Send weekly recovered revenue report', 'failed-order-rescue-for-woocommerce' ) . '</label></p>';
		echo '<p><label>' . esc_html__( 'Report email', 'failed-order-rescue-for-woocommerce' ) . ' <input type="email" class="regular-text" name="ford_settings[pro_report_email]" value="' . esc_attr( $settings['pro_report_email'] ) . '"></label></p>';
		echo '<p><label><input type="checkbox" name="ford_settings[pro_high_value_alert_enabled]" value="yes" ' . checked( 'yes', $settings['pro_high_value_alert_enabled'], false ) . '> ' . esc_html__( 'Send high-value failed order alerts', 'failed-order-rescue-for-woocommerce' ) . '</label></p>';
		echo '<p><label>' . esc_html__( 'High-value threshold', 'failed-order-rescue-for-woocommerce' ) . ' <input type="number" min="0" step="0.01" name="ford_settings[pro_high_value_threshold]" value="' . esc_attr( $settings['pro_high_value_threshold'] ) . '"></label></p>';
		submit_button();
		echo '</form>';
	}

	/**
	 * Render export page.
	 *
	 * @return void
	 */
	public static function render_export() {
		if ( ! self::can_use() ) {
			self::render_locked_panel();
			return;
		}

		$url = wp_nonce_url( admin_url( 'admin-post.php?action=ford_export_orders' ), 'ford_export_orders' );
		echo '<div class="ford-panel">';
		echo '<h2>' . esc_html__( 'CSV Export', 'failed-order-rescue-for-woocommerce' ) . '</h2>';
		echo '<p>' . esc_html__( 'Export recoverable failed and pending orders with payment method, total, last email, and recovery status.', 'failed-order-rescue-for-woocommerce' ) . '</p>';
		echo '<p><a class="button button-primary" href="' . esc_url( $url ) . '">' . esc_html__( 'Download CSV', 'failed-order-rescue-for-woocommerce' ) . '</a></p>';
		echo '</div>';
	}

	/**
	 * Report recipient.
	 *
	 * @return string
	 */
	private static function report_email() {
		$email = FORD_Settings::get( 'pro_report_email' );

		return is_email( $email ) ? $email : get_option( 'admin_email' );
	}
}
