<?php
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

// phpcs:disable WordPress.Security.NonceVerification.Recommended, WordPress.Security.SafeRedirect.wp_redirect_wp_redirect
// Justification: OAuth callbacks cannot use a WordPress nonce — the user bounces through Google's authorization server, so a session-bound nonce we set before the outbound redirect would not survive. Instead the OAuth `state` parameter (a per-request random token stored in a transient and verified on return) protects against CSRF. wp_redirect() is intentional for the outgoing redirect to Google's authorization endpoint, which is not in WordPress's allowed_redirect_hosts and would be blocked by wp_safe_redirect().

class CCGAL_Google_OAuth {

	const AUTH_URL  = 'https://accounts.google.com/o/oauth2/v2/auth';
	const TOKEN_URL = 'https://oauth2.googleapis.com/token';
	const SCOPE     = 'https://www.googleapis.com/auth/drive.readonly';

	public static function init() {
		add_action( 'admin_post_ccgal_oauth_start',      array( __CLASS__, 'handle_start' ) );
		add_action( 'admin_post_ccgal_oauth_callback',   array( __CLASS__, 'handle_callback' ) );
		add_action( 'admin_post_ccgal_oauth_disconnect', array( __CLASS__, 'handle_disconnect' ) );
	}

	public static function get_redirect_uri() {
		return admin_url( 'admin-post.php?action=ccgal_oauth_callback' );
	}

	public static function get_client_id() {
		return trim( (string) get_option( 'ccgal_oauth_client_id', '' ) );
	}

	public static function get_client_secret() {
		$enc = (string) get_option( 'ccgal_oauth_client_secret', '' );
		return $enc ? CCGAL_Encryption::decrypt( $enc ) : '';
	}

	public static function save_client_credentials( $client_id, $client_secret ) {
		update_option( 'ccgal_oauth_client_id', sanitize_text_field( $client_id ), false );
		if ( '' !== $client_secret ) {
			update_option( 'ccgal_oauth_client_secret', CCGAL_Encryption::encrypt( $client_secret ), false );
		}
	}

	public static function get_tokens() {
		$enc = (string) get_option( 'ccgal_oauth_tokens', '' );
		if ( ! $enc ) {
			return null;
		}
		$json = CCGAL_Encryption::decrypt( $enc );
		if ( ! $json ) {
			return null;
		}
		$tokens = json_decode( $json, true, 32 );
		return is_array( $tokens ) ? $tokens : null;
	}

	public static function save_tokens( array $tokens ) {
		if ( ! isset( $tokens['obtained_at'] ) ) {
			$tokens['obtained_at'] = time();
		}
		update_option( 'ccgal_oauth_tokens', CCGAL_Encryption::encrypt( wp_json_encode( $tokens ) ), false );
	}

	public static function is_connected() {
		$t = self::get_tokens();
		return is_array( $t ) && ! empty( $t['refresh_token'] );
	}

	public static function handle_start() {
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_die( esc_html__( 'Permission denied.', 'customer-cloud-gallery' ) );
		}
		check_admin_referer( 'ccgal_oauth_start' );

		$client_id = self::get_client_id();
		if ( empty( $client_id ) ) {
			wp_safe_redirect( add_query_arg( 'ccgal_msg', 'missing_credentials', admin_url( 'admin.php?page=ccgal-settings' ) ) );
			exit;
		}

		$state = wp_generate_password( 32, false, false );
		set_transient( 'ccgal_oauth_state_' . $state, get_current_user_id(), 600 );

		$params = array(
			'client_id'              => $client_id,
			'redirect_uri'           => self::get_redirect_uri(),
			'response_type'          => 'code',
			'scope'                  => self::SCOPE,
			'access_type'            => 'offline',
			'prompt'                 => 'consent',
			'include_granted_scopes' => 'true',
			'state'                  => $state,
		);

		// External redirect to Google's OAuth endpoint — wp_safe_redirect would block off-host targets.
		wp_redirect( esc_url_raw( self::AUTH_URL . '?' . http_build_query( $params ) ) );
		exit;
	}

	public static function handle_callback() {
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_die( esc_html__( 'Permission denied.', 'customer-cloud-gallery' ) );
		}

		$state = isset( $_GET['state'] ) ? sanitize_text_field( wp_unslash( $_GET['state'] ) ) : '';
		$code  = isset( $_GET['code'] )  ? sanitize_text_field( wp_unslash( $_GET['code'] ) )  : '';
		$error = isset( $_GET['error'] ) ? sanitize_text_field( wp_unslash( $_GET['error'] ) ) : '';

		if ( $error ) {
			wp_safe_redirect( add_query_arg( 'ccgal_msg', 'oauth_error', admin_url( 'admin.php?page=ccgal-settings' ) ) );
			exit;
		}

		$user_id = get_transient( 'ccgal_oauth_state_' . $state );
		delete_transient( 'ccgal_oauth_state_' . $state );

		if ( ! $user_id || (int) $user_id !== get_current_user_id() ) {
			wp_die( esc_html__( 'Invalid state. Please retry the connection.', 'customer-cloud-gallery' ) );
		}

		$response = wp_remote_post(
			self::TOKEN_URL,
			array(
				'timeout' => 30,
				'body'    => array(
					'code'          => $code,
					'client_id'     => self::get_client_id(),
					'client_secret' => self::get_client_secret(),
					'redirect_uri'  => self::get_redirect_uri(),
					'grant_type'    => 'authorization_code',
				),
			)
		);

		if ( is_wp_error( $response ) ) {
			wp_safe_redirect( add_query_arg( 'ccgal_msg', 'token_error', admin_url( 'admin.php?page=ccgal-settings' ) ) );
			exit;
		}

		$body = json_decode( wp_remote_retrieve_body( $response ), true, 32 );
		if ( empty( $body['access_token'] ) ) {
			wp_safe_redirect( add_query_arg( 'ccgal_msg', 'token_error', admin_url( 'admin.php?page=ccgal-settings' ) ) );
			exit;
		}

		self::save_tokens( $body );

		wp_safe_redirect( add_query_arg( 'ccgal_msg', 'connected', admin_url( 'admin.php?page=ccgal-settings' ) ) );
		exit;
	}

	public static function handle_disconnect() {
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_die( esc_html__( 'Permission denied.', 'customer-cloud-gallery' ) );
		}
		check_admin_referer( 'ccgal_oauth_disconnect' );
		delete_option( 'ccgal_oauth_tokens' );
		wp_safe_redirect( add_query_arg( 'ccgal_msg', 'disconnected', admin_url( 'admin.php?page=ccgal-settings' ) ) );
		exit;
	}

	public static function get_access_token() {
		$tokens = self::get_tokens();
		if ( ! $tokens ) {
			return new WP_Error( 'ccgal_not_connected', __( 'Google Drive is not connected.', 'customer-cloud-gallery' ) );
		}

		$expires_in  = isset( $tokens['expires_in'] ) ? (int) $tokens['expires_in'] : 3600;
		$obtained_at = isset( $tokens['obtained_at'] ) ? (int) $tokens['obtained_at'] : 0;
		$is_expired  = ( $obtained_at + $expires_in - 60 ) < time();

		if ( ! $is_expired && ! empty( $tokens['access_token'] ) ) {
			return $tokens['access_token'];
		}

		if ( empty( $tokens['refresh_token'] ) ) {
			return new WP_Error( 'ccgal_no_refresh_token', __( 'No refresh token. Please reconnect Google Drive.', 'customer-cloud-gallery' ) );
		}

		$response = wp_remote_post(
			self::TOKEN_URL,
			array(
				'timeout' => 30,
				'body'    => array(
					'client_id'     => self::get_client_id(),
					'client_secret' => self::get_client_secret(),
					'refresh_token' => $tokens['refresh_token'],
					'grant_type'    => 'refresh_token',
				),
			)
		);

		if ( is_wp_error( $response ) ) {
			return $response;
		}

		$body = json_decode( wp_remote_retrieve_body( $response ), true, 32 );
		if ( empty( $body['access_token'] ) ) {
			return new WP_Error( 'ccgal_token_refresh_failed', __( 'Access token could not be refreshed.', 'customer-cloud-gallery' ) );
		}

		$tokens['access_token'] = $body['access_token'];
		$tokens['expires_in']   = isset( $body['expires_in'] ) ? (int) $body['expires_in'] : 3600;
		$tokens['obtained_at']  = time();
		self::save_tokens( $tokens );

		return $tokens['access_token'];
	}
}
