<?php
/**
 * Standard Bulk Generator Controller
 *
 * @package AIPT\Api\BulkGenerator\Standard
 * @since 2.5.0
 */

namespace AIPT\Api\BulkGenerator\Standard;

use WP_Error;
use WP_REST_Request;
use WP_REST_Response;
use AIPT\Core\ErrorHandler;

class StandardBulkGeneratorController {

	protected const RATE_LIMIT_MAX_REQUESTS    = 10;
	protected const RATE_LIMIT_WINDOW_SECONDS  = 60;
	protected const RATE_LIMIT_TRANSIENT_PREFIX = 'aipt_rate_limit_std_';

	private ?StandardGenerator $generator = null;

	public function register_routes(): void {
		register_rest_route( 'aipt/v1', '/standard-bulk-generator/generate', array(
			'methods'             => 'POST',
			'callback'            => array( $this, 'generate_descriptions' ),
			'permission_callback' => array( $this, 'check_permissions_write' ),
			'args'                => array(
				'product_ids' => array(
					'type'              => 'array',
					'required'          => true,
					'sanitize_callback' => function ( $param ) {
						return array_map( 'absint', $param );
					},
				),
				'options'     => array(
					'type'     => 'object',
					'required' => true,
				),
			),
		) );

		register_rest_route( 'aipt/v1', '/standard-bulk-generator/apply', array(
			'methods'             => 'POST',
			'callback'            => array( $this, 'apply_descriptions' ),
			'permission_callback' => array( $this, 'check_permissions_write' ),
			'args'                => array(
				'items' => array(
					'type'     => 'array',
					'required' => true,
				),
			),
		) );
	}

	/**
	 * Check write permissions for the current user.
	 *
	 * @param WP_REST_Request|null $request REST request instance.
	 * @return bool|WP_Error True if authorized, WP_Error otherwise.
	 */
	public function check_permissions_write( $request = null ) {
		if ( ! current_user_can( 'manage_woocommerce' ) ) {
			return new WP_Error(
				'rest_forbidden',
				__( 'You do not have permission to perform this action.', 'ai-product-tools' ),
				array( 'status' => 403 )
			);
		}

		if ( $request instanceof WP_REST_Request ) {
			$nonce = $request->get_header( 'X-WP-Nonce' );
			if ( $nonce && ! wp_verify_nonce( $nonce, 'wp_rest' ) ) {
				return new WP_Error(
					'rest_invalid_nonce',
					__( 'Invalid security token. Please refresh the page and try again.', 'ai-product-tools' ),
					array( 'status' => 403 )
				);
			}
		}

		return true;
	}

	/**
	 * Generate descriptions for selected products.
	 *
	 * @param WP_REST_Request $request REST request instance.
	 * @return WP_REST_Response|WP_Error Response with generated descriptions or error.
	 */
	public function generate_descriptions( WP_REST_Request $request ) {
		$rate_check = $this->checkRateLimit( (int) get_current_user_id() );
		if ( ! $rate_check['allowed'] ) {
			return new WP_Error(
				'rate_limit_exceeded',
				sprintf(
					/* translators: %d: number of seconds to wait */
					__( 'Rate limit exceeded. Please wait %d seconds before trying again.', 'ai-product-tools' ),
					$rate_check['reset_in']
				),
				array(
					'status'      => 429,
					'retry_after' => $rate_check['reset_in'],
				)
			);
		}

		$product_ids = $request->get_param( 'product_ids' );
		$options     = $request->get_param( 'options' );

		if ( empty( $product_ids ) ) {
			return new WP_Error(
				'invalid_input',
				__( 'No products selected', 'ai-product-tools' ),
				array( 'status' => 400 )
			);
		}

		$options = $this->sanitizeOptions( $options );

		try {
			$generator = $this->getGenerator( $options );
			$results   = $generator->bulkGenerate( $product_ids, $options );

			return new WP_REST_Response(
				array(
					'success' => true,
					'data'    => $results,
				),
				200
			);

		} catch ( \Exception $e ) {
			$provider = $options['provider'] ?? get_option( 'aipt_api_provider', 'openai' );
			$error_message = ErrorHandler::format_api_error_message( ucfirst( $provider ), $e->getMessage() );

			$status_code = 500;
			if ( strpos( $e->getMessage(), 'Invalid' ) !== false ) {
				$status_code = 400;
			} elseif ( strpos( $e->getMessage(), 'API Error' ) !== false ) {
				$status_code = 502;
			}

			return new WP_Error(
				'aipt_error',
				$error_message,
				array( 'status' => $status_code )
			);
		}
	}

	/**
	 * Apply generated descriptions to products.
	 *
	 * @param WP_REST_Request $request REST request instance.
	 * @return WP_REST_Response|WP_Error Response with applied results or error.
	 */
	public function apply_descriptions( WP_REST_Request $request ) {
		$items = $request->get_param( 'items' );

		if ( empty( $items ) ) {
			return new WP_Error(
				'invalid_input',
				__( 'No descriptions selected to apply', 'ai-product-tools' ),
				array( 'status' => 400 )
			);
		}

		try {
			$generator = $this->getGenerator( array() );
			$result    = $generator->applyDescriptions( $items );

			return new WP_REST_Response(
				array(
					'success' => true,
					'data'    => $result,
				),
				200
			);

		} catch ( \Exception $e ) {
			return new WP_Error(
				'aipt_error',
				ErrorHandler::make_urls_readable( $e->getMessage() ),
				array( 'status' => 500 )
			);
		}
	}

	private function getGenerator( array $options ): StandardGenerator {
		if ( null === $this->generator ) {
			$this->generator = new StandardGenerator( $options );
		}
		return $this->generator;
	}

	private function sanitizeOptions( $options ): array {
		if ( ! is_array( $options ) ) {
			$options = array();
		}

		$sanitized = array(
			'provider'                   => sanitize_text_field( $options['provider'] ?? get_option( 'aipt_api_provider', 'openai' ) ),
			'model'                      => sanitize_text_field( $options['model'] ?? '' ),
			'generateDescription'        => (bool) ( $options['generateDescription'] ?? false ),
			'generateShortDescription'   => (bool) ( $options['generateShortDescription'] ?? false ),
			'generateTags'               => (bool) ( $options['generateTags'] ?? false ),
			'keepExistingDescription'    => (bool) ( $options['keepExistingDescription'] ?? false ),
			'improveExistingDescription' => (bool) ( $options['improveExistingDescription'] ?? false ),
			'additionalTagsCount'        => absint( $options['additionalTagsCount'] ?? 3 ),
			'max_tags_count'             => absint( $options['max_tags_count'] ?? get_option( 'aipt_max_tags_count', 3 ) ),
		);

		if ( isset( $options['language'] ) ) {
			$sanitized['language'] = sanitize_text_field( $options['language'] );
		}
		if ( isset( $options['writing_style'] ) ) {
			$sanitized['writing_style'] = sanitize_text_field( $options['writing_style'] );
		}
		if ( isset( $options['writingStyle'] ) ) {
			$sanitized['writingStyle'] = sanitize_text_field( $options['writingStyle'] );
		}
		if ( isset( $options['content_length_preset'] ) ) {
			$sanitized['content_length_preset'] = sanitize_text_field( $options['content_length_preset'] );
		}
		if ( isset( $options['short_length_preset'] ) ) {
			$sanitized['short_length_preset'] = sanitize_text_field( $options['short_length_preset'] );
		}

		if ( ! empty( $options['prompts'] ) && is_array( $options['prompts'] ) ) {
			$sanitized['prompts'] = array();
			foreach ( array( 'short', 'full', 'tags' ) as $type ) {
				if ( isset( $options['prompts'][ $type ] ) && is_array( $options['prompts'][ $type ] ) ) {
					$sanitized['prompts'][ $type ] = array();
					if ( isset( $options['prompts'][ $type ]['system_prompt'] ) ) {
						$sanitized['prompts'][ $type ]['system_prompt'] = sanitize_textarea_field(
							$options['prompts'][ $type ]['system_prompt']
						);
					}
					if ( isset( $options['prompts'][ $type ]['user_prompt'] ) ) {
						$sanitized['prompts'][ $type ]['user_prompt'] = sanitize_textarea_field(
							$options['prompts'][ $type ]['user_prompt']
						);
					}
				}
			}
		}

		return $sanitized;
	}

	private function checkRateLimit( int $user_id ): array {
		$transient_key = self::RATE_LIMIT_TRANSIENT_PREFIX . $user_id;
		$rate_data     = get_transient( $transient_key );

		if ( false === $rate_data ) {
			$rate_data = array(
				'count'        => 1,
				'window_start' => time(),
			);
			set_transient( $transient_key, $rate_data, self::RATE_LIMIT_WINDOW_SECONDS );

			return array(
				'allowed'   => true,
				'remaining' => self::RATE_LIMIT_MAX_REQUESTS - 1,
				'reset_in'  => self::RATE_LIMIT_WINDOW_SECONDS,
			);
		}

		$elapsed = time() - $rate_data['window_start'];

		if ( $elapsed >= self::RATE_LIMIT_WINDOW_SECONDS ) {
			$rate_data = array(
				'count'        => 1,
				'window_start' => time(),
			);
			set_transient( $transient_key, $rate_data, self::RATE_LIMIT_WINDOW_SECONDS );

			return array(
				'allowed'   => true,
				'remaining' => self::RATE_LIMIT_MAX_REQUESTS - 1,
				'reset_in'  => self::RATE_LIMIT_WINDOW_SECONDS,
			);
		}

		if ( $rate_data['count'] >= self::RATE_LIMIT_MAX_REQUESTS ) {
			return array(
				'allowed'   => false,
				'remaining' => 0,
				'reset_in'  => self::RATE_LIMIT_WINDOW_SECONDS - $elapsed,
			);
		}

		$rate_data['count']++;
		set_transient( $transient_key, $rate_data, self::RATE_LIMIT_WINDOW_SECONDS - $elapsed );

		return array(
			'allowed'   => true,
			'remaining' => self::RATE_LIMIT_MAX_REQUESTS - $rate_data['count'],
			'reset_in'  => self::RATE_LIMIT_WINDOW_SECONDS - $elapsed,
		);
	}
}
