<?php
/**
 * Ability Registrar Service
 *
 * Registers plugin capabilities with the WordPress Abilities API (WP 6.9+).
 * Exposes core AI generation features as discoverable abilities for external
 * AI agents and the WordPress command palette.
 *
 * @package AIPT\Core\Services
 * @since 2.5.11
 */

namespace AIPT\Core\Services;

defined( 'ABSPATH' ) || exit;

use AIPT\Api\Services\AIClientFactoryInterface;
use AIPT\Api\Services\ContentGenerationService;
use AIPT\Core\CreditSystem\CreditManager;

/**
 * Registers plugin abilities with the WordPress Abilities API
 *
 * Acts as a thin adapter layer over existing services.
 * Guarded by function_exists() for backward compatibility with WP < 6.9.
 *
 * @internal Used by Init
 *
 * Since 2.6.0: abilities expose meta.mcp.public + annotations for WP 7.0 MCP / AI tool calling.
 */
class AbilityRegistrar {

	/**
	 * Plugin ability category slug
	 *
	 * @var string
	 */
	private const CATEGORY = 'ai-product-tools';

	/**
	 * Ability ID prefix
	 *
	 * @var string
	 */
	private const PREFIX = 'ai-product-tools/';

	/**
	 * AI client factory
	 *
	 * @var AIClientFactoryInterface
	 */
	private $ai_client_factory;

	/**
	 * Constructor
	 *
	 * @param AIClientFactoryInterface $ai_client_factory AI client factory for provider instantiation.
	 */
	public function __construct( AIClientFactoryInterface $ai_client_factory ) {
		$this->ai_client_factory = $ai_client_factory;
	}

	/**
	 * Register hooks for Abilities API integration
	 *
	 * Does nothing if Abilities API is not available (WP < 6.9).
	 */
	public function register(): void {
		if ( ! WordPressRuntimeDetector::supportsAbilitiesApi() ) {
			return;
		}

		add_action( 'wp_abilities_api_categories_init', [ $this, 'registerCategory' ] );
		add_action( 'wp_abilities_api_init', [ $this, 'registerAbilities' ] );
	}

	/**
	 * Register the plugin ability category
	 */
	public function registerCategory(): void {
		WordPressRuntimeDetector::registerAbilityCategory( self::CATEGORY, [
			'label'       => __( 'AI Product Tools', 'ai-product-tools' ),
			'description' => __( 'AI-powered content generation abilities for WooCommerce: descriptions, titles, tags, SEO meta, and direct provider invocation.', 'ai-product-tools' ),
		] );
	}

	/**
	 * Register all plugin abilities
	 */
	public function registerAbilities(): void {
		$this->registerGenerateDescription();
		$this->registerGenerateTitle();
		$this->registerGenerateTags();
		$this->registerGenerateSeoMeta();
		$this->registerGetCreditBalance();
		$this->registerInvokeProvider();
	}

	/**
	 * Register generate-description ability
	 */
	private function registerGenerateDescription(): void {
		WordPressRuntimeDetector::registerAbility( self::PREFIX . 'generate-description', [
			'label'               => __( 'Generate Product Description', 'ai-product-tools' ),
			'description'         => __( 'Generates an AI-powered description for a WooCommerce product.', 'ai-product-tools' ),
			'category'            => self::CATEGORY,
			'input_schema'        => [
				'type'       => 'object',
				'properties' => [
					'product_id' => [
						'type'        => 'integer',
						'description' => 'WooCommerce product ID',
					],
					'is_short'   => [
						'type'        => 'boolean',
						'description' => 'Generate short description instead of full',
						'default'     => false,
					],
				],
				'required'   => [ 'product_id' ],
			],
			'output_schema'       => [
				'type'       => 'object',
				'properties' => [
					'description' => [
						'type'        => 'string',
						'description' => 'Generated HTML description',
					],
				],
			],
			'execute_callback'    => [ $this, 'executeGenerateDescription' ],
			'permission_callback' => [ $this, 'check_permissions_write' ],
			'meta'                => [
				'show_in_rest' => true,
				'mcp'          => [
					'public' => true,
					'type'   => 'tool',
				],
				'annotations'  => [
					'readonly'    => false,
					'destructive' => false,
					'idempotent'  => false,
				],
			],
		] );
	}

	/**
	 * Register generate-title ability
	 */
	private function registerGenerateTitle(): void {
		WordPressRuntimeDetector::registerAbility( self::PREFIX . 'generate-title', [
			'label'               => __( 'Generate Product Title', 'ai-product-tools' ),
			'description'         => __( 'Generates an AI-powered title for a WooCommerce product.', 'ai-product-tools' ),
			'category'            => self::CATEGORY,
			'input_schema'        => [
				'type'       => 'object',
				'properties' => [
					'product_id' => [
						'type'        => 'integer',
						'description' => 'WooCommerce product ID',
					],
					'max_length' => [
						'type'        => 'integer',
						'description' => 'Maximum title length in characters',
						'default'     => 60,
					],
					'tone'       => [
						'type'        => 'string',
						'description' => 'Writing tone (e.g. SEO-Focused, Professional, Creative)',
						'default'     => 'SEO-Focused',
					],
				],
				'required'   => [ 'product_id' ],
			],
			'output_schema'       => [
				'type'       => 'object',
				'properties' => [
					'title' => [
						'type'        => 'string',
						'description' => 'Generated product title',
					],
				],
			],
			'execute_callback'    => [ $this, 'executeGenerateTitle' ],
			'permission_callback' => [ $this, 'check_permissions_write' ],
			'meta'                => [
				'show_in_rest' => true,
				'mcp'          => [
					'public' => true,
					'type'   => 'tool',
				],
				'annotations'  => [
					'readonly'    => false,
					'destructive' => false,
					'idempotent'  => false,
				],
			],
		] );
	}

	/**
	 * Register generate-tags ability
	 */
	private function registerGenerateTags(): void {
		WordPressRuntimeDetector::registerAbility( self::PREFIX . 'generate-tags', [
			'label'               => __( 'Generate Product Tags', 'ai-product-tools' ),
			'description'         => __( 'Generates AI-powered tags for a WooCommerce product.', 'ai-product-tools' ),
			'category'            => self::CATEGORY,
			'input_schema'        => [
				'type'       => 'object',
				'properties' => [
					'product_id'    => [
						'type'        => 'integer',
						'description' => 'WooCommerce product ID',
					],
					'max_tags'      => [
						'type'        => 'integer',
						'description' => 'Maximum number of tags to generate',
						'default'     => 5,
					],
					'keep_existing' => [
						'type'        => 'boolean',
						'description' => 'Keep existing tags and add complementary ones',
						'default'     => false,
					],
				],
				'required'   => [ 'product_id' ],
			],
			'output_schema'       => [
				'type'       => 'object',
				'properties' => [
					'tags'      => [
						'type'        => 'array',
						'items'       => [ 'type' => 'string' ],
						'description' => 'Generated tags array',
					],
					'tags_text' => [
						'type'        => 'string',
						'description' => 'Comma-separated tags string',
					],
				],
			],
			'execute_callback'    => [ $this, 'executeGenerateTags' ],
			'permission_callback' => [ $this, 'check_permissions_write' ],
			'meta'                => [
				'show_in_rest' => true,
				'mcp'          => [
					'public' => true,
					'type'   => 'tool',
				],
				'annotations'  => [
					'readonly'    => false,
					'destructive' => false,
					'idempotent'  => false,
				],
			],
		] );
	}

	/**
	 * Register generate-seo-meta ability
	 */
	private function registerGenerateSeoMeta(): void {
		WordPressRuntimeDetector::registerAbility( self::PREFIX . 'generate-seo-meta', [
			'label'               => __( 'Generate SEO Meta', 'ai-product-tools' ),
			'description'         => __( 'Generates AI-powered SEO meta title and description for a WooCommerce product.', 'ai-product-tools' ),
			'category'            => self::CATEGORY,
			'input_schema'        => [
				'type'       => 'object',
				'properties' => [
					'product_id' => [
						'type'        => 'integer',
						'description' => 'WooCommerce product ID',
					],
				],
				'required'   => [ 'product_id' ],
			],
			'output_schema'       => [
				'type'       => 'object',
				'properties' => [
					'meta_title'       => [
						'type'        => 'string',
						'description' => 'Generated SEO meta title',
					],
					'meta_description' => [
						'type'        => 'string',
						'description' => 'Generated SEO meta description',
					],
				],
			],
			'execute_callback'    => [ $this, 'executeGenerateSeoMeta' ],
			'permission_callback' => [ $this, 'check_permissions_write' ],
			'meta'                => [
				'show_in_rest' => true,
				'mcp'          => [
					'public' => true,
					'type'   => 'tool',
				],
				'annotations'  => [
					'readonly'    => false,
					'destructive' => false,
					'idempotent'  => false,
				],
			],
		] );
	}

	/**
	 * Register get-credit-balance ability (read-only)
	 */
	private function registerGetCreditBalance(): void {
		WordPressRuntimeDetector::registerAbility( self::PREFIX . 'get-credit-balance', [
			'label'               => __( 'Get Credit Balance', 'ai-product-tools' ),
			'description'         => __( 'Returns the current AI credit balance and usage summary.', 'ai-product-tools' ),
			'category'            => self::CATEGORY,
			'output_schema'       => [
				'type'       => 'object',
				'properties' => [
					'total'        => [
						'type'        => 'number',
						'description' => 'Total credits allocated',
					],
					'used'         => [
						'type'        => 'number',
						'description' => 'Credits used',
					],
					'available'    => [
						'type'        => 'number',
						'description' => 'Credits remaining',
					],
					'is_unlimited' => [
						'type'        => 'boolean',
						'description' => 'Whether the plan has unlimited credits',
					],
				],
			],
			'execute_callback'    => [ $this, 'executeGetCreditBalance' ],
			'permission_callback' => [ $this, 'check_permissions' ],
			'meta'                => [
				'show_in_rest' => true,
				'readonly'     => true,

				'mcp'          => [
					'public' => true,
					'type'   => 'tool',
				],
				'annotations'  => [
					'readonly'    => true,
					'destructive' => false,
					'idempotent'  => true,
				],
			],
		] );
	}

	/**
	 * Register invoke-provider ability
	 *
	 * Exposes a generic AI prompt passthrough to Abilities API consumers.
	 * Gated by manage_woocommerce to prevent unauthorized token spend.
	 *
	 * @since 2.6.0
	 */
	private function registerInvokeProvider(): void {
		WordPressRuntimeDetector::registerAbility( self::PREFIX . 'invoke-provider', [
			'label'               => __( 'Invoke AI Provider', 'ai-product-tools' ),
			'description'         => __( 'Executes a prompt against the currently configured AI provider. Useful for AI agents and tool-calling clients.', 'ai-product-tools' ),
			'category'            => self::CATEGORY,
			'input_schema'        => [
				'type'       => 'object',
				'properties' => [
					'prompt'   => [
						'type'        => 'string',
						'description' => 'The user prompt to send to the AI provider.',
						'minLength'   => 1,
						'maxLength'   => 8000,
					],
					'provider' => [
						'type'        => 'string',
						'description' => 'Optional provider id (openai / gemini / claude / openrouter). Defaults to the current aipt_api_provider option.',
						'enum'        => [ 'openai', 'gemini', 'claude', 'openrouter' ],
					],
					'model'    => [
						'type'        => 'string',
						'description' => 'Optional model identifier. Defaults to the provider default.',
					],
				],
				'required'             => [ 'prompt' ],
				'additionalProperties' => false,
			],
			'output_schema'       => [
				'type'       => 'object',
				'properties' => [
					'text'             => [ 'type' => 'string' ],
					'provider'         => [ 'type' => 'string' ],
					'model'            => [ 'type' => 'string' ],
					'tokenUsage'       => [ 'type' => [ 'object', 'null' ] ],
					'providerMetadata' => [ 'type' => [ 'object', 'null' ] ],
				],
				'required' => [ 'text', 'provider' ],
			],
			'execute_callback'    => [ \AIPT\Core\Abilities\InvokeProviderAbility::class, 'execute' ],
			'permission_callback' => [ \AIPT\Core\Abilities\InvokeProviderAbility::class, 'permission_check' ],
			'meta'                => [
				'show_in_rest' => true,
				'mcp'          => [
					'public' => true,
					'type'   => 'tool',
				],
				'annotations'  => [
					'readonly'    => false,
					'destructive' => false,
					'idempotent'  => false,
				],
			],
		] );
	}

	/**
	 * Execute generate-description ability
	 *
	 * @param array $input Validated input (product_id, is_short).
	 * @return array|\WP_Error Generated description or error.
	 */
	public function executeGenerateDescription( array $input ) {
		$credit_check = $this->checkCredits( 'description' );
		if ( is_wp_error( $credit_check ) ) {
			return $credit_check;
		}

		$service = $this->createContentGenerationService();
		$result  = $service->generateDescription( [
			'product_id' => absint( $input['product_id'] ),
			'is_short'   => ! empty( $input['is_short'] ),
		] );

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

		$this->useCredits( 'description' );

		return $result;
	}

	/**
	 * Execute generate-title ability
	 *
	 * Title generation is NOT part of the Advanced Description Generator
	 * and therefore MUST NOT touch the Ctrl credit ledger. See AGENTS.md
	 * (Core/CreditSystem section) for the scoping rule.
	 *
	 * @param array $input Validated input (product_id, max_length, tone).
	 * @return array|\WP_Error Generated title or error.
	 */
	public function executeGenerateTitle( array $input ) {
		$service = $this->createContentGenerationService();
		$result  = $service->generateTitle( [
			'product_id' => absint( $input['product_id'] ),
			'max_length' => isset( $input['max_length'] ) ? absint( $input['max_length'] ) : 60,
			'tone'       => isset( $input['tone'] ) ? sanitize_text_field( $input['tone'] ) : 'SEO-Focused',
		] );

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

		return $result;
	}

	/**
	 * Execute generate-tags ability
	 *
	 * @param array $input Validated input (product_id, max_tags, keep_existing).
	 * @return array|\WP_Error Generated tags or error.
	 */
	public function executeGenerateTags( array $input ) {
		$credit_check = $this->checkCredits( 'tags' );
		if ( is_wp_error( $credit_check ) ) {
			return $credit_check;
		}

		$service = $this->createContentGenerationService();
		$result  = $service->generateTags( [
			'product_id'    => absint( $input['product_id'] ),
			'max_tags'      => isset( $input['max_tags'] ) ? absint( $input['max_tags'] ) : 5,
			'keep_existing' => ! empty( $input['keep_existing'] ),
		] );

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

		$this->useCredits( 'tags' );

		return $result;
	}

	/**
	 * Execute generate-seo-meta ability
	 *
	 * SEO Meta generation is NOT part of the Advanced Description Generator
	 * and therefore MUST NOT touch the Ctrl credit ledger. See AGENTS.md
	 * (Core/CreditSystem section) for the scoping rule.
	 *
	 * Delegates to the SeoMeta bulk generator service for single-product generation.
	 *
	 * @param array $input Validated input (product_id).
	 * @return array|\WP_Error Generated SEO meta or error.
	 */
	public function executeGenerateSeoMeta( array $input ) {
		$product_id = absint( $input['product_id'] );
		$product    = wc_get_product( $product_id );

		if ( ! $product ) {
			return new \WP_Error(
				'invalid_product',
				__( 'Invalid product ID.', 'ai-product-tools' ),
				[ 'status' => 404 ]
			);
		}

		try {
			$service = new \AIPT\Api\BulkGenerator\SeoMeta\SeoMetaGeneratorService();
			$results = $service->bulk_generate( [ $product_id ], [] );

			if ( empty( $results ) || ! isset( $results[0] ) ) {
				return new \WP_Error(
					'generation_failed',
					__( 'SEO meta generation failed to produce a result.', 'ai-product-tools' ),
					[ 'status' => 500 ]
				);
			}

			$result = $results[0];

			if ( ! empty( $result['error'] ) ) {
				return new \WP_Error(
					'generation_failed',
					esc_html( $result['error'] ),
					[ 'status' => 500 ]
				);
			}

			return [
				'meta_title'       => $result['meta_title'] ?? '',
				'meta_description' => $result['meta_description'] ?? '',
			];
		} catch ( \Throwable $e ) {
			return new \WP_Error(
				'generation_failed',
				esc_html( $e->getMessage() ),
				[ 'status' => 500 ]
			);
		}
	}

	/**
	 * Execute get-credit-balance ability
	 *
	 * @param array $input Unused for this read-only ability.
	 * @return array|\WP_Error Credit balance data or error.
	 */
	public function executeGetCreditBalance( array $input = [] ) {
		$credit_manager = CreditManager::getInstance();

		if ( ! $credit_manager->isRegistered() ) {
			return new \WP_Error(
				'not_registered',
				__( 'Site is not registered with the credit system.', 'ai-product-tools' ),
				[ 'status' => 403 ]
			);
		}

		$balance = $credit_manager->getBalance();

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

	/**
	 * Check write permissions for generation abilities
	 *
	 * @return bool True if current user has manage_woocommerce capability.
	 */
	public function check_permissions_write(): bool {
		return current_user_can( 'manage_woocommerce' );
	}

	/**
	 * Check read permissions for informational abilities
	 *
	 * @return bool True if current user has manage_options capability.
	 */
	public function check_permissions(): bool {
		return current_user_can( 'manage_options' );
	}

	/**
	 * Check if credits are available for the given action
	 *
	 * @param string $action Credit action type.
	 * @return true|\WP_Error True if credits available, WP_Error otherwise.
	 */
	private function checkCredits( string $action ) {
		$credit_manager = CreditManager::getInstance();

		if ( ! $credit_manager->isRegistered() ) {
			return new \WP_Error(
				'not_registered',
				__( 'Site is not registered with the credit system.', 'ai-product-tools' ),
				[ 'status' => 403 ]
			);
		}

		$check = $credit_manager->check( $action );

		if ( ! $check->allowed ) {
			return new \WP_Error(
				'insufficient_credits',
				sprintf(
					/* translators: 1: required optimization requests, 2: available optimization requests */
					__( 'Insufficient optimization requests. Required: %1$s, Available: %2$s', 'ai-product-tools' ),
					$check->cost,
					$check->remaining
				),
				[ 'status' => 402 ]
			);
		}

		return true;
	}

	/**
	 * Deduct credits for the given action
	 *
	 * @param string $action Credit action type.
	 */
	private function useCredits( string $action ): void {
		CreditManager::getInstance()->use( $action );
	}

	/**
	 * Create ContentGenerationService instance
	 *
	 * @return ContentGenerationService
	 */
	private function createContentGenerationService(): ContentGenerationService {
		$style_descriptions = [
			'Professional'        => 'Use clear, concise, and formal language. Focus on features, benefits, and technical details.',
			'Encouraging'         => 'Use positive, motivational language that inspires confidence and action.',
			'Exaggerated'         => 'Use dramatic and hyperbolic language to create excitement and emphasis.',
			'Friendly'            => 'Use warm, conversational language that builds rapport and trust.',
			'Storytelling'        => 'Create a narrative that engages readers and connects emotionally.',
			'Minimalist'          => 'Use simple, straightforward language focusing on essential details.',
			'Luxurious and Elegant' => 'Use sophisticated, refined language that conveys premium quality and exclusivity.',
			'Adventurous'         => 'Use dynamic, exciting language that creates a sense of exploration and discovery.',
			'Educational'         => 'Use informative, detailed language that explains and educates.',
			'Humorous'            => 'Use light-hearted, playful language with appropriate humor and wit.',
		];

		/**
		 * Filter style descriptions for content generation
		 *
		 * @param array $style_descriptions Style name => description map.
		 */
		$style_descriptions = apply_filters( 'aipt_ability_style_descriptions', $style_descriptions );

		return new ContentGenerationService( $this->ai_client_factory, $style_descriptions );
	}
}
