<?php
/**
 * @license GPL-2.0-or-later
 * @link    https://wordpress.org/plugins/pressio-crm
 */
namespace PressioCRM\API;

defined( 'ABSPATH' ) || exit;

use PressioCRM\Framework\Controller;
use WP_REST_Request;
use WP_REST_Response;
use WP_REST_Server;

/**
 * Global search endpoint.
 *
 * GET /search?q=term&limit=5
 *
 * Returns contacts, deals, and tasks matching the query.
 * Minimum query length: 2 characters.
 * All three resource types are searched in a single request — no N+1.
 */
class RestSearch extends Controller {

	protected $rest_base = 'search';

	public function register_routes(): void {
		register_rest_route(
			$this->namespace,
			'/' . $this->rest_base,
			[
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => [ $this, 'index' ],
				'permission_callback' => [ $this, 'require_contacts_cap' ],
				'args'                => [
					'q'     => [
						'type'              => 'string',
						'required'          => true,
						'minLength'         => 2,
						'sanitize_callback' => 'sanitize_text_field',
						'validate_callback' => 'rest_validate_request_arg',
					],
					'limit' => [
						'type'              => 'integer',
						'default'           => 5,
						'required'          => false,
						'minimum'           => 1,
						'maximum'           => 8,
						'sanitize_callback' => 'absint',
						'validate_callback' => 'rest_validate_request_arg',
					],
				],
			]
		);
	}

	public function index( WP_REST_Request $request ): WP_REST_Response {
		global $wpdb;

		$q     = sanitize_text_field( $request->get_param( 'q' ) );
		$limit = min( 8, max( 1, absint( $request->get_param( 'limit' ) ?: 5 ) ) );

		if ( mb_strlen( $q ) < 2 ) {
			return $this->ok( [ 'contacts' => [], 'deals' => [], 'tasks' => [], 'total' => 0 ] );
		}

		$like = '%' . $wpdb->esc_like( $q ) . '%';

		$contacts_table = $wpdb->prefix . 'pcrm_contacts';
		$deals_table    = $wpdb->prefix . 'pcrm_deals';
		$tasks_table    = $wpdb->prefix . 'pcrm_tasks';

		// ── Contacts ─────────────────────────────────────────────────────────────
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$raw_contacts = $wpdb->get_results(
			$wpdb->prepare(
				'SELECT id, first_name, last_name, email, company
				 FROM %i
				 WHERE deleted_at IS NULL
				   AND ( first_name LIKE %s OR last_name LIKE %s OR email LIKE %s OR company LIKE %s )
				 ORDER BY first_name ASC, last_name ASC
				 LIMIT %d',
				$contacts_table, $like, $like, $like, $like, $limit
			)
		);

		// ── Deals ─────────────────────────────────────────────────────────────────
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$raw_deals = $wpdb->get_results(
			$wpdb->prepare(
				'SELECT d.id, d.title, d.value, d.status, d.currency,
				        TRIM( CONCAT( COALESCE(c.first_name,\'\'), \' \', COALESCE(c.last_name,\'\') ) ) AS contact_name
				 FROM %i d
				 LEFT JOIN %i c ON c.id = d.contact_id AND c.deleted_at IS NULL
				 WHERE d.deleted_at IS NULL
				   AND d.title LIKE %s
				 ORDER BY d.created_at DESC
				 LIMIT %d',
				$deals_table, $contacts_table, $like, $limit
			)
		);

		// ── Tasks ─────────────────────────────────────────────────────────────────
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$raw_tasks = $wpdb->get_results(
			$wpdb->prepare(
				'SELECT id, title, type, status, priority, due_date
				 FROM %i
				 WHERE deleted_at IS NULL
				   AND title LIKE %s
				 ORDER BY due_date ASC
				 LIMIT %d',
				$tasks_table, $like, $limit
			)
		);

		$contacts = array_map(
			static fn( $c ) => [
				'id'         => (int) $c->id,
				'first_name' => (string) $c->first_name,
				'last_name'  => (string) $c->last_name,
				'email'      => (string) $c->email,
				'company'    => (string) $c->company,
			],
			$raw_contacts ?: []
		);

		$deals = array_map(
			static fn( $d ) => [
				'id'           => (int) $d->id,
				'title'        => (string) $d->title,
				'value'        => (float) $d->value,
				'status'       => (string) $d->status,
				'currency'     => (string) $d->currency,
				'contact_name' => (string) $d->contact_name,
			],
			$raw_deals ?: []
		);

		$tasks = array_map(
			static fn( $t ) => [
				'id'       => (int) $t->id,
				'title'    => (string) $t->title,
				'type'     => (string) $t->type,
				'status'   => (string) $t->status,
				'priority' => (string) $t->priority,
				'due_date' => (string) $t->due_date,
			],
			$raw_tasks ?: []
		);

		$total = count( $contacts ) + count( $deals ) + count( $tasks );

		return $this->ok( compact( 'contacts', 'deals', 'tasks', 'total' ) );
	}
}
