<?php

namespace AIPT\Api\BulkGenerator\Title;

use AIPT\Api\BulkGenerator\BaseBulkGeneratorController;
use AIPT\Core\ErrorHandler;
use WP_Error;
use WP_REST_Request;
use WP_REST_Response;

class TitleGeneratorController extends BaseBulkGeneratorController {

	protected const RATE_LIMIT_SCOPE = 'title';

	private $service;

	public function __construct() {
		$this->service = new TitleGeneratorService();
	}

	public function register_routes() {
		register_rest_route( 'aipt/v1', '/title-generator/bulk-generate', array(
			'methods'             => 'POST',
			'callback'            => array( $this, 'bulk_generate' ),
			'permission_callback' => array( $this, 'check_permissions_write' ),
			'args'                => array(
				'productIds' => array(
					'type'              => 'array',
					'required'          => true,
					'sanitize_callback' => function ( $param ) {
						if ( ! is_array( $param ) ) {
							return array();
						}
						return array_map( 'absint', $param );
					},
				),
				'options'    => array(
					'type'     => 'object',
					'required' => true,
				),
			),
		) );

		register_rest_route( 'aipt/v1', '/title-generator/bulk-apply', array(
			'methods'             => 'POST',
			'callback'            => array( $this, 'bulk_apply' ),
			'permission_callback' => array( $this, 'check_permissions_write' ),
			'args'                => array(
				'results' => array(
					'type'     => 'array',
					'required' => true,
				),
				'options' => array(
					'type'     => 'object',
					'required' => false,
				),
			),
		) );

		register_rest_route( 'aipt/v1', '/title-generator/bulk-reject', array(
			'methods'             => 'POST',
			'callback'            => array( $this, 'bulk_reject' ),
			'permission_callback' => array( $this, 'check_permissions_write' ),
			'args'                => array(
				'results' => array(
					'required' => true,
					'type'     => 'array',
					'items'    => array(
						'type'       => 'object',
						'properties' => array(
							'product_id' => array(
								'required' => true,
								'type'     => 'integer',
							),
						),
					),
				),
			),
		) );
	}

	/**
	 * Apply premium feature controls to options.
	 *
	 * Uses filter hook to allow Premium module to preserve premium options.
	 * Free version always uses default values for premium features.
	 *
	 * @param array $options Request options.
	 * @return array Validated options.
	 */
	private function applyPremiumControls( $options ) {
		$default_options = array(
			'tone'         => 'SEO-Focused',
			'keywords'     => '',
			'mode'         => 'rewrite',
			'titleSources' => array( 'product_description' ),
		);

		$controlled_options = array_merge( $options, $default_options );

		/**
		 * Filter title generator validated options.
		 *
		 * Premium module can hook here to preserve premium option values
		 * when a valid license is present.
		 *
		 * @since 2.5.0
		 * @param array $controlled_options Options with free defaults applied.
		 * @param array $options            Original request options.
		 */
		$controlled_options = apply_filters( 'aipt_title_validate_options', $controlled_options, $options );

		return $controlled_options;
	}

	public function bulk_generate( WP_REST_Request $request ) {

		$ai_gate = \AIPT\Core\Services\AiSupportGate::guard();
		if ( $ai_gate instanceof \WP_Error ) {
			return $ai_gate;
		}
		try {
			$rate_check = $this->checkRateLimit( (int) get_current_user_id(), static::RATE_LIMIT_SCOPE );
			if ( ! $rate_check['allowed'] ) {
				return $this->rateLimitResponse( $rate_check );
			}

			$products = $request->get_param( 'productIds' ) ?? array();
			$options  = $request->get_param( 'options' ) ?? array();

			$premium_params_present = array();
			if ( ! empty( $options['tone'] ) && 'SEO-Focused' !== $options['tone'] ) {
				$premium_params_present[] = 'tone';
			}
			if ( ! empty( $options['keywords'] ) ) {
				$premium_params_present[] = 'keywords';
			}
			if ( ! empty( $options['titleSources'] ) ) {
				$free_default   = array( 'product_description' );
				$incoming       = array_values( array_map( 'strval', (array) $options['titleSources'] ) );
				$normalised     = $incoming;
				sort( $normalised );
				$default_sorted = $free_default;
				sort( $default_sorted );
				if ( $normalised !== $default_sorted ) {
					$premium_params_present[] = 'titleSources';
				}
			}

			if ( ! empty( $premium_params_present ) && ! \AIPT\Utils\PremiumFeatureManager::getInstance()->canUsePremiumFeatures() ) {
				return new \WP_Error(
					'premium_required',
					sprintf(
						/* translators: %s: comma-separated list of premium parameter names that triggered the gate */
						__( 'The following options require Pro plan: %s', 'ai-product-tools' ),
						implode( ', ', $premium_params_present )
					),
					array( 'status' => 403, 'premium_features' => $premium_params_present )
				);
			}

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

			if ( empty( $products ) ) {
				throw new \Exception( __( 'No products provided.', 'ai-product-tools' ) );
			}

			if ( ! is_array( $products ) ) {
				throw new \Exception( __( 'Invalid products format. Expected array.', 'ai-product-tools' ) );
			}

			$result = $this->service->bulk_generate( $products, $options );

			\AIPT\Core\Services\UsageTracker::record_event(
				'title',
				'generated',
				is_array( $result ) ? count( $result ) : count( (array) $products ),
				array(
					'product_id' => is_array( $products ) && ! empty( $products )
						? (int) $products[ array_key_first( $products ) ]
						: 0,
				)
			);

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

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

			$readable_error = ErrorHandler::make_urls_readable( $error_message );

			if ( strpos( $error_message, 'API Error' ) !== false ) {
				$readable_error = ErrorHandler::format_api_error_message( $provider_name, $error_message );
			}

			return ErrorHandler::create_wp_error( $readable_error, 'aipt_title_generation_error' );
		}
	}

	public function bulk_apply( $request ) {
		try {
			$rate_check = $this->checkRateLimit( (int) get_current_user_id(), static::RATE_LIMIT_SCOPE . '_apply' );
			if ( ! $rate_check['allowed'] ) {
				return $this->rateLimitResponse( $rate_check );
			}

			$params  = $request->get_json_params();
			$results = $params['results'] ?? array();

			if ( empty( $results ) ) {
				return new \WP_Error( 'invalid_request', __( 'No titles to apply', 'ai-product-tools' ), array( 'status' => 400 ) );
			}

			$success_count   = 0;
			$skipped_count   = 0;
			$failed_ids      = array();
			$total_processed = 0;
			$saved_ids       = array();

			$prev_term  = \wp_defer_term_counting();
			$prev_comm  = \wp_defer_comment_counting();
			\wp_defer_term_counting( true );
			\wp_defer_comment_counting( true );
			$prev_cache = \wp_suspend_cache_invalidation( true );

			try {
				foreach ( $results as $result ) {
					$product_id  = $result['product_id'] ?? null;
					$title       = $result['title'] ?? null;
					$status      = $result['status'] ?? 'pending';
					$update_slug = ! empty( $result['update_slug'] );

					if ( null === $product_id || '' === $product_id || null === $title || '' === $title ) {
						$skipped_count++;
						continue;
					}

					if ( ! is_scalar( $title ) && ! ( is_object( $title ) && method_exists( $title, '__toString' ) ) ) {
						$failed_ids[] = (int) $product_id;
						continue;
					}

					if ( 'rejected' === $status ) {
						$skipped_count++;
						continue;
					}

					$product = wc_get_product( $product_id );
					if ( ! $product instanceof \WC_Product ) {
						$skipped_count++;
						continue;
					}

					/** @var \WC_Product $product */
					$total_processed++;

					$sanitized_title = sanitize_text_field( (string) $title );

					if ( '' === trim( $sanitized_title ) ) {
						$failed_ids[] = (int) $product_id;
						continue;
					}

					$product->set_name( $sanitized_title );

					if ( $update_slug ) {
						$product->set_slug( sanitize_title( $sanitized_title ) );
					}

					$save_result = $product->save();

					if ( is_wp_error( $save_result ) ) {
						$failed_ids[] = $product_id;
					} elseif ( $save_result && $save_result > 0 ) {
						$success_count++;
						$saved_ids[] = (int) $product_id;
					} else {
						$failed_ids[] = $product_id;
					}
				}
			} finally {
				\wp_suspend_cache_invalidation( $prev_cache );
				\wp_defer_comment_counting( $prev_comm );
				\wp_defer_term_counting( $prev_term );

				foreach ( $saved_ids as $saved_id ) {
					\clean_post_cache( $saved_id );
					\wc_delete_product_transients( $saved_id );
				}
			}

			$overall_success = $success_count > 0;

			if ( $success_count === $total_processed && $total_processed > 0 ) {
				$message = sprintf(
					/* translators: %d: Number of titles applied */
					__( '%d title(s) applied successfully.', 'ai-product-tools' ),
					$success_count
				);
			} elseif ( $success_count > 0 ) {
				$message = sprintf(
					/* translators: %1$d: Number of successful updates, %2$d: Number of failed updates */
					__( '%1$d title(s) applied successfully, %2$d failed.', 'ai-product-tools' ),
					$success_count,
					count( $failed_ids )
				);
			} elseif ( 0 === $total_processed ) {
				$message = __( 'No valid titles to apply. All items were skipped.', 'ai-product-tools' );
			} else {
				$message = __( 'No titles were applied. All updates failed.', 'ai-product-tools' );
			}

			if ( $success_count > 0 ) {
				\AIPT\Core\Services\UsageTracker::record_event(
					'title',
					'applied',
					$success_count,
					array(
						'product_id' => is_array( $results ) && ! empty( $results ) && isset( $results[0]['product_id'] )
							? (int) $results[0]['product_id']
							: 0,
					)
				);
			}

			return new \WP_REST_Response( array(
				'success' => $overall_success,
				'message' => $message,
				'data'    => array(
					'total_processed' => $total_processed,
					'updated'         => $success_count,
					'skipped'         => $skipped_count,
					'failed'          => count( $failed_ids ),
					'failed_ids'      => $failed_ids,
				),
			), 200 );

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

	public function bulk_reject( $request ) {
		try {
			$rate_check = $this->checkRateLimit( (int) get_current_user_id(), static::RATE_LIMIT_SCOPE . '_reject' );
			if ( ! $rate_check['allowed'] ) {
				return $this->rateLimitResponse( $rate_check );
			}

			$params  = $request->get_json_params();
			$results = $params['results'] ?? array();

			if ( empty( $results ) ) {
				return new \WP_Error( 'invalid_request', __( 'No titles to reject', 'ai-product-tools' ), array( 'status' => 400 ) );
			}

			$success_count = count( $results );

			\AIPT\Core\Services\UsageTracker::record_event(
				'title',
				'rejected',
				$success_count,
				array(
					'product_id' => is_array( $results ) && ! empty( $results ) && isset( $results[0]['product_id'] )
						? (int) $results[0]['product_id']
						: 0,
				)
			);

			return new WP_REST_Response( array(
				'success'        => true,
				'message'        => sprintf(
					/* translators: %d: Number of titles that were rejected */
					__( '%d title(s) rejected successfully.', 'ai-product-tools' ),
					$success_count
				),
				'rejected_count' => $success_count,
			), 200 );

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