<?php

namespace SugarCalendarBookings\Integrations\OAuthRelay;

use SugarCalendarBookings\Support\Helpers\Date;

/**
 * Abstract OAuth Connection.
 *
 * Default implementation of OAuthConnectionInterface.
 * Wraps OAuthConnectionModel with configurable expiration buffer.
 *
 * @since 1.4.0
 */
abstract class AbstractOAuthConnection implements OAuthConnectionInterface {

	/**
	 * Seconds before expiration to trigger refresh.
	 * Override in subclasses for provider-specific buffers.
	 *
	 * @since 1.4.0
	 *
	 * @var int
	 */
	protected int $expiration_buffer = 300; // 5 minutes default.

	/**
	 * The underlying connection model.
	 *
	 * @since 1.4.0
	 *
	 * @var OAuthConnectionModel
	 */
	protected OAuthConnectionModel $model;

	/**
	 * Constructor.
	 *
	 * @since 1.4.0
	 *
	 * @param OAuthConnectionModel $model The connection model.
	 */
	public function __construct( OAuthConnectionModel $model ) {

		$this->model = $model;
	}

	/**
	 * Check if token is expiring soon and needs refresh.
	 *
	 * @since 1.4.0
	 *
	 * @return bool
	 */
	public function is_expiring_soon(): bool {

		$expires_at = $this->model->expires_at;

		if ( empty( $expires_at ) ) {
			return true;
		}

		$threshold_time = Date::create()->getTimestamp() + $this->expiration_buffer;

		return $threshold_time >= $expires_at->getTimestamp();
	}

	/**
	 * Get the encrypted access token.
	 *
	 * @since 1.4.0
	 *
	 * @return string
	 */
	public function get_access_token(): string {

		return $this->model->access_token;
	}

	/**
	 * Get the encrypted refresh token.
	 *
	 * @since 1.4.0
	 *
	 * @return string
	 */
	public function get_refresh_token(): string {

		return $this->model->refresh_token;
	}

	/**
	 * Get the OAuth app ID for token refresh.
	 *
	 * @since 1.4.0
	 *
	 * @return int
	 */
	public function get_app_id(): int {

		return $this->model->app_id;
	}

	/**
	 * Update tokens after refresh.
	 *
	 * Restores status to 'active' if the connection was previously in error,
	 * since a successful refresh means the connection is healthy again.
	 *
	 * @since 1.4.0
	 *
	 * @param array $token_data Token data from refresh response.
	 */
	public function update_tokens( array $token_data ): void {

		$this->model->access_token = $token_data['access_token'];
		$this->model->expires_at   = gmdate( 'Y-m-d H:i:s', time() + $token_data['expires_in'] );
		$this->model->refreshed_at = current_time( 'mysql', true );

		// Refresh token is not always returned (e.g., Google only returns it on initial auth).
		if ( ! empty( $token_data['refresh_token'] ) ) {
			$this->model->refresh_token = $token_data['refresh_token'];
		}

		// Restore active status if previously in error.
		if ( $this->model->status === 'auth_error' ) {
			$this->model->status = 'active';
		}

		$this->model->save();
	}

	/**
	 * Mark the connection as having an authentication error.
	 *
	 * @since 1.4.0
	 */
	public function mark_auth_error(): void {

		$this->model->status = 'auth_error';

		$this->model->save();
	}

	/**
	 * Get the underlying model.
	 *
	 * @since 1.4.0
	 *
	 * @return OAuthConnectionModel
	 */
	public function get_model(): OAuthConnectionModel {

		return $this->model;
	}
}
