<?php

namespace VendorTasksDokanClickUp\Rest;

use VendorTasksDokanClickUp\API\ClickUpClient;
use VendorTasksDokanClickUp\VendorIntegration\VendorTaskState;
use WP_Error;
use WP_REST_Request;
use WP_REST_Response;
use WP_REST_Server;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * REST API Controller
 *
 * Handles ClickUp integration REST API endpoints for admin settings.
 *
 * @since 1.0.0
 * @package VendorTasksDokanClickUp
 * @subpackage Rest
 */
class ConnectivityController {

	/**
	 * API namespace
	 */
	public const NAMESPACE = 'vendor-tasks-dokan-clickup/v1';

	/**
	 * Class constructor
	 *
	 * Automatically registers hooks following Dokan pattern
	 *
	 * @since 1.0.0
	 */
	public function __construct() {
		add_action( 'rest_api_init', array( $this, 'register_routes' ) );
	}

	/**
	 * Register REST API routes
	 *
	 * @since 1.0.0
	 *
	 * @return void
	 */
	public function register_routes(): void {
		// Get ClickUp workspaces
		register_rest_route(
			self::NAMESPACE,
			'/workspaces',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $this, 'get_workspaces' ),
				'permission_callback' => array( $this, 'check_admin_permission' ),
				'args'                => array(
					'api_token' => array(
						'required'          => false,
						'type'              => 'string',
						'sanitize_callback' => 'sanitize_text_field',
						'default'           => '',
					),
				),
			)
		);

		// Get ClickUp lists for a workspace
		register_rest_route(
			self::NAMESPACE,
			'/lists',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $this, 'get_lists' ),
				'permission_callback' => array( $this, 'check_admin_permission' ),
				'args'                => array(
					'api_token'    => array(
						'required'          => false,
						'type'              => 'string',
						'sanitize_callback' => 'sanitize_text_field',
						'default'           => '',
					),
					'workspace_id' => array(
						'required'          => true,
						'type'              => 'string',
						'sanitize_callback' => 'sanitize_text_field',
					),
				),
			)
		);

		// Get workspace members (for assignees field)
		register_rest_route(
			self::NAMESPACE,
			'/members',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $this, 'get_members' ),
				'permission_callback' => array( $this, 'check_admin_permission' ),
				'args'                => array(
					'workspace_id' => array(
						'required'          => true,
						'type'              => 'string',
						'sanitize_callback' => 'sanitize_text_field',
					),
				),
			)
		);

		// Manually create a ClickUp task for a single vendor
		register_rest_route(
			self::NAMESPACE,
			'/create-task',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $this, 'create_task_for_vendor' ),
				'permission_callback' => array( $this, 'check_admin_permission' ),
				'args'                => array(
					'vendor_id' => array(
						'required'          => true,
						'type'              => 'integer',
						'sanitize_callback' => 'absint',
					),
					'force'     => array(
						'required' => false,
						'type'     => 'boolean',
						'default'  => false,
					),
				),
			)
		);

		// ClickUp → WordPress webhook receiver (F-16)
		// ClickUp cannot send a wp-nonce, so authorization is enforced in
		// verify_webhook_request() via mandatory HMAC-SHA256 signature checking
		// against the configured webhook_secret. No secret = endpoint rejected.
		register_rest_route(
			self::NAMESPACE,
			'/webhook',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $this, 'handle_clickup_webhook' ),
				'permission_callback' => array( $this, 'verify_webhook_request' ),
			)
		);

		// Event groups — filterable by pro/add-ons
		register_rest_route(
			self::NAMESPACE,
			'/event-groups',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => array( $this, 'get_event_groups' ),
				'permission_callback' => array( $this, 'check_admin_permission' ),
			)
		);

		// Test ClickUp connection
		register_rest_route(
			self::NAMESPACE,
			'/test-connection',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => array( $this, 'test_connection' ),
				'permission_callback' => array( $this, 'check_admin_permission' ),
				'args'                => array(
					'api_token' => array(
						'required'          => false,
						'type'              => 'string',
						'sanitize_callback' => 'sanitize_text_field',
						'default'           => '',
					),
					'list_id'   => array(
						'required'          => true,
						'type'              => 'string',
						'sanitize_callback' => 'sanitize_text_field',
					),
				),
			)
		);
	}

	/**
	 * Get ClickUp workspaces
	 *
	 * @since 1.0.0
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response
	 */
	public function get_workspaces( WP_REST_Request $request ): WP_REST_Response {
		$api_token = $request->get_param( 'api_token' );

		// Temporarily set token if provided
		$temp_data = $this->set_temporary_token( $api_token );

		// Get ClickUp client and fetch workspaces
		$client = vendor_tasks_dokan_clickup()->get_clickup_client();
		if ( ! $client ) {
			$this->restore_token( $temp_data['token'], $temp_data['settings'] );
			return new WP_REST_Response(
				array(
					'success' => false,
					'message' => __( 'ClickUp API token not configured.', 'alamin-vendor-tasks-dokan-clickup' ),
				),
				400
			);
		}
		$workspaces = $client->get_workspaces();

		// Restore original token
		$this->restore_token( $temp_data['token'], $temp_data['settings'] );

		if ( is_wp_error( $workspaces ) ) {
			vendor_tasks_dokan_clickup()->log(
				sprintf( 'Failed to fetch workspaces: %s', $workspaces->get_error_message() ),
				'error'
			);

			return new WP_REST_Response(
				array(
					'success' => false,
					'message' => $workspaces->get_error_message(),
				),
				500
			);
		}

		// Format workspaces for dropdown
		$formatted_workspaces = array();
		foreach ( $workspaces['teams'] ?? array() as $workspace ) {
			$formatted_workspaces[] = array(
				'id'   => $workspace['id'],
				'name' => $workspace['name'],
			);
		}

		return new WP_REST_Response(
			array(
				'success'    => true,
				'workspaces' => $formatted_workspaces,
			),
			200
		);
	}

	/**
	 * Get ClickUp lists for a workspace
	 *
	 * @since 1.0.0
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response
	 */
	public function get_lists( WP_REST_Request $request ): WP_REST_Response {
		$workspace_id = $request->get_param( 'workspace_id' );
		$api_token    = $request->get_param( 'api_token' );

		if ( empty( $workspace_id ) ) {
			vendor_tasks_dokan_clickup()->log( 'Missing workspace_id parameter', 'error' );

			return new WP_REST_Response(
				array(
					'success' => false,
					'message' => __( 'Workspace ID is required.', 'alamin-vendor-tasks-dokan-clickup' ),
				),
				400
			);
		}

		// Temporarily set token if provided
		$temp_data = $this->set_temporary_token( $api_token );

		// Get ClickUp client and fetch lists
		$client = vendor_tasks_dokan_clickup()->get_clickup_client();
		if ( ! $client ) {
			$this->restore_token( $temp_data['token'], $temp_data['settings'] );
			return new WP_REST_Response(
				array(
					'success' => false,
					'message' => __( 'ClickUp API token not configured.', 'alamin-vendor-tasks-dokan-clickup' ),
				),
				400
			);
		}
		$lists = $client->get_lists_for_workspace( $workspace_id );

		// Restore original token
		$this->restore_token( $temp_data['token'], $temp_data['settings'] );

		if ( is_wp_error( $lists ) ) {
			vendor_tasks_dokan_clickup()->log(
				sprintf( 'Failed to fetch lists: %s', $lists->get_error_message() ),
				'error'
			);

			return new WP_REST_Response(
				array(
					'success' => false,
					'message' => $lists->get_error_message(),
				),
				500
			);
		}

		return new WP_REST_Response(
			array(
				'success' => true,
				'lists'   => $lists,
			),
			200
		);
	}

	/**
	 * Test ClickUp API connection
	 *
	 * @since 1.0.0
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response
	 */
	public function test_connection( WP_REST_Request $request ): WP_REST_Response {
		$api_token = $request->get_param( 'api_token' );
		$list_id   = $request->get_param( 'list_id' );

		// Get current settings
		$settings      = get_option( 'vendor_tasks_dokan_clickup_settings', array() );
		$original_list = $settings['list_id'] ?? '';

		// Temporarily set token if provided
		$temp_data = $this->set_temporary_token( $api_token );

		// Always temporarily update list_id for testing
		$settings['list_id'] = $list_id;
		update_option( 'vendor_tasks_dokan_clickup_settings', $settings );

		// Get ClickUp client and test connection
		$client = vendor_tasks_dokan_clickup()->get_clickup_client();
		if ( ! $client ) {
			$this->restore_token( $temp_data['token'], $temp_data['settings'] );
			return new WP_REST_Response(
				array(
					'success' => false,
					'message' => __( 'ClickUp API token not configured.', 'alamin-vendor-tasks-dokan-clickup' ),
				),
				400
			);
		}
		$result = $client->test_connection();

		// If connection successful, get list info
		$list_name = '';
		if ( ! is_wp_error( $result ) ) {
			$list_info = $client->get_list();
			if ( ! is_wp_error( $list_info ) ) {
				$list_name = $list_info['name'] ?? 'Unknown';
			} else {
				// If we can't get list info, that's also an error
				$result = $list_info;
			}
		}

		// Restore original credentials
		$this->restore_token( $temp_data['token'], $temp_data['settings'] );
		$settings['list_id'] = $original_list;
		update_option( 'vendor_tasks_dokan_clickup_settings', $settings );

		if ( is_wp_error( $result ) ) {
			vendor_tasks_dokan_clickup()->log(
				sprintf( 'Connection test failed: %s', $result->get_error_message() ),
				'error'
			);

			return new WP_REST_Response(
				array(
					'success' => false,
					'message' => $result->get_error_message(),
				),
				500
			);
		}

		return new WP_REST_Response(
			array(
				'success'   => true,
				'message'   => __( 'Connection successful!', 'alamin-vendor-tasks-dokan-clickup' ),
				'list_name' => $list_name,
			),
			200
		);
	}

	/**
	 * Get workspace members for the assignees dropdown
	 *
	 * @since 1.1.0
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response
	 */
	public function get_members( WP_REST_Request $request ): WP_REST_Response {
		$workspace_id = $request->get_param( 'workspace_id' );
		$client       = vendor_tasks_dokan_clickup()->get_clickup_client();
		if ( ! $client ) {
			return new WP_REST_Response(
				array(
					'success' => false,
					'message' => __( 'ClickUp API token not configured.', 'alamin-vendor-tasks-dokan-clickup' ),
				),
				400
			);
		}
		$members = $client->get_workspace_members( $workspace_id );

		if ( is_wp_error( $members ) ) {
			return new WP_REST_Response(
				array(
					'success' => false,
					'message' => $members->get_error_message(),
				),
				500
			);
		}

		return new WP_REST_Response(
			array(
				'success' => true,
				'members' => $members,
			),
			200
		);
	}

	/**
	 * Manually create a ClickUp task for a specific vendor
	 *
	 * @since 1.1.0
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response
	 */
	public function create_task_for_vendor( WP_REST_Request $request ): WP_REST_Response {
		$vendor_id = (int) $request->get_param( 'vendor_id' );
		$force     = (bool) $request->get_param( 'force' );

		$user = get_userdata( $vendor_id );
		if ( ! $user ) {
			return new WP_REST_Response(
				array(
					'success' => false,
					'message' => __( 'Vendor not found.', 'alamin-vendor-tasks-dokan-clickup' ),
				),
				404
			);
		}

		if ( $force ) {
			( new VendorTaskState() )->clear_task( $vendor_id );
		}

		$registration = new \VendorTasksDokanClickUp\VendorIntegration\Registration();
		$result       = $registration->create_clickup_task_for_vendor( $vendor_id );

		if ( is_wp_error( $result ) ) {
			return new WP_REST_Response(
				array(
					'success' => false,
					'message' => $result->get_error_message(),
				),
				500
			);
		}

		$state    = new VendorTaskState();
		$task_id  = $state->get_task_id( $vendor_id );
		$task_url = $state->get_task_url( $vendor_id );

		return new WP_REST_Response(
			array(
				'success'  => true,
				'message'  => __( 'Task created successfully.', 'alamin-vendor-tasks-dokan-clickup' ),
				'task_id'  => $task_id,
				'task_url' => $task_url,
			),
			200
		);
	}

	/**
	 * Check admin permission
	 *
	 * @since 1.0.0
	 *
	 * @return bool
	 */
	public function check_admin_permission(): bool {
		return current_user_can( 'manage_options' );
	}

	/**
	 * Authorize incoming ClickUp webhook requests.
	 *
	 * The endpoint must be publicly reachable (ClickUp sends unsigned HTTP POST
	 * requests), so user authentication is not possible. Instead we gate access
	 * on two conditions:
	 *   1. The webhook feature is enabled in plugin settings.
	 *   2. A webhook_secret must be configured AND the X-Signature header must match
	 *      HMAC-SHA256(secret, raw_body). Requests with a missing secret or invalid
	 *      signature are rejected with 401 before any payload processing occurs.
	 *
	 * @since 1.1.0
	 *
	 * @param WP_REST_Request $request Incoming REST request.
	 * @return true|\WP_Error True when authorized; WP_Error with HTTP status on failure.
	 */
	public function verify_webhook_request( WP_REST_Request $request ) {
		$settings = get_option( 'vendor_tasks_dokan_clickup_settings', array() );

		if ( empty( $settings['enable_webhook'] ) ) {
			return new \WP_Error(
				'webhook_disabled',
				__( 'Webhook is not enabled.', 'alamin-vendor-tasks-dokan-clickup' ),
				array( 'status' => 403 )
			);
		}

		$secret = $settings['webhook_secret'] ?? '';
		if ( empty( $secret ) ) {
			vendor_tasks_dokan_clickup()->log( 'Webhook: no secret configured — request rejected. Configure a webhook secret to enable this endpoint.', 'error' );
			return new \WP_Error(
				'webhook_secret_missing',
				__( 'Webhook secret is not configured. The endpoint is disabled until a secret is set.', 'alamin-vendor-tasks-dokan-clickup' ),
				array( 'status' => 401 )
			);
		}

		$signature = $request->get_header( 'x_signature' );
		$expected  = hash_hmac( 'sha256', $request->get_body(), $secret );

		if ( empty( $signature ) || ! hash_equals( $expected, $signature ) ) {
			vendor_tasks_dokan_clickup()->log( 'Webhook: invalid signature — request rejected.', 'error' );
			return new \WP_Error(
				'invalid_signature',
				__( 'Webhook signature verification failed.', 'alamin-vendor-tasks-dokan-clickup' ),
				array( 'status' => 401 )
			);
		}

		return true;
	}

	/**
	 * Temporarily set API token for request
	 *
	 * @since 1.0.0
	 *
	 * @param string $api_token New API token (optional).
	 * @return array{token: string, settings: array<string, mixed>} Original token and settings.
	 */
	private function set_temporary_token( string $api_token = '' ): array {
		$settings       = get_option( 'vendor_tasks_dokan_clickup_settings', array() );
		$original_token = $settings['api_token'] ?? '';

		// Only update if new token provided
		if ( ! empty( $api_token ) ) {
			$settings['api_token'] = $api_token;
			update_option( 'vendor_tasks_dokan_clickup_settings', $settings );

			vendor_tasks_dokan_clickup()->log(
				'Temporarily using new API token for request',
				'debug'
			);
		}

		return array(
			'token'    => $original_token,
			'settings' => $settings,
		);
	}

	/**
	 * Restore original API token
	 *
	 * @since 1.0.0
	 *
	 * @param string               $original_token Original API token.
	 * @param array<string, mixed> $settings Settings array.
	 * @return void
	 */
	private function restore_token( string $original_token, array $settings ): void {
		$settings['api_token'] = $original_token;
		update_option( 'vendor_tasks_dokan_clickup_settings', $settings );
	}

	/**
	 * Return event groups, filtered so pro/add-ons can inject their own groups.
	 *
	 * Filter: vendor_tasks_dokan_clickup_event_groups
	 * Each group: { label: string, events: array<{ key, label, description, icon, defaultOpen, pro }> }
	 *
	 * @since 1.0.0
	 *
	 * @return WP_REST_Response
	 */
	public function get_event_groups(): WP_REST_Response {
		$groups = array(
			array(
				'label'  => __( 'Vendor Status', 'alamin-vendor-tasks-dokan-clickup' ),
				'events' => array(
					array(
						'key'         => 'vendor_registered',
						'label'       => __( 'New Vendor Registration', 'alamin-vendor-tasks-dokan-clickup' ),
						'description' => __( 'Task created when a new vendor applies to join the marketplace.', 'alamin-vendor-tasks-dokan-clickup' ),
						'icon'        => 'usercheck',
						'defaultOpen' => true,
						'pro'         => false,
					),
					array(
						'key'         => 'vendor_approved',
						'label'       => __( 'Vendor Approved', 'alamin-vendor-tasks-dokan-clickup' ),
						'description' => __( 'Task created when an admin approves a pending vendor application.', 'alamin-vendor-tasks-dokan-clickup' ),
						'icon'        => 'check2',
						'defaultOpen' => false,
						'pro'         => false,
					),
					array(
						'key'         => 'vendor_disabled',
						'label'       => __( 'Vendor Disabled', 'alamin-vendor-tasks-dokan-clickup' ),
						'description' => __( 'Task created when an admin disables a vendor account.', 'alamin-vendor-tasks-dokan-clickup' ),
						'icon'        => 'shield',
						'defaultOpen' => false,
						'pro'         => false,
					),
				),
			),
			array(
				'label'  => __( 'Store & Profile', 'alamin-vendor-tasks-dokan-clickup' ),
				'events' => array(
					array(
						'key'         => 'store_updated',
						'label'       => __( 'Store Profile Updated', 'alamin-vendor-tasks-dokan-clickup' ),
						'description' => __( 'Task updated when the vendor saves their store profile.', 'alamin-vendor-tasks-dokan-clickup' ),
						'icon'        => 'store',
						'defaultOpen' => false,
						'pro'         => false,
					),
					array(
						'key'         => 'payment_method_configured',
						'label'       => __( 'Payment Method Configured', 'alamin-vendor-tasks-dokan-clickup' ),
						'description' => __( 'Task updated when the vendor sets up their payment method for the first time.', 'alamin-vendor-tasks-dokan-clickup' ),
						'icon'        => 'wallet',
						'defaultOpen' => false,
						'pro'         => true,
					),
					array(
						'key'         => 'trust_status_changed',
						'label'       => __( 'Trust Status Changed', 'alamin-vendor-tasks-dokan-clickup' ),
						'description' => __( "Task updated when the vendor's trust status changes.", 'alamin-vendor-tasks-dokan-clickup' ),
						'icon'        => 'star',
						'defaultOpen' => false,
						'pro'         => true,
					),
				),
			),
			array(
				'label'  => __( 'Products', 'alamin-vendor-tasks-dokan-clickup' ),
				'events' => array(
					array(
						'key'         => 'product_submitted_for_review',
						'label'       => __( 'Product Submitted for Review', 'alamin-vendor-tasks-dokan-clickup' ),
						'description' => __( 'Task updated when the vendor submits a product for admin review.', 'alamin-vendor-tasks-dokan-clickup' ),
						'icon'        => 'clipboard',
						'defaultOpen' => false,
						'pro'         => false,
					),
					array(
						'key'         => 'first_product_published',
						'label'       => __( 'First Product Published', 'alamin-vendor-tasks-dokan-clickup' ),
						'description' => __( 'Task updated when the vendor publishes their first product.', 'alamin-vendor-tasks-dokan-clickup' ),
						'icon'        => 'rocket',
						'defaultOpen' => false,
						'pro'         => false,
					),
				),
			),
			array(
				'label'  => __( 'Orders', 'alamin-vendor-tasks-dokan-clickup' ),
				'events' => array(
					array(
						'key'         => 'new_order',
						'label'       => __( 'New Order', 'alamin-vendor-tasks-dokan-clickup' ),
						'description' => __( "Task updated when a new order is placed through the vendor's store.", 'alamin-vendor-tasks-dokan-clickup' ),
						'icon'        => 'cart',
						'defaultOpen' => false,
						'pro'         => false,
					),
					array(
						'key'         => 'first_sale',
						'label'       => __( 'First Sale', 'alamin-vendor-tasks-dokan-clickup' ),
						'description' => __( 'Task updated when the vendor makes their first sale.', 'alamin-vendor-tasks-dokan-clickup' ),
						'icon'        => 'trending',
						'defaultOpen' => false,
						'pro'         => false,
					),
				),
			),
			array(
				'label'  => __( 'Withdrawals', 'alamin-vendor-tasks-dokan-clickup' ),
				'events' => array(
					array(
						'key'         => 'withdrawal_requested',
						'label'       => __( 'Withdrawal Requested', 'alamin-vendor-tasks-dokan-clickup' ),
						'description' => __( 'Task updated when the vendor submits a withdrawal request.', 'alamin-vendor-tasks-dokan-clickup' ),
						'icon'        => 'wallet',
						'defaultOpen' => false,
						'pro'         => false,
					),
					array(
						'key'         => 'reverse_withdrawal_alert',
						'label'       => __( 'Reverse Withdrawal Alert', 'alamin-vendor-tasks-dokan-clickup' ),
						'description' => __( "Task updated when the vendor's reverse-withdrawal balance exceeds the threshold.", 'alamin-vendor-tasks-dokan-clickup' ),
						'icon'        => 'alert',
						'defaultOpen' => false,
						'pro'         => true,
					),
				),
			),
			array(
				'label'  => __( 'Advanced', 'alamin-vendor-tasks-dokan-clickup' ),
				'events' => array(
					array(
						'key'         => 'commission_changed',
						'label'       => __( 'Commission Changed', 'alamin-vendor-tasks-dokan-clickup' ),
						'description' => __( "Task updated when the vendor's commission rate is updated.", 'alamin-vendor-tasks-dokan-clickup' ),
						'icon'        => 'sliders',
						'defaultOpen' => false,
						'pro'         => true,
					),
				),
			),
		);

		/**
		 * Filter the event groups returned to the Task tab.
		 * Pro plugin/add-ons can append or modify groups here.
		 *
		 * @since 1.0.0
		 * @param array<int,array<string,mixed>> $groups
		 */
		$groups = apply_filters( 'vendor_tasks_dokan_clickup_event_groups', $groups );

		return new WP_REST_Response( array( 'event_groups' => $groups ), 200 );
	}

	/**
	 * Handle incoming ClickUp webhook (F-16)
	 *
	 * @since 1.1.0
	 *
	 * @param WP_REST_Request $request REST request object.
	 * @return WP_REST_Response|WP_Error
	 */
	public function handle_clickup_webhook( WP_REST_Request $request ) {
		return apply_filters(
			'vendor_tasks_dokan_clickup_handle_webhook',
			new WP_REST_Response(
				array(
					'success' => false,
					'message' => 'Webhook handler not available.',
				),
				503
			),
			$request
		);
	}
}
