<?php

namespace WeDevs\AppBridge\Core\REST;

use WeDevs\AppBridge\Core\Notifications\Messages\BroadcastNotification;
use WeDevs\AppBridge\Core\Notifications\NotificationDriverFactory;
use WeDevs\AppBridge\Core\Notifications\NotificationManager;
use WP_Error;
use WP_REST_Controller;
use WP_REST_Request;
use WP_REST_Response;
use WP_REST_Server;
use WP_User_Query;

/**
 * Backend for the admin "Send Notifications" panel.
 *
 *   GET  /roles                    → role options for the picker
 *   GET  /users?search=<query>     → async user search results
 *   POST /send                     → fire a one-off push via the selected provider
 *
 * Each integration (Pocket Store, Vendor App, …) registers its own instance
 * pinned to its own option key, so the dispatched broadcast resolves
 * OneSignal credentials from the right settings page.
 */
class PushNotificationsController extends WP_REST_Controller {

	protected $rest_base = 'push-notifications';

	private string $option_key;

	public function __construct(
		string $rest_namespace = 'app-bridge/v1',
		string $option_key = NotificationDriverFactory::DEFAULT_OPTION_KEY
	) {
		$this->namespace  = $rest_namespace;
		$this->option_key = $option_key;
	}

	public function register_routes(): void {
		register_rest_route(
			$this->namespace,
			'/' . $this->rest_base . '/roles',
			[
				[
					'methods'             => WP_REST_Server::READABLE,
					'callback'            => [ $this, 'list_roles' ],
					'permission_callback' => [ $this, 'admin_only' ],
				],
			]
		);

		register_rest_route(
			$this->namespace,
			'/' . $this->rest_base . '/users',
			[
				[
					'methods'             => WP_REST_Server::READABLE,
					'callback'            => [ $this, 'search_users' ],
					'permission_callback' => [ $this, 'admin_only' ],
					'args'                => [
						'search' => [
							'type'              => 'string',
							'required'          => false,
							'sanitize_callback' => 'sanitize_text_field',
						],
					],
				],
			]
		);

		register_rest_route(
			$this->namespace,
			'/' . $this->rest_base . '/send',
			[
				[
					'methods'             => WP_REST_Server::CREATABLE,
					'callback'            => [ $this, 'send' ],
					'permission_callback' => [ $this, 'admin_only' ],
					'args'                => [
						'recipient_type' => [
							'type'     => 'string',
							'required' => true,
							'enum'     => [ 'users', 'roles' ],
						],
						'user_ids'       => [
							'type'     => 'array',
							'required' => false,
							'default'  => [],
							'items'    => [ 'type' => 'integer' ],
						],
						'roles'          => [
							'type'     => 'array',
							'required' => false,
							'default'  => [],
							'items'    => [ 'type' => 'string' ],
						],
						'title'          => [
							'type'              => 'string',
							'required'          => true,
							'sanitize_callback' => 'sanitize_text_field',
						],
						'message'        => [
							'type'              => 'string',
							'required'          => true,
							'sanitize_callback' => 'sanitize_textarea_field',
						],
						'icon'           => [
							'type'              => 'string',
							'required'          => false,
							'sanitize_callback' => 'esc_url_raw',
						],
						'action_type'    => [
							'type'              => 'string',
							'required'          => false,
							'default'           => 'category',
							'sanitize_callback' => 'sanitize_key',
						],
						'action_type_id' => [
							'type'              => 'string',
							'required'          => false,
							'sanitize_callback' => 'sanitize_text_field',
						],
					],
				],
			]
		);
	}

	public function admin_only(): bool {
		return current_user_can( 'manage_options' );
	}

	/**
	 * Return WP roles formatted for SmartMultiSelect.
	 */
	public function list_roles(): WP_REST_Response {
		$roles = wp_roles()->roles;
		$out   = [];

		foreach ( $roles as $slug => $role ) {
			$out[] = [
				'value' => (string) $slug,
				'label' => translate_user_role( $role['name'] ),
			];
		}

		return rest_ensure_response( $out );
	}

	/**
	 * Search WP users by name / email / login. Caps results at 20.
	 */
	public function search_users( WP_REST_Request $request ): WP_REST_Response {
		$search = trim( (string) $request->get_param( 'search' ) );

		if ( '' === $search || strlen( $search ) < 2 ) {
			return rest_ensure_response( [] );
		}

		$query = new WP_User_Query(
			[
				'search'         => '*' . esc_attr( $search ) . '*',
				'search_columns' => [ 'user_login', 'user_email', 'user_nicename', 'display_name' ],
				'number'         => 20,
				'fields'         => [ 'ID', 'display_name', 'user_email' ],
			]
		);

		$out = [];
		foreach ( $query->get_results() as $user ) {
			$label = $user->display_name ? $user->display_name : $user->user_email;
			$out[] = [
				'value' => (string) $user->ID,
				'label' => sprintf( '%s (%s)', $label, $user->user_email ),
			];
		}

		return rest_ensure_response( $out );
	}

	/**
	 * Dispatch a broadcast through the selected provider.
	 */
	public function send( WP_REST_Request $request ) {
		$type           = $request->get_param( 'recipient_type' );
		$user_ids       = array_filter( array_map( 'absint', (array) $request->get_param( 'user_ids' ) ) );
		$roles          = array_filter( array_map( 'sanitize_key', (array) $request->get_param( 'roles' ) ) );
		$title          = (string) $request->get_param( 'title' );
		$message        = (string) $request->get_param( 'message' );
		$icon           = (string) $request->get_param( 'icon' );
		$action_type    = (string) $request->get_param( 'action_type' );
		$action_type_id = (string) $request->get_param( 'action_type_id' );

		if ( '' === trim( $title ) || '' === trim( $message ) ) {
			return new WP_Error( 'app_bridge_invalid_payload', __( 'Title and message are required.', 'app-bridge' ), [ 'status' => 400 ] );
		}

		$audience = [];
		if ( 'users' === $type ) {
			if ( empty( $user_ids ) ) {
				return new WP_Error( 'app_bridge_invalid_audience', __( 'Select at least one user.', 'app-bridge' ), [ 'status' => 400 ] );
			}
			$audience['external_user_ids'] = array_map( 'strval', $user_ids );
		} else {
			if ( empty( $roles ) ) {
				return new WP_Error( 'app_bridge_invalid_audience', __( 'Select at least one role.', 'app-bridge' ), [ 'status' => 400 ] );
			}
			$audience['roles'] = $roles;
		}

		$results = ( new NotificationManager() )->send(
			new BroadcastNotification(
				$title,
				$message,
				$audience,
				[
					'icon'           => $icon,
					'action_type'    => $action_type,
					'action_type_id' => $action_type_id,
				],
				[],
				$this->option_key
			),
			$this->option_key
		);

		return $this->respond( $results );
	}

	/**
	 * Shape the dispatcher's per-driver result map into a REST response.
	 *
	 * @param array<string, bool> $results
	 */
	private function respond( array $results ) {
		$any_success = in_array( true, $results, true );

		if ( ! $any_success ) {
			return new WP_Error(
				'app_bridge_dispatch_failed',
				__( 'Notification provider rejected the request. Check the provider credentials.', 'app-bridge' ),
				[
					'status'  => 502,
					'results' => $results,
				]
			);
		}

		return rest_ensure_response(
			[
				'message' => __( 'Notification dispatched.', 'app-bridge' ),
				'results' => $results,
			]
		);
	}
}
