<?php
/**
 * Marketing email consent storage and enforcement.
 *
 * @package CartCue
 */

namespace CartCue;

defined( 'ABSPATH' ) || exit;

final class MarketingConsent {

	public const USER_META_KEY  = 'cartcue_marketing_consent';
	public const ORDER_META_KEY = '_cartcue_marketing_consent';
	/** @deprecated 1.0.3 Migrated to ap_consents table. */
	public const GUEST_OPTION   = 'cartcue_marketing_consents';

	public static function init(): void {
		add_action( 'user_register', [ __CLASS__, 'on_user_register' ], 20, 1 );
	}

	/** Default settings merged into cartcue_settings. */
	public static function default_settings(): array {
		return [
			'consent_enabled'          => '0',
			'consent_enforce'          => '1',
			'consent_checkout'         => '1',
			'consent_checkout_blocks'  => '0',
			'consent_wp_register'      => '0',
			'consent_wc_register'      => '0',
			'consent_text'             => __( 'I agree to receive marketing emails from {{shop.name}}.', 'cartcue-sales-automation' ),
			'global_email_cap_enabled' => '0',
			'global_email_cap_count'   => '3',
			'global_email_cap_days'    => '7',
			'quiet_hours_enabled'      => '0',
			'quiet_hours_start'        => '21:00',
			'quiet_hours_end'          => '08:00',
		];
	}

	public static function get_settings(): array {
		$stored = get_option( 'cartcue_settings', [] );
		if ( ! is_array( $stored ) ) {
			$stored = [];
		}
		return array_merge( self::default_settings(), $stored );
	}

	public static function is_enabled(): bool {
		$s = self::get_settings();
		return '1' === (string) ( $s['consent_enabled'] ?? '0' );
	}

	public static function is_enforced(): bool {
		if ( ! self::is_enabled() ) {
			return false;
		}
		$s = self::get_settings();
		return '1' === (string) ( $s['consent_enforce'] ?? '1' );
	}

	public static function consent_label(): string {
		$s    = self::get_settings();
		$text = (string) ( $s['consent_text'] ?? '' );
		if ( '' === $text ) {
			$text = self::default_settings()['consent_text'];
		}
		return str_replace( '{{shop.name}}', get_bloginfo( 'name' ), $text );
	}

	/**
	 * Whether CartCue may send marketing email to this address.
	 */
	public static function can_send_to( string $email ): bool {
		$email = strtolower( trim( $email ) );
		if ( ! is_email( $email ) ) {
			return false;
		}

		if ( Unsubscribe::is_suppressed( $email ) ) {
			return false;
		}

		if ( ! self::is_enforced() ) {
			return true;
		}

		return self::has_consent( $email );
	}

	public static function has_consent( string $email ): bool {
		$email = strtolower( trim( $email ) );
		if ( ! is_email( $email ) ) {
			return false;
		}

		$user = get_user_by( 'email', $email );
		if ( $user ) {
			return '1' === (string) get_user_meta( $user->ID, self::USER_META_KEY, true );
		}

		global $wpdb;
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery
		$status = $wpdb->get_var(
			$wpdb->prepare(
				'SELECT status FROM %i WHERE email = %s',
				DB::consents(),
				$email
			)
		);

		return 1 === (int) $status;
	}

	public static function grant( string $email, string $source = 'unknown' ): void {
		$email = strtolower( trim( $email ) );
		if ( ! is_email( $email ) ) {
			return;
		}

		$user = get_user_by( 'email', $email );
		if ( $user ) {
			update_user_meta( $user->ID, self::USER_META_KEY, '1' );
			update_user_meta( $user->ID, 'cartcue_marketing_consent_at', current_time( 'mysql' ) );
			update_user_meta( $user->ID, 'cartcue_marketing_consent_source', sanitize_key( $source ) );
			return;
		}

		global $wpdb;
		$now = current_time( 'mysql' );
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery
		$wpdb->query(
			$wpdb->prepare(
				'INSERT INTO %i (email, status, source, granted_at)
				 VALUES (%s, 1, %s, %s)
				 ON DUPLICATE KEY UPDATE status = 1, source = %s, granted_at = %s',
				DB::consents(),
				$email,
				sanitize_key( $source ),
				$now,
				sanitize_key( $source ),
				$now
			)
		);
	}

	public static function revoke( string $email ): void {
		$email = strtolower( trim( $email ) );
		if ( ! is_email( $email ) ) {
			return;
		}

		$user = get_user_by( 'email', $email );
		if ( $user ) {
			update_user_meta( $user->ID, self::USER_META_KEY, '0' );
		}

		global $wpdb;
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery
		$wpdb->delete( DB::consents(), [ 'email' => $email ], [ '%s' ] );
	}

	/**
	 * One-time migration from wp_options guest consent array to ap_consents.
	 */
	public static function migrate_guest_consents(): void {
		$guests = get_option( self::GUEST_OPTION, [] );
		if ( ! is_array( $guests ) || empty( $guests ) ) {
			return;
		}

		foreach ( $guests as $email => $meta ) {
			if ( ! is_email( $email ) ) {
				continue;
			}
			$source = is_array( $meta ) ? (string) ( $meta['source'] ?? 'migrated' ) : 'migrated';
			self::grant( $email, $source );
		}

		delete_option( self::GUEST_OPTION );
	}

	public static function on_user_register( int $user_id ): void {
		if ( ! self::is_enabled() ) {
			return;
		}
		// phpcs:ignore WordPress.Security.NonceVerification.Missing
		if ( ! empty( $_POST['cartcue_marketing_consent'] ) ) {
			update_user_meta( $user_id, self::USER_META_KEY, '1' );
		}
	}

	/**
	 * Sum completed order totals for a billing email (guests + registered).
	 */
	public static function lifetime_spent_by_email( string $email ): float {
		$email = strtolower( trim( $email ) );
		if ( ! is_email( $email ) ) {
			return 0.0;
		}

		if ( class_exists( '\Automattic\WooCommerce\Utilities\OrderUtil' )
			&& \Automattic\WooCommerce\Utilities\OrderUtil::custom_orders_table_usage_is_enabled() ) {
			global $wpdb;
			$statuses   = array_map(
				static function ( $s ) {
					return 'wc-' . $s;
				},
				array_keys( wc_get_is_paid_statuses() )
			);
			$in_clause  = "'" . implode( "','", array_map( 'esc_sql', $statuses ) ) . "'";
			// phpcs:ignore WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- status list built from wc_get_is_paid_statuses().
			$total = $wpdb->get_var(
				$wpdb->prepare(
					"SELECT SUM(total_amount) FROM {$wpdb->prefix}wc_orders
					 WHERE billing_email = %s AND status IN ({$in_clause})", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- status list from wc_get_is_paid_statuses().
					$email
				)
			);
			return (float) ( $total ?? 0.0 );
		}

		$orders = wc_get_orders(
			[
				'billing_email' => $email,
				'status'        => array_keys( wc_get_is_paid_statuses() ),
				'limit'         => -1,
				'return'        => 'objects',
			]
		);

		$total = 0.0;
		foreach ( $orders as $order ) {
			$total += (float) $order->get_total();
		}

		return $total;
	}

	/**
	 * Days since last paid order for billing email; -1 if none.
	 */
	public static function days_since_last_order_by_email( string $email ): int {
		$email = strtolower( trim( $email ) );
		if ( ! is_email( $email ) ) {
			return -1;
		}

		$orders = wc_get_orders(
			[
				'billing_email' => $email,
				'status'        => array_keys( wc_get_is_paid_statuses() ),
				'limit'         => 1,
				'orderby'       => 'date',
				'order'         => 'DESC',
			]
		);

		if ( empty( $orders ) ) {
			return -1;
		}

		$order = $orders[0];
		$date  = $order->get_date_created();
		if ( ! $date ) {
			return -1;
		}

		return (int) floor( ( time() - $date->getTimestamp() ) / DAY_IN_SECONDS );
	}
}
