<?php

namespace Limb_Chatbot\Includes\Api\V1\Controllers;

use Exception;
use Limb_Chatbot\Includes\Services\Data_Deletion_Service;
use Limb_Chatbot\Includes\Services\Helper;
use Limb_Chatbot\Includes\Services\Install;
use Limb_Chatbot\Includes\Services\Migration_Service;
use Limb_Chatbot\Includes\Services\Seeder_Service;
use Limb_Chatbot\Includes\Repositories\Setting_Repository;
use Limb_Chatbot\Includes\Data_Schemas\Setting as Setting_Schema;
use Limb_Chatbot\Includes\Services\Sanitizer;
use Limb_Chatbot\Includes\Services\User_Manager;
use Limb_Chatbot\Includes\Services\Validator;
use Limb_Chatbot\Includes\Services\Session_Manager;
use WP_REST_Request;
use WP_REST_Response;
use WP_Error;
use WP_REST_Server;

/**
 * REST API controller for core plugin operations.
 *
 * Handles plugin-level operations following REST principles.
 * Currently supports data deletion, but can be extended for other core operations.
 *
 * @since 1.0.0
 */
class Plugin_Controller extends Rest_Controller {

	/**
	 * Route base for the controller.
	 *
	 * @var string
	 * @since 1.0.0
	 */
	protected $rest_base = 'plugin';

	/**
	 * Registers REST routes for the controller.
	 *
	 * @return void
	 * @since 1.0.0
	 */
	public function register_routes(): void {
		// DELETE /limb/chatbot/v1/plugin/data - Delete all plugin data
		register_rest_route(
			$this->namespace, '/' . $this->rest_base . '/data',
			array(
				array(
					'methods'             => WP_REST_Server::DELETABLE,
					'callback'            => array( $this, 'delete_plugin_data' ),
					'permission_callback' => array( $this, 'permission_callback' ),
				),
			)
		);
		// POST /limb/chatbot/v1/plugin/migrate - Run the migrations
		register_rest_route(
			$this->namespace, '/' . $this->rest_base . '/migrate',
			array(
				array(
					'methods'             => WP_REST_Server::CREATABLE,
					'callback'            => array( $this, 'migrate' ),
					'permission_callback' => array( $this, 'permission_callback' ),
				),
			)
		);
		// GET /limb/chatbot/v1/plugin/migration-status - Check migration status
		register_rest_route(
			$this->namespace, '/' . $this->rest_base . '/migration-status',
			array(
				array(
					'methods'             => WP_REST_Server::READABLE,
					'callback'            => array( $this, 'get_migration_status' ),
					'permission_callback' => array( $this, 'permission_callback' ),
				),
			)
		);
		// GET /limb/chatbot/v1/plugin/nonce - Generate a nonce for frontend use
		register_rest_route(
			$this->namespace, '/' . $this->rest_base . '/nonce',
			array(
				array(
					'methods'             => WP_REST_Server::READABLE,
					'callback'            => array( $this, 'generate_nonce' ),
					'permission_callback' => '__return_true',
				),
			)
		);
		// POST /limb/chatbot/v1/plugin/deactivation-reason - Submit deactivation feedback
		register_rest_route(
			$this->namespace, '/' . $this->rest_base . '/deactivation',
			array(
				array(
					'methods'             => WP_REST_Server::CREATABLE,
					'callback'            => array( $this, 'submit_deactivation_reason' ),
					'permission_callback' => array( $this, 'permission_callback' ),
				),
			)
		);

		// POST /limb/chatbot/v1/plugin/notifications
		// Update the unified notification setting (`lbaic.plugin.notifications`).
		register_rest_route(
			$this->namespace,
			'/' . $this->rest_base . '/notifications',
			[
				[
					'methods'             => WP_REST_Server::EDITABLE,
					'callback'            => [ $this, 'update_notifications_setting' ],
					'permission_callback' => [ $this, 'permission_callback' ],
				],
			]
		);
	}

	/**
	 * POST /plugin/notifications
	 *
	 * Request body:
	 * {
	 *   "value": { ... } // must match `lbaic.plugin.notifications` structure
	 * }
	 *
	 * @return WP_REST_Response|WP_Error
	 * @since 2.0.0
	 */
	public function update_notifications_setting( WP_REST_Request $request ) {
		try {
			$key_primary = 'lbaic.plugin.notifications';
			$key_alias   = 'lbaic.plugin.notification_types';
			$data        = $request->get_json_params();
			$value       = $data['value'] ?? null;

			$setting_repository = new Setting_Repository();
			$sanitize           = new Sanitizer( new Setting_Schema() );
			$validator          = new Validator( new Setting_Schema() );

			// Settings_Controller uses "create" context for both create/update validation.
			// That means our schema's validation will enforce required structure.
			$sanitize->sanitize( [ $key_primary => $value ], 'create', false, [ $key_primary ] );
			$validator->validate( $sanitize->get_sanitized(), 'create', false, [ $key_primary ] );

			if ( $validator->has_errors() ) {
				return rest_ensure_response( $validator->get_error() );
			}

			$validated_value = $validator->get_validated()[ $key_primary ] ?? [];

			// Persist both keys so either naming convention works.
			$primary_setting = $setting_repository->update( $key_primary, [ 'value' => $validated_value ] );
			$alias_setting   = $setting_repository->update( $key_alias, [ 'value' => $validated_value ] );

			return rest_ensure_response(
				[
					'primary' => $primary_setting,
					'alias'   => $alias_setting,
				]
			);
		} catch ( \Exception $e ) {
			Helper::log( $e, __METHOD__ );

			return Helper::get_wp_error( $e );
		}
	}

	/**
	 * Deletes all plugin data via REST API.
	 *
	 * This endpoint deletes all plugin tables and options without checking
	 * the lbaic.plugin.remove_plugin_data setting.
	 *
	 * Follows REST principle: DELETE operation removes the resource (plugin data).
	 *
	 * @param  WP_REST_Request  $request  Incoming REST request.
	 *
	 * @return WP_REST_Response|WP_Error REST response or error.
	 * @since 1.0.0
	 */
	public function delete_plugin_data( WP_REST_Request $request ) {
		try {
			$deletion_service = Data_Deletion_Service::instance();
			if ( $deletion_service->delete_all_data() ) {
				$install = Install::instance();
				$install->create_tables();
				( new Seeder_Service( true ) )->seed();
			}


			return rest_ensure_response( array( 'success' => true ) );
		} catch ( Exception $e ) {
			Helper::log( $e, __METHOD__ );

			return Helper::get_wp_error( $e );
		}
	}

	/**
	 * Execute database migrations via REST API.
	 *
	 * This endpoint checks if the database needs migration and executes all
	 * necessary migrations to bring the database schema up to date with the
	 * current plugin version.
	 *
	 * Response includes:
	 * - success: Boolean indicating migration success
	 * - version_changed: Boolean indicating if version was updated
	 * - from_version: Original database version
	 * - to_version: Target plugin version
	 * - migrations_run: Array of executed migrations with details
	 * - message: Human-readable status message
	 * - errors: Array of error messages (if any)
	 *
	 * @param  WP_REST_Request  $request  Incoming REST request.
	 *
	 * @return WP_REST_Response|WP_Error REST response with migration results or error.
	 * @since 1.0.0
	 */
	public function migrate( WP_REST_Request $request ) {
		try {
			$migration_service = new Migration_Service();
			$results           = $migration_service->migrate();

			return rest_ensure_response( $results );
		} catch ( Exception $e ) {
			Helper::log( $e, __METHOD__ );

			return Helper::get_wp_error( $e );
		}
	}

	/**
	 * Get migration status without executing migrations.
	 *
	 * This endpoint checks if the database needs migration and returns
	 * information about the current state without executing any migrations.
	 *
	 * Response includes:
	 * - current_version: Current plugin version from code
	 * - db_version: Database version from options
	 * - needs_migration: Boolean indicating if migration is needed
	 * - up_to_date: Boolean indicating if database is current
	 *
	 * @param  WP_REST_Request  $request  Incoming REST request.
	 *
	 * @return WP_REST_Response|WP_Error REST response with status or error.
	 * @since 1.0.0
	 */
	public function get_migration_status( WP_REST_Request $request ) {
		try {
			$migration_service = new Migration_Service();

			return rest_ensure_response(
				array(
					'current_version' => $migration_service->get_current_version(),
					'db_version'      => $migration_service->get_db_version(),
					'needs_migration' => ! $migration_service->is_up_to_date(),
					'up_to_date'      => $migration_service->is_up_to_date(),
				)
			);
		} catch ( Exception $e ) {
			Helper::log( $e, __METHOD__ );

			return Helper::get_wp_error( $e );
		}
	}

	/**
	 * Generate a nonce for frontend use via REST API.
	 *
	 * This endpoint generates a WordPress REST API nonce that can be used
	 * by the frontend to authenticate subsequent API requests. The nonce
	 * should be included in the X-WP-Nonce header for authenticated requests.
	 *
	 * @param  WP_REST_Request  $request  Incoming REST request.
	 *
	 * @return WP_REST_Response|WP_Error Nonce payload or error.
	 * @since 1.0.0
	 */
	public function generate_nonce( WP_REST_Request $request ) {
		try {
			$session_manager = Session_Manager::instance();
			$nonce           = $session_manager->get_nonce();
			$expires         = $session_manager->get_nonce_expiration();
			$user            = User_Manager::instance()->get_current_user();

			// Prevent caching: a cached body would serve a nonce minted for another user/session.
			$response = rest_ensure_response(
				array(
					'nonce'             => $nonce,
					'expires'           => $expires,
					'chatbot_user_uuid' => $user->uuid,
				)
			);

			$response->header( 'Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0' );
			$response->header( 'Pragma', 'no-cache' );
			$response->header( 'Expires', '0' );

			return $response;
		} catch ( Exception $e ) {
			Helper::log( $e, __METHOD__ );

			return Helper::get_wp_error( $e );
		}
	}

	/**
	 * Checks whether the current user has permission to manage plugin core operations.
	 *
	 * Only allows logged-in users with administrative capabilities.
	 *
	 * @param  WP_REST_Request  $request  Incoming REST request.
	 *
	 * @return bool True if authorized, false otherwise.
	 * @since 1.0.0
	 */
	public function permission_callback( $request ): bool {
		// Only allow admin users to manage core plugin operations
		return current_user_can( 'manage_options' );
	}

	/**
	 * Submit deactivation reason to external API.
	 *
	 * This endpoint receives deactivation feedback from the admin and forwards
	 * it to the external wpaichatbot.com API using wp_remote_post to avoid CORS.
	 * Data is encrypted using RSA public key before transmission.
	 *
	 * @param  WP_REST_Request  $request  Incoming REST request.
	 *
	 * @return WP_REST_Response|WP_Error REST response or error.
	 * @since 1.0.0
	 */
	public function submit_deactivation_reason( WP_REST_Request $request ) {
		try {
			$data = array(
				'site_url'           => sanitize_url( $request->get_param( 'site_url' ) ),
				'site_mode'          => sanitize_text_field( $request->get_param( 'site_mode' ) ),
				'reason'             => sanitize_text_field( $request->get_param( 'reason' ) ),
				'sub_reason'         => sanitize_text_field( $request->get_param( 'sub_reason' ) ),
				'additional_details' => sanitize_textarea_field( $request->get_param( 'additional_details' ) ),
				'date'               => sanitize_text_field( $request->get_param( 'date' ) ),
				'timestamp'          => time(),
			);

			$response = wp_remote_post(
				'https://wpaichatbot.com/wp-json/limb/deactive-reason',
				array(
					'timeout' => 5,
					'headers' => array(
						'Content-Type' => 'application/json',
					),
					'body'    => wp_json_encode( $data ),
				)
			);

			if ( is_wp_error( $response ) ) {
				// Log error but still return success to not block deactivation
				Helper::log( $response->get_error_message(), __METHOD__ );
			}

			return rest_ensure_response( array( 'success' => true ) );
		} catch ( Exception $e ) {
			Helper::log( $e, __METHOD__ );

			// Return success anyway to not block deactivation
			return rest_ensure_response( array( 'success' => true ) );
		}
	}
}
