<?php

namespace AIPT\Api\BulkGenerator\Desc\Controllers;

defined( 'ABSPATH' ) || exit;

use WP_Error;
use WP_REST_Request;
use WP_REST_Response;
use WP_REST_Server;
use AIPT\Api\BulkGenerator\Desc\ContentGenerator;
use AIPT\Api\BulkGenerator\Desc\Services\ProductFilterService;
use AIPT\Utils\ProductFilter\ProductFilterBuilder;
use AIPT\Utils\ProductFilter\ProductFilterMapper;
use AIPT\Core\ErrorHandler;
use AIPT\Core\FsManager;

require_once AIPT_PLUGIN_DIR . 'src/Core/CreditSystem/index.php';
use AIPT\Core\CreditSystem\CreditManager;

class GenerationController extends BaseController {

	private ContentGenerator $generator;
	private ProductFilterService $productFilterService;

	public function __construct( ?ContentGenerator $generator = null, ?ProductFilterService $productFilterService = null ) {
		$this->generator = $generator ?? new ContentGenerator();
		$this->productFilterService = $productFilterService ?? new ProductFilterService();
		\AIPT\Core\CreditSystem\setupCreditSystem();
	}

	public function register_routes(): void {
		register_rest_route(
			self::REST_NAMESPACE,
			'/products',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $this, 'get_products' ),
				'permission_callback' => array( $this, 'check_permissions' ),
				'args'                => $this->get_product_args(),
			)
		);

		register_rest_route(
			self::REST_NAMESPACE,
			'/categories',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $this, 'get_categories' ),
				'permission_callback' => array( $this, 'check_permissions' ),
			)
		);

		register_rest_route(
			self::REST_NAMESPACE,
			'/tags',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $this, 'get_tags' ),
				'permission_callback' => array( $this, 'check_permissions' ),
			)
		);

		register_rest_route(
			self::REST_NAMESPACE . '/description-generator',
			'/generate',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $this, 'generate_single' ),
				'permission_callback' => array( $this, 'check_permissions_write' ),
			)
		);

		register_rest_route(
			self::REST_NAMESPACE . '/description-generator',
			'/bulk-generate',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $this, 'bulk_generate' ),
				'permission_callback' => array( $this, 'check_permissions_write' ),
			)
		);

		register_rest_route(
			self::REST_NAMESPACE . '/description-generator',
			'/preview-cost',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $this, 'preview_cost' ),
				'permission_callback' => array( $this, 'check_permissions_write' ),
			)
		);
	}

	public function get_products( WP_REST_Request $request ): WP_REST_Response {
		try {
			$response = $this->productFilterService->fetchFilteredProducts( (array) $request->get_params() );
			return new WP_REST_Response( $response, 200 );

		} catch ( \Throwable $e ) {
			if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
			}

			return new WP_REST_Response(
				array(
					'success'    => false,
					'products'   => array(),
					'total'      => 0,
					'totalPages' => 0,
					'page'       => absint( $request->get_param( 'page' ) ?: 1 ),
					'perPage'    => absint( $request->get_param( 'per_page' ) ?: 10 ),
					'error'      => 'An error occurred while fetching products.',
				),
				200
			);
		}
	}

	public function get_categories(): WP_REST_Response {
		try {
			$categories = ProductFilterMapper::getCategories();
			return new WP_REST_Response( $categories, 200 );

		} catch ( \Throwable $e ) {
			if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
			}
			return new WP_REST_Response( array(), 200 );
		}
	}

	public function get_tags(): WP_REST_Response {
		try {
			$tags = ProductFilterMapper::getTags();
			return new WP_REST_Response( $tags, 200 );

		} catch ( \Throwable $e ) {
			if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
			}
			return new WP_REST_Response( array(), 200 );
		}
	}

	public function generate_single( WP_REST_Request $request ) {

		$ai_gate = \AIPT\Core\Services\AiSupportGate::guard();
		if ( $ai_gate instanceof \WP_Error ) {
			return $ai_gate;
		}
		$data       = $request->get_json_params();
		$product_id = absint( $data['productId'] ?? 0 );
		$options    = $this->sanitize_generation_options( $data['options'] ?? array() );

		if ( ! $product_id ) {
			return $this->error_response( 'invalid_product', __( 'Invalid product ID', 'ai-product-tools' ), 400 );
		}

		$content_types = $this->extract_content_types( $options );
		if ( empty( $content_types ) ) {
			return $this->error_response( 'no_content_types', __( 'No content types selected', 'ai-product-tools' ), 400 );
		}

		$credit_result = $this->validate_credits( 1, $content_types, $options );
		if ( is_wp_error( $credit_result ) ) {
			return $credit_result;
		}

		$result = $this->generator->generateForProduct( $product_id, $content_types, $options );

		if ( ! $result->success ) {
			$error_msg = ! empty( $result->errors ) ? implode( ', ', $result->errors ) : __( 'Generation failed', 'ai-product-tools' );
			return $this->error_response( 'generation_failed', $error_msg, 500 );
		}

		$this->deduct_credits( $credit_result, $content_types );

		return $this->success_response(
			array(
				'product_id'      => $product_id,
				'content'         => $result->content,
				'current_balance' => $this->get_current_balance(),
			),
			__( 'Content generated successfully', 'ai-product-tools' )
		);
	}

	public function bulk_generate( WP_REST_Request $request ) {

		$ai_gate = \AIPT\Core\Services\AiSupportGate::guard();
		if ( $ai_gate instanceof \WP_Error ) {
			return $ai_gate;
		}
		$rate_check = $this->checkRateLimit( (int) get_current_user_id(), 'desc' );

		if ( ! $rate_check['allowed'] ) {
			return $this->rateLimitResponse( $rate_check );
		}

		$data        = $request->get_json_params();
		$product_ids = array_filter( array_map( 'absint', $data['productIds'] ?? array() ) );
		$options     = $this->sanitize_generation_options( $data['options'] ?? array() );

		if ( empty( $product_ids ) ) {
			return $this->error_response( 'no_products', __( 'No products selected', 'ai-product-tools' ), 400 );
		}

		$content_types = $this->extract_content_types( $options );
		if ( empty( $content_types ) ) {
			return $this->error_response( 'no_content_types', __( 'No content types selected', 'ai-product-tools' ), 400 );
		}

		$credit_result = $this->validate_credits( count( $product_ids ), $content_types, $options );
		if ( is_wp_error( $credit_result ) ) {
			return $credit_result;
		}

		$result = $this->generator->generate( $product_ids, $content_types, $options );

		$this->deduct_credits( $credit_result, $content_types, $result->successCount );

		if ( (int) $result->successCount > 0 ) {
			\AIPT\Core\Services\UsageTracker::record_event(
				'advanced_desc',
				'generated',
				(int) $result->successCount,
				array( 'product_id' => (int) ( $product_ids[ array_key_first( $product_ids ) ] ?? 0 ) )
			);
		}

		$formatted_results = $this->format_bulk_results( $result, $content_types, $options );

		return new WP_REST_Response(
			array(
				'success'         => true,
				'results'         => $formatted_results,
				'summary'         => array(
					'total'          => count( $product_ids ),
					'successful'     => $result->successCount,
					'failed'         => $result->failureCount,
					'processingTime' => round( $result->processingTime, 2 ),
				),
				'current_balance' => $this->get_current_balance(),
			),
			200
		);
	}

	/**
	 * Preview the credit cost for a bulk generation without consuming any credits.
	 *
	 * This endpoint is READ-ONLY: it calls CreditManager::getCosts() and
	 * CreditManager::getBalance() to calculate the potential cost but NEVER
	 * calls CreditManager::use(). It is rate-limited to 30 req/min per user.
	 *
	 * @param WP_REST_Request $request The REST request.
	 * @return WP_REST_Response|WP_Error
	 */
	public function preview_cost( WP_REST_Request $request ) {
		$ai_gate = \AIPT\Core\Services\AiSupportGate::guard();
		if ( $ai_gate instanceof \WP_Error ) {
			return $ai_gate;
		}

		$rate_check = $this->checkRateLimit( (int) get_current_user_id(), 'desc_cost', 30, 60 );
		if ( ! $rate_check['allowed'] ) {
			return $this->rateLimitResponse( $rate_check );
		}

		$body        = $request->get_json_params();
		$product_ids = array_filter( array_map( 'absint', $body['productIds'] ?? array() ) );

		if ( empty( $product_ids ) ) {
			return new WP_Error(
				'no_products_selected',
				__( 'Please select at least one product.', 'ai-product-tools' ),
				array( 'status' => 400 )
			);
		}

		$options     = $this->sanitize_generation_options( $body['options'] ?? array() );

		$manager = CreditManager::getInstance();
		$costs   = $manager->getCosts();
		$balance = $manager->getBalance();

		$cost_per_product = 0;
		if ( ! empty( $options['generateDescription'] ) ) {
			$cost_per_product += $costs['description'] ?? 1;
		}
		if ( ! empty( $options['generateShortDescription'] ) ) {
			$cost_per_product += $costs['description'] ?? 1;
		}
		if ( ! empty( $options['generateTags'] ) ) {
			$additional_tags   = (int) ( $options['additionalTagsCount'] ?? 0 );
			$cost_per_product += ( $costs['tags'] ?? 1 ) * max( 1, $additional_tags );
		}

		if ( ! empty( $options['improveExistingDescription'] ) ) {
			$cost_per_product *= 2;
		}

		if ( $cost_per_product <= 0 ) {
			$cost_per_product = 1;
		}

		$product_count  = count( $product_ids );
		$total_cost     = $product_count * $cost_per_product;
		$available      = (int) ( $balance['available'] ?? 0 );
		$is_unlimited   = (bool) ( $balance['is_unlimited'] ?? false );

		return new WP_REST_Response(
			array(
				'success' => true,
				'preview' => array(
					'product_count'   => $product_count,
					'cost_per_product' => $cost_per_product,
					'total_cost'      => $total_cost,
					'remaining_after' => max( 0, $available - $total_cost ),
					'is_allowed'      => $is_unlimited || $available >= $total_cost,
					'is_unlimited'    => $is_unlimited,
					'breakdown'       => $costs,
				),
			),
			200
		);
	}

	private function validate_credits( int $product_count, array $content_types, array $options ) {
		$credit     = CreditManager::getInstance();
		$fs_manager = FsManager::getInstance();
		$plan_type  = $fs_manager->getPlanType();

		$descriptions_per_product = count( $content_types );
		if ( ! empty( $options['improveExistingDescription'] ) ) {
			$descriptions_per_product *= 2;
		}

		$total_descriptions = $product_count * $descriptions_per_product;
		$result             = $credit->check( 'description', $total_descriptions );

		if ( 'business' === $plan_type || PHP_INT_MAX === $result->remaining ) {
			return array(
				'plan_type'                => $plan_type,
				'total_descriptions'       => $total_descriptions,
				'descriptions_per_product' => $descriptions_per_product,
				'has_enough'               => true,
				'cost_per_item'            => 0,
				'total_cost'               => 0,
				'is_unlimited'             => true,
			);
		}

		if ( ! $result->allowed ) {
			return new WP_Error(
				'insufficient_credits',
				sprintf(
					/* translators: 1: required optimization requests, 2: available optimization requests */
					__( 'Not enough optimization requests. Required: %1$d, Available: %2$d', 'ai-product-tools' ),
					$result->cost,
					$result->remaining
				),
				array( 'status' => 403 )
			);
		}

		$costs = $credit->getCosts();

		return array(
			'plan_type'                => $plan_type,
			'total_descriptions'       => $total_descriptions,
			'descriptions_per_product' => $descriptions_per_product,
			'has_enough'               => true,
			'cost_per_item'            => $costs['description'] ?? 1,
			'total_cost'               => $result->cost,
			'is_unlimited'             => false,
		);
	}

	private function deduct_credits( array $credit_result, array $content_types, int $success_count = 1 ): void {
		if ( $credit_result['is_unlimited'] || 'business' === $credit_result['plan_type'] ) {
			return;
		}

		$credit            = CreditManager::getInstance();
		$items_per_product = $credit_result['descriptions_per_product'] ?? count( $content_types );
		$total_to_deduct   = $success_count * $items_per_product;

		$credit->use( 'description', $total_to_deduct );
	}

	private function get_current_balance(): array {
		$credit  = CreditManager::getInstance();
		$balance = $credit->getBalance();

		return array(
			'total'        => $balance['total'] ?? 0,
			'used'         => $balance['used'] ?? 0,
			'available'    => $balance['available'] ?? 0,
			'is_unlimited' => $balance['is_unlimited'] ?? false,
		);
	}

	private function format_bulk_results( $result, array $content_types, array $options ): array {
		$formatted = array();
		$provider_option = get_option( 'aipt_api_provider', 'openai' );
		if ( isset( $options['provider'] ) && is_string( $options['provider'] ) ) {
			$provider = $options['provider'];
		} elseif ( is_string( $provider_option ) ) {
			$provider = $provider_option;
		} else {
			$provider = 'openai';
		}

		foreach ( $result->results as $product_id => $product_result ) {
			if ( $product_result->success ) {

				foreach ( $content_types as $type ) {
					$db_type = $this->map_type_to_db( $type );
					if ( isset( $product_result->content[ $type ] ) ) {
						$formatted[] = array(
							'product_id' => $product_id,
							'success'    => true,
							'type'       => $db_type,
							'text'       => $product_result->content[ $type ],
							'status'     => 'pending',
						);
						continue;
					}
					$per_type_error = '';
					if (
						is_array( $product_result->errors )
						&& isset( $product_result->errors[ $type ] )
						&& is_string( $product_result->errors[ $type ] )
					) {
						$per_type_error = trim( $product_result->errors[ $type ] );
					}
					if ( '' === $per_type_error ) {
						$per_type_error = __(
							'Content type was not generated',
							'ai-product-tools'
						);
					}
					$formatted[] = array(
						'product_id' => $product_id,
						'success'    => false,
						'type'       => $db_type,
						'status'     => 'failed',
						'api_error'  => ErrorHandler::format_api_error_message(
							ucfirst( $provider ),
							$per_type_error
						),
					);
				}
			} else {
				$raw_error = '';
				if ( is_string( $product_result->errors ) && trim( $product_result->errors ) !== '' ) {
					$raw_error = $product_result->errors;
				} elseif ( is_wp_error( $product_result->errors ) ) {

					$raw_error = $product_result->errors->get_error_message();
				} elseif ( is_iterable( $product_result->errors ) ) {
					foreach ( $product_result->errors as $candidate ) {
						if ( is_string( $candidate ) && trim( $candidate ) !== '' ) {
							$raw_error = $candidate;
							break;
						}
						if ( is_wp_error( $candidate ) ) {
							$candidate_message = $candidate->get_error_message();
							if ( trim( $candidate_message ) !== '' ) {
								$raw_error = $candidate_message;
								break;
							}
						}
					}
				}
				if ( '' === $raw_error ) {
					$raw_error = __( 'Description generation failed', 'ai-product-tools' );
				}
				$formatted_error = ErrorHandler::format_api_error_message(
					ucfirst( $provider ),
					$raw_error
				);
				foreach ( $content_types as $content_type ) {
					$db_type     = $this->map_type_to_db( $content_type );
					$formatted[] = array(
						'product_id' => $product_id,
						'success'    => false,
						'type'       => $db_type,
						'api_error'  => $formatted_error,
					);
				}
			}
		}

		return $formatted;
	}

	private function map_type_to_db( string $type ): string {
		$mapping = array(
			'short_description' => 'short',
			'description'       => 'full',
			'tags'              => 'tags',
		);

		return $mapping[ $type ] ?? $type;
	}

	private function get_product_args(): array {
		return array(
			'search'            => array(
				'type'              => 'string',
				'required'          => false,
				'sanitize_callback' => 'sanitize_text_field',
			),
			'category'          => array(
				'type'              => 'string',
				'required'          => false,
				'sanitize_callback' => 'sanitize_text_field',
			),
			'tag'               => array(
				'type'              => 'string',
				'required'          => false,
				'sanitize_callback' => 'sanitize_text_field',
			),
			'status'            => array(
				'type'              => 'string',
				'required'          => false,
				'sanitize_callback' => 'sanitize_text_field',
			),
			'stock_status'      => array(
				'type'              => 'string',
				'required'          => false,
				'enum'              => array( 'instock', 'outofstock', 'onbackorder' ),
				'sanitize_callback' => 'sanitize_text_field',
			),
			'descriptionFilter' => array(
				'type'              => 'string',
				'required'          => false,
				'enum'              => array( 'with_both', 'with_full', 'with_short', 'without_both', 'without_full', 'without_short', 'with_tags', 'without_tags' ),
				'sanitize_callback' => 'sanitize_text_field',
			),
			'product_type'      => array(
				'type'              => 'string',
				'required'          => false,
				'enum'              => array( 'simple', 'variable', 'grouped', 'external' ),
				'sanitize_callback' => 'sanitize_text_field',
			),
			'featured'          => array(
				'type'     => 'boolean',
				'required' => false,
			),
			'on_sale'           => array(
				'type'     => 'boolean',
				'required' => false,
			),
			'price_min'         => array(
				'type'              => 'number',
				'required'          => false,
				'sanitize_callback' => 'floatval',
			),
			'price_max'         => array(
				'type'              => 'number',
				'required'          => false,
				'sanitize_callback' => 'floatval',
			),
			'date_after'        => array(
				'type'              => 'string',
				'required'          => false,
				'sanitize_callback' => 'sanitize_text_field',
			),
			'date_before'       => array(
				'type'              => 'string',
				'required'          => false,
				'sanitize_callback' => 'sanitize_text_field',
			),
			'filter_logic'      => array(
				'type'              => 'string',
				'required'          => false,
				'default'           => 'and',
				'enum'              => array( 'and', 'or' ),
				'sanitize_callback' => 'sanitize_text_field',
			),
			'has_image'         => array(
				'type'     => 'boolean',
				'required' => false,
			),
			'has_gallery'       => array(
				'type'     => 'boolean',
				'required' => false,
			),
			'sku_status'        => array(
				'type'              => 'string',
				'required'          => false,
				'enum'              => array( 'has_sku', 'no_sku' ),
				'sanitize_callback' => 'sanitize_text_field',
			),
			'stock_qty_min'     => array(
				'type'              => 'integer',
				'required'          => false,
				'sanitize_callback' => 'absint',
			),
			'stock_qty_max'     => array(
				'type'              => 'integer',
				'required'          => false,
				'sanitize_callback' => 'absint',
			),
			'page'              => array(
				'type'              => 'integer',
				'required'          => false,
				'default'           => 1,
				'sanitize_callback' => 'absint',
			),
			'per_page'          => array(
				'type'              => 'integer',
				'required'          => false,
				'default'           => 10,
				'minimum'           => 1,

			'maximum'           => 1000,
				'sanitize_callback' => 'absint',
			),
			'orderby'           => array(
				'type'              => 'string',
				'required'          => false,
				'default'           => 'date',
				'sanitize_callback' => 'sanitize_text_field',
			),
			'order'             => array(
				'type'              => 'string',
				'required'          => false,
				'default'           => 'DESC',
				'enum'              => array( 'ASC', 'DESC' ),
				'sanitize_callback' => 'sanitize_text_field',
			),
		);
	}
}
