<?php

namespace AIOSEO\Plugin\Pro\Ai;

// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

use AIOSEO\Plugin\Common\Ai as CommonAi;

/**
 * Handles AIOSEO AI.
 *
 * @since 4.8.4
 */
class Ai extends CommonAi\Ai {
	/**
	 * The hook name for autogenerating alt text on upload.
	 *
	 * @since 4.9.6
	 *
	 * @var string
	 */
	private $autogenerateAltHook = 'aioseo_ai_autogenerate_alt_text';

	/**
	 * Class constructor.
	 *
	 * @since 4.8.4
	 */
	public function __construct() {
		parent::__construct();

		add_action( 'add_attachment', [ $this, 'maybeScheduleAltTextGeneration' ] );
		add_action( $this->autogenerateAltHook, [ $this, 'autogenerateAltText' ] );
	}

	/**
	 * Schedules async AI alt text generation when a new image is uploaded.
	 *
	 * @since 4.9.6
	 *
	 * @param  int  $attachmentId The attachment ID.
	 * @return void
	 */
	public function maybeScheduleAltTextGeneration( $attachmentId ) {
		if (
			defined( 'WP_IMPORTING' ) ||
			! aioseo()->options->image->altTag->autogenerateWithAi ||
			! aioseo()->sensitiveOptions->hasValue( 'aiAccessToken' ) ||
			! (int) aioseo()->internalOptions->internal->ai->credits->remaining ||
			! aioseo()->helpers->attachmentIs( 'image', $attachmentId )
		) {
			return;
		}

		aioseo()->actionScheduler->scheduleAsync( $this->autogenerateAltHook, [ $attachmentId ] );
	}

	/**
	 * Generates alt text for an image using AI and saves it.
	 * This is the async handler called by Action Scheduler.
	 *
	 * @since 4.9.6
	 *
	 * @param  int  $attachmentId The attachment ID.
	 * @return void
	 */
	public function autogenerateAltText( $attachmentId ) {
		if ( ! empty( get_post_meta( $attachmentId, '_wp_attachment_image_alt', true ) ) ) {
			return;
		}

		$result = $this->generateImageAlt( [ 'attachmentId' => $attachmentId ] );
		if ( empty( $result['success'] ) || empty( $result['altTexts'][0] ) ) {
			return;
		}

		update_post_meta( $attachmentId, '_wp_attachment_image_alt', sanitize_text_field( $result['altTexts'][0] ) );
	}

	/**
	 * Gets an access token from the server.
	 *
	 * @since 4.8.4
	 *
	 * @param  bool $refresh Whether to refresh the access token.
	 * @return void
	 */
	public function getAccessToken( $refresh = false ) {
		if (
			(
				aioseo()->sensitiveOptions->hasValue( 'aiAccessToken' ) ||
				aioseo()->core->cache->get( 'ai_access_token_idle' )
			) &&
			! $refresh
		) {
			return;
		}

		// If user has no valid license, run the Lite flow.
		if ( ! aioseo()->license->isActive() ) {
			parent::getAccessToken( $refresh );

			return;
		}

		$response = aioseo()->helpers->wpRemotePost( $this->getApiUrl() . 'ai/auth/', [
			'body'    => wp_json_encode( [
				'domain' => aioseo()->helpers->getSiteDomain()
			] ),
			'headers' => $this->getRequestHeaders()
		] );

		if ( is_wp_error( $response ) ) {
			aioseo()->core->cache->update( 'ai_access_token_idle', true, 4 * HOUR_IN_SECONDS );

			// Schedule another, one-time event in approx. 1 hour from now.
			aioseo()->actionScheduler->scheduleSingle( $this->creditFetchAction, HOUR_IN_SECONDS + wp_rand( 0, 30 * MINUTE_IN_SECONDS ), [] );

			return;
		}

		$body = wp_remote_retrieve_body( $response );
		$data = json_decode( $body );
		if ( empty( $data->accessToken ) ) {
			aioseo()->core->cache->update( 'ai_access_token_idle', true, HOUR_IN_SECONDS );

			// Schedule another, one-time event in approx. 1 hour from now.
			aioseo()->actionScheduler->scheduleSingle( $this->creditFetchAction, HOUR_IN_SECONDS + wp_rand( 0, 30 * MINUTE_IN_SECONDS ), [] );

			return;
		}

		aioseo()->sensitiveOptions->set( 'aiAccessToken', sanitize_text_field( $data->accessToken ) );
		aioseo()->internalOptions->internal->ai->isTrialAccessToken  = $data->isFree ?? false;
		aioseo()->internalOptions->internal->ai->isManuallyConnected = false;

		aioseo()->core->cache->update( 'ai_access_token_idle', true, 12 * HOUR_IN_SECONDS );

		$this->updateCredits( true );
	}

	/**
	 * Returns the default request headers.
	 *
	 * @since   4.8.4
	 * @version 4.9.6 Changed method visibility to public.
	 *
	 * @return array The default request headers.
	 */
	public function getRequestHeaders() {
		$headers = parent::getRequestHeaders();

		$licenseKey = aioseo()->license->getLicenseKey();
		if ( ! $licenseKey || ! aioseo()->license->isActive() ) {
			return $headers;
		}

		$headers['X-AIOSEO-License'] = $licenseKey;

		return $headers;
	}
}