<?php

namespace Antimanual\Api;

use Antimanual\Encryption;
use Antimanual\Mcp\McpServer;
use Antimanual\Tools\ToolRegistry;

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

/**
 * Admin REST endpoints for configuring the MCP server.
 *
 * Manages the enable flag, access level, per-tool exposure, and the bearer
 * token (generated once, stored encrypted, shown to the admin a single time).
 */
class McpController {

	/**
	 * Register routes.
	 *
	 * @param string $namespace REST namespace.
	 */
	public function register_routes( string $namespace ) {
		register_rest_route(
			$namespace,
			'/mcp-settings',
			[
				[
					'methods'             => 'GET',
					'callback'            => [ $this, 'get_settings' ],
					'permission_callback' => fn() => current_user_can( 'manage_options' ),
				],
				[
					'methods'             => 'POST',
					'callback'            => [ $this, 'save_settings' ],
					'permission_callback' => fn() => current_user_can( 'manage_options' ),
				],
			]
		);

		register_rest_route(
			$namespace,
			'/mcp-settings/token',
			[
				[
					'methods'             => 'POST',
					'callback'            => [ $this, 'regenerate_token' ],
					'permission_callback' => fn() => current_user_can( 'manage_options' ),
				],
				[
					'methods'             => 'DELETE',
					'callback'            => [ $this, 'delete_token' ],
					'permission_callback' => fn() => current_user_can( 'manage_options' ),
				],
			]
		);
	}

	/**
	 * Return the current MCP settings plus the catalog of exposable tools.
	 *
	 * @return \WP_REST_Response
	 */
	public function get_settings() {
		$settings = McpServer::get_settings();

		$owner = ! empty( $settings['owner_id'] ) ? get_userdata( (int) $settings['owner_id'] ) : null;

		return rest_ensure_response(
			[
				'success' => true,
				'data'    => [
					'enabled'       => (bool) $settings['enabled'],
					'access_level'  => $settings['access_level'],
					'has_token'     => ! empty( $settings['token'] ),
					'token_created' => (int) ( $settings['token_created'] ?? 0 ),
					'token_owner'   => $owner ? $owner->display_name : '',
					'endpoint_url'  => rest_url( 'antimanual/v1/mcp' ),
					'tools'         => $this->tool_catalog( $settings ),
				],
			]
		);
	}

	/**
	 * Build the list of all tools with their exposure state.
	 *
	 * @param array $settings Settings.
	 * @return array<int, array>
	 */
	private function tool_catalog( array $settings ): array {
		$saved = $settings['tools'] ?? [];
		$out   = [];

		foreach ( ToolRegistry::all() as $name => $tool ) {
			$out[] = [
				'name'        => $name,
				'title'       => $tool['title'],
				'description' => $tool['description'],
				'read_only'   => (bool) $tool['read_only'],
				'enabled'     => ! array_key_exists( $name, $saved ) || ! empty( $saved[ $name ] ),
			];
		}

		return $out;
	}

	/**
	 * Persist enable flag, access level, and per-tool exposure.
	 *
	 * @param \WP_REST_Request $request Request.
	 * @return \WP_REST_Response
	 */
	public function save_settings( $request ) {
		$payload = json_decode( $request->get_body(), true );
		$payload = is_array( $payload ) ? $payload : [];

		$current = McpServer::get_settings();

		$access = ( isset( $payload['access_level'] ) && 'write' === $payload['access_level'] ) ? 'write' : 'read';

		$valid_tools = array_keys( ToolRegistry::all() );
		$tools       = [];
		if ( isset( $payload['tools'] ) && is_array( $payload['tools'] ) ) {
			foreach ( $payload['tools'] as $name => $on ) {
				$name = sanitize_key( (string) $name );
				if ( in_array( $name, $valid_tools, true ) ) {
					$tools[ $name ] = (bool) $on;
				}
			}
		}

		$settings = [
			'enabled'       => ! empty( $payload['enabled'] ),
			'access_level'  => $access,
			'token'         => $current['token'],     // preserved; managed by token routes
			'token_created' => (int) ( $current['token_created'] ?? 0 ),
			'owner_id'      => (int) $current['owner_id'],
			'tools'         => $tools,
		];

		update_option( McpServer::OPTION, $settings );

		return rest_ensure_response(
			[
				'success' => true,
				'data'    => [ 'message' => __( 'MCP settings saved.', 'antimanual' ) ],
			]
		);
	}

	/**
	 * Generate a new bearer token, store it encrypted, and return it once.
	 *
	 * @return \WP_REST_Response
	 */
	public function regenerate_token() {
		$raw = 'atml_mcp_' . bin2hex( random_bytes( 24 ) );

		$current                  = McpServer::get_settings();
		$current['token']         = Encryption::encrypt( $raw );
		$current['token_created'] = time();
		$current['owner_id']      = get_current_user_id();

		update_option( McpServer::OPTION, $current );

		return rest_ensure_response(
			[
				'success' => true,
				'data'    => [
					'token'   => $raw, // shown to the admin only this once
					'message' => __( 'New MCP token generated. Copy it now — it will not be shown again.', 'antimanual' ),
				],
			]
		);
	}

	/**
	 * Revoke the current token.
	 *
	 * @return \WP_REST_Response
	 */
	public function delete_token() {
		$current                  = McpServer::get_settings();
		$current['token']         = '';
		$current['token_created'] = 0;

		update_option( McpServer::OPTION, $current );

		return rest_ensure_response(
			[
				'success' => true,
				'data'    => [ 'message' => __( 'MCP token revoked.', 'antimanual' ) ],
			]
		);
	}
}
