<?php
/**
 * Persistent, one-time Google Calendar OAuth state storage.
 *
 * @package Niwa_AI
 */

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

class Niwa_AI_Calendar_OAuth_State {

	const OPTION_PREFIX = 'niwa_ai_google_calendar_state_';
	const LIFETIME      = 600;

	/** Store one OAuth flow outside object-cache-backed transients. */
	public static function create( array $flow ) {
		$state              = Niwa_AI_Calendar_Credentials::random_token( 24 );
		$flow['expires_at'] = time() + self::LIFETIME;
		return add_option( self::key( $state ), $flow, '', false )
			? $state
			: new WP_Error( 'calendar_state_store_failed', __( 'The Google Calendar connection could not be started. Please try again.', 'niwa-ai' ) );
	}

	/** Atomically claim, remove, and return one unexpired OAuth flow. */
	public static function consume( $state ) {
		$state = (string) $state;
		if ( 1 !== preg_match( '/^[A-Za-z0-9_-]{32}$/', $state ) ) {
			return false;
		}

		$key       = self::key( $state );
		$claim_key = $key . '_claim';
		$claimed   = (int) get_option( $claim_key, 0 );
		if ( $claimed > 0 && $claimed < time() ) {
			delete_option( $claim_key );
		}
		if ( ! add_option( $claim_key, time() + self::LIFETIME, '', false ) ) {
			return false;
		}

		$flow = get_option( $key, false );
		delete_option( $key );
		delete_option( $claim_key );
		if ( ! is_array( $flow ) || empty( $flow['expires_at'] ) || (int) $flow['expires_at'] < time() ) {
			return false;
		}
		unset( $flow['expires_at'] );
		return $flow;
	}

	/** Remove a state when relay authorization cannot be started. */
	public static function delete( $state ) {
		$state = (string) $state;
		if ( 1 === preg_match( '/^[A-Za-z0-9_-]{32}$/', $state ) ) {
			$key = self::key( $state );
			delete_option( $key );
			delete_option( $key . '_claim' );
		}
	}

	private static function key( $state ) {
		return self::OPTION_PREFIX . hash( 'sha256', (string) $state );
	}
}
