<?php
/**
 * The customer's own SMS preference.
 *
 * @package TextTango
 */

declare( strict_types=1 );

namespace TextTango\Consent;

use TextTango\Api\PhoneNumber;
use TextTango\Otp\UserRepository;
use WP_User;

defined( 'ABSPATH' ) || exit;

/**
 * Lets a customer change their mind, from their account or their profile
 * (spec §7, §22).
 *
 * Consent that cannot be withdrawn is not consent, and since no STOP text ever
 * reaches this site, a place to switch it off is the only reliable way for
 * somebody to stop marketing without waiting to be refused mid-send.
 *
 * Two surfaces, one preference: **My Account → Account details** for customers,
 * and the WordPress profile for anyone with admin access. Both write the same
 * record, with the source noting which was used.
 */
final class AccountPreference {

	/**
	 * Form field name, shared by both surfaces.
	 */
	public const FIELD = 'texttango_sms_optin';

	/**
	 * Nonce action for the WordPress profile form.
	 */
	private const PROFILE_NONCE = 'texttango_consent_profile';

	/**
	 * Register hooks.
	 */
	public function register(): void {
		add_action( 'woocommerce_edit_account_form', array( $this, 'render_account_field' ) );
		add_action( 'woocommerce_save_account_details', array( $this, 'save_account_field' ) );

		add_action( 'show_user_profile', array( $this, 'render_profile_field' ) );
		add_action( 'edit_user_profile', array( $this, 'render_profile_field' ) );
		add_action( 'personal_options_update', array( $this, 'save_profile_field' ) );
		add_action( 'edit_user_profile_update', array( $this, 'save_profile_field' ) );
	}

	/**
	 * The opt-in checkbox on My Account → Account details.
	 */
	public function render_account_field(): void {
		$user_id = get_current_user_id();

		if ( $user_id <= 0 ) {
			return;
		}

		$record = Consent::record_for( $user_id );
		?>
		<fieldset>
			<legend><?php esc_html_e( 'SMS preferences', 'texttango' ); ?></legend>
			<p class="woocommerce-form-row form-row">
				<label for="<?php echo esc_attr( self::FIELD ); ?>">
					<input
						type="checkbox"
						name="<?php echo esc_attr( self::FIELD ); ?>"
						id="<?php echo esc_attr( self::FIELD ); ?>"
						value="1"
						<?php checked( Consent::STATE_DENIED !== $record['state'] ); ?> />
					<?php echo esc_html( CheckoutConsent::label() ); ?>
				</label>
			</p>
			<?php if ( Consent::STATE_PENDING === $record['state'] ) : ?>
				<p class="woocommerce-form-row form-row">
					<small>
						<?php esc_html_e( 'We have texted you a link to confirm. Nothing marketing is sent until you open it.', 'texttango' ); ?>
					</small>
				</p>
			<?php endif; ?>
			<p class="woocommerce-form-row form-row">
				<small>
					<?php esc_html_e( 'Updates about orders you have placed are sent either way.', 'texttango' ); ?>
				</small>
			</p>
		</fieldset>
		<?php
	}

	/**
	 * Save the My Account checkbox.
	 *
	 * WooCommerce verifies its own nonce before firing this action.
	 *
	 * @param int $user_id User being saved.
	 */
	public function save_account_field( $user_id ): void {
		// phpcs:ignore WordPress.Security.NonceVerification.Missing -- WooCommerce verifies save-account-details before this action fires.
		Consent::record_for_user( (int) $user_id, isset( $_POST[ self::FIELD ] ), 'account' );
	}

	/**
	 * The preference, plus the consent trail, on the WordPress profile.
	 *
	 * @param WP_User $user User being edited.
	 */
	public function render_profile_field( WP_User $user ): void {
		$record     = Consent::record_for( $user->ID );
		$phone      = UserRepository::phone_for( $user->ID );
		$suppressed = '' !== $phone ? Suppressions::find( $phone ) : null;
		?>
		<table class="form-table" role="presentation">
			<tr>
				<th scope="row"><?php esc_html_e( 'SMS marketing', 'texttango' ); ?></th>
				<td>
					<label>
						<input type="checkbox" name="<?php echo esc_attr( self::FIELD ); ?>" value="1"
							<?php checked( Consent::STATE_DENIED !== $record['state'] ); ?> />
						<?php echo esc_html( CheckoutConsent::label() ); ?>
					</label>
					<?php if ( '' !== $record['at'] ) : ?>
						<p class="description">
							<?php
							printf(
								/* translators: 1: what was recorded, 2: date recorded, 3: where it was captured. */
								esc_html__( 'Recorded as %1$s on %2$s via %3$s.', 'texttango' ),
								esc_html( self::outcome_label( (string) $record['state'] ) ),
								esc_html( $record['at'] ),
								esc_html( '' !== $record['source'] ? $record['source'] : __( 'unknown', 'texttango' ) )
							);
							?>
						</p>
					<?php endif; ?>
					<?php if ( Consent::STATE_PENDING === $record['state'] ) : ?>
						<p class="description">
							<?php esc_html_e( 'A confirmation link has been texted to them. Marketing stays blocked, and nothing is synced to TextTango, until they open it. Ticking this box on their behalf would not be their consent, so it does not confirm for them.', 'texttango' ); ?>
						</p>
					<?php endif; ?>
					<p class="description">
						<?php esc_html_e( 'Order updates are service messages and send either way.', 'texttango' ); ?>
					</p>
				</td>
			</tr>
			<?php if ( null !== $suppressed ) : ?>
				<tr>
					<th scope="row"><?php esc_html_e( 'Opted out', 'texttango' ); ?></th>
					<td>
						<p>
							<?php
							printf(
								/* translators: 1: masked number, 2: date. */
								esc_html__( 'TextTango is refusing messages to %1$s since %2$s. Nothing is sent to this number, order updates included.', 'texttango' ),
								'<code>' . esc_html( PhoneNumber::mask( $phone ) ) . '</code>',
								esc_html( (string) $suppressed['created_at'] )
							);
							?>
						</p>
						<p class="description">
							<?php esc_html_e( 'This mirrors a refusal from the platform and cannot be cleared from WordPress. The customer has to opt back in with TextTango.', 'texttango' ); ?>
						</p>
					</td>
				</tr>
			<?php endif; ?>
		</table>
		<?php
		wp_nonce_field( self::PROFILE_NONCE, 'texttango_consent_nonce' );
	}

	/**
	 * How a state reads in the sentence describing what was recorded.
	 *
	 * @param string $state One of the Consent::STATE_* constants.
	 */
	private static function outcome_label( string $state ): string {
		if ( Consent::STATE_GRANTED === $state ) {
			return __( 'agreed', 'texttango' );
		}

		return Consent::STATE_PENDING === $state
			? __( 'asked for, unconfirmed', 'texttango' )
			: __( 'declined', 'texttango' );
	}

	/**
	 * Save the profile checkbox.
	 *
	 * @param int $user_id User being saved.
	 */
	public function save_profile_field( $user_id ): void {
		$user_id = (int) $user_id;

		if ( ! current_user_can( 'edit_user', $user_id ) ) {
			return;
		}

		$nonce = isset( $_POST['texttango_consent_nonce'] )
			? sanitize_text_field( wp_unslash( $_POST['texttango_consent_nonce'] ) )
			: '';

		if ( ! wp_verify_nonce( $nonce, self::PROFILE_NONCE ) ) {
			return;
		}

		$source = get_current_user_id() === $user_id ? 'profile' : 'admin';

		Consent::record_for_user( $user_id, isset( $_POST[ self::FIELD ] ), $source );
	}
}
