<?php
/**
 * Donors REST API
 *
 * Provides REST API endpoints for donor profile operations.
 *
 * @package AmbassadorHub\Donors
 */

namespace AmbassadorHub\Donors;

use WP_REST_Controller;
use WP_REST_Server;
use WP_REST_Request;
use WP_REST_Response;
use WP_Error;

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

// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQL.NotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare

/**
 * Donors API class.
 */
class DonorsApi extends WP_REST_Controller {

	/**
	 * API namespace.
	 *
	 * @var string
	 */
	protected $namespace = \AmbassadorHub\Api\ApiModule::NAMESPACE;

	/**
	 * Resource base.
	 *
	 * @var string
	 */
	protected $rest_base = 'donors';

	/**
	 * Initialize the API.
	 *
	 * @return void
	 */
	public static function init(): void {
		$instance = new self();
		add_action( 'ambh_register_rest_routes', array( $instance, 'register_routes' ) );
	}

	/**
	 * Constructor.
	 */
	private function __construct() {
		// Private constructor for static init pattern.
	}

	/**
	 * Register REST API routes.
	 *
	 * @return void
	 */
	public function register_routes(): void {
		// GET /donors - List donors.
		// POST /donors - Create donor.
		register_rest_route(
			$this->namespace,
			'/' . $this->rest_base,
			array(
				array(
					'methods'             => WP_REST_Server::READABLE,
					'callback'            => array( $this, 'get_donors' ),
					'permission_callback' => array( $this, 'admin_permissions_check' ),
					'args'                => array(
						'search' => array(
							'description' => __( 'Search donors by name or email.', 'ambassadorhub' ),
							'type'        => 'string',
							'required'    => false,
						),
						'limit'  => array(
							'description' => __( 'Maximum number of results.', 'ambassadorhub' ),
							'type'        => 'integer',
							'default'     => 50,
							'minimum'     => 1,
							'maximum'     => 100,
						),
						'offset' => array(
							'description' => __( 'Number of results to skip.', 'ambassadorhub' ),
							'type'        => 'integer',
							'default'     => 0,
							'minimum'     => 0,
						),
					),
				),
				array(
					'methods'             => WP_REST_Server::CREATABLE,
					'callback'            => array( $this, 'create_donor' ),
					'permission_callback' => array( $this, 'admin_permissions_check' ),
					'args'                => $this->get_donor_params(),
				),
			)
		);

		// GET /donors/{id} - Get single donor.
		// PUT /donors/{id} - Update donor.
		// DELETE /donors/{id} - Delete donor.
		register_rest_route(
			$this->namespace,
			'/' . $this->rest_base . '/(?P<id>[\d]+)',
			array(
				array(
					'methods'             => WP_REST_Server::READABLE,
					'callback'            => array( $this, 'get_donor' ),
					'permission_callback' => array( $this, 'admin_permissions_check' ),
					'args'                => array(
						'id' => array(
							'description' => __( 'Donor ID.', 'ambassadorhub' ),
							'type'        => 'integer',
							'required'    => true,
						),
					),
				),
				array(
					'methods'             => WP_REST_Server::EDITABLE,
					'callback'            => array( $this, 'update_donor' ),
					'permission_callback' => array( $this, 'admin_permissions_check' ),
					'args'                => array_merge(
						array(
							'id' => array(
								'type'     => 'integer',
								'required' => true,
							),
						),
						$this->get_donor_params( false )
					),
				),
				array(
					'methods'             => WP_REST_Server::DELETABLE,
					'callback'            => array( $this, 'delete_donor' ),
					'permission_callback' => array( $this, 'admin_permissions_check' ),
					'args'                => array(
						'id' => array(
							'description' => __( 'Donor ID.', 'ambassadorhub' ),
							'type'        => 'integer',
							'required'    => true,
						),
					),
				),
			)
		);
	}

	/**
	 * Get donors list.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response
	 */
	public function get_donors( WP_REST_Request $request ): WP_REST_Response {
		$search = (string) $request->get_param( 'search' );
		$limit  = (int) $request->get_param( 'limit' );
		$offset = (int) $request->get_param( 'offset' );

		$donors = DonorsModule::get_all(
			array(
				'search' => $search,
				'limit'  => $limit,
				'offset' => $offset,
			)
		);

		$total = DonorsModule::count( $search );
		$data  = array_map( array( $this, 'prepare_donor_for_response' ), $donors );

		$response = new WP_REST_Response( $data, 200 );
		$response->header( 'X-Total-Count', $total );
		$response->header( 'X-Total-Pages', (int) ceil( $total / $limit ) );

		return $response;
	}

	/**
	 * Get a single donor.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response|WP_Error
	 */
	public function get_donor( WP_REST_Request $request ) {
		$donor = DonorsModule::get( (int) $request->get_param( 'id' ) );

		if ( ! $donor ) {
			return new WP_Error( 'donor_not_found', __( 'Donor not found.', 'ambassadorhub' ), array( 'status' => 404 ) );
		}

		return new WP_REST_Response( $this->prepare_donor_for_response( $donor ), 200 );
	}

	/**
	 * Create a donor.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response|WP_Error
	 */
	public function create_donor( WP_REST_Request $request ) {
		$data = array(
			'first_name'  => sanitize_text_field( (string) $request->get_param( 'first_name' ) ),
			'last_name'   => sanitize_text_field( (string) $request->get_param( 'last_name' ) ),
			'name'        => sanitize_text_field( (string) $request->get_param( 'name' ) ),
			'email'       => sanitize_email( (string) $request->get_param( 'email' ) ),
			'street'      => $request->get_param( 'street' ) !== null ? sanitize_text_field( (string) $request->get_param( 'street' ) ) : null,
			'city'        => $request->get_param( 'city' ) !== null ? sanitize_text_field( (string) $request->get_param( 'city' ) ) : null,
			'postal_code' => $request->get_param( 'postal_code' ) !== null ? sanitize_text_field( (string) $request->get_param( 'postal_code' ) ) : null,
			'state'       => $request->get_param( 'state' ) !== null ? sanitize_text_field( (string) $request->get_param( 'state' ) ) : null,
			'country'     => $request->get_param( 'country' ) !== null ? sanitize_text_field( (string) $request->get_param( 'country' ) ) : null,
		);

		$donor_id = DonorsModule::create( $data );

		if ( ! $donor_id ) {
			return new WP_Error( 'donor_create_failed', __( 'Failed to create donor.', 'ambassadorhub' ), array( 'status' => 500 ) );
		}

		return new WP_REST_Response( $this->prepare_donor_for_response( DonorsModule::get( $donor_id ) ), 201 );
	}

	/**
	 * Update a donor.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response|WP_Error
	 */
	public function update_donor( WP_REST_Request $request ) {
		$id    = (int) $request->get_param( 'id' );
		$donor = DonorsModule::get( $id );

		if ( ! $donor ) {
			return new WP_Error( 'donor_not_found', __( 'Donor not found.', 'ambassadorhub' ), array( 'status' => 404 ) );
		}

		$data = array_filter(
			array(
				'first_name'  => $request->get_param( 'first_name' ) !== null ? sanitize_text_field( (string) $request->get_param( 'first_name' ) ) : null,
				'last_name'   => $request->get_param( 'last_name' ) !== null ? sanitize_text_field( (string) $request->get_param( 'last_name' ) ) : null,
				'name'        => $request->get_param( 'name' ) !== null ? sanitize_text_field( (string) $request->get_param( 'name' ) ) : null,
				'email'       => $request->get_param( 'email' ) !== null ? sanitize_email( (string) $request->get_param( 'email' ) ) : null,
				'street'      => $request->get_param( 'street' ) !== null ? sanitize_text_field( (string) $request->get_param( 'street' ) ) : null,
				'city'        => $request->get_param( 'city' ) !== null ? sanitize_text_field( (string) $request->get_param( 'city' ) ) : null,
				'postal_code' => $request->get_param( 'postal_code' ) !== null ? sanitize_text_field( (string) $request->get_param( 'postal_code' ) ) : null,
				'state'       => $request->get_param( 'state' ) !== null ? sanitize_text_field( (string) $request->get_param( 'state' ) ) : null,
				'country'     => $request->get_param( 'country' ) !== null ? sanitize_text_field( (string) $request->get_param( 'country' ) ) : null,
			),
			fn( $v ) => null !== $v
		);

		DonorsModule::update( $id, $data );

		return new WP_REST_Response( $this->prepare_donor_for_response( DonorsModule::get( $id ) ), 200 );
	}

	/**
	 * Delete a donor.
	 *
	 * @param WP_REST_Request $request Request object.
	 * @return WP_REST_Response|WP_Error
	 */
	public function delete_donor( WP_REST_Request $request ) {
		$id = (int) $request->get_param( 'id' );

		if ( ! DonorsModule::get( $id ) ) {
			return new WP_Error( 'donor_not_found', __( 'Donor not found.', 'ambassadorhub' ), array( 'status' => 404 ) );
		}

		$result = DonorsModule::anonymize( $id );

		if ( ! $result ) {
			return new WP_Error( 'donor_anonymize_failed', __( 'Failed to anonymise donor.', 'ambassadorhub' ), array( 'status' => 500 ) );
		}

		return new WP_REST_Response( $this->prepare_donor_for_response( DonorsModule::get( $id ) ), 200 );
	}

	/**
	 * Permission check — admin only.
	 *
	 * @return bool|WP_Error
	 */
	public function admin_permissions_check() {
		if ( ! current_user_can( 'manage_options' ) ) {
			return new WP_Error( 'rest_forbidden', __( 'Insufficient permissions.', 'ambassadorhub' ), array( 'status' => 403 ) );
		}
		return true;
	}

	/**
	 * Prepare a donor DB row for a REST response.
	 *
	 * @param object $donor Raw donor object from DB.
	 * @return array
	 */
	private function prepare_donor_for_response( object $donor ): array {
		return array(
			'id'          => (int) $donor->id,
			'first_name'  => $donor->first_name,
			'last_name'   => $donor->last_name,
			'name'        => $donor->name,
			'email'       => $donor->email,
			'street'      => $donor->street ?? null,
			'city'        => $donor->city ?? null,
			'postal_code' => $donor->postal_code ?? null,
			'state'       => $donor->state ?? null,
			'country'     => $donor->country ?? null,
			'created_at'  => $donor->created_at,
			'updated_at'  => $donor->updated_at,
		);
	}

	/**
	 * Get donor creation/update params schema.
	 *
	 * @param bool $required Whether fields are required.
	 * @return array
	 */
	private function get_donor_params( bool $required = true ): array {
		return array(
			'first_name'  => array(
				'description' => __( 'Donor first name.', 'ambassadorhub' ),
				'type'        => 'string',
				'required'    => $required,
			),
			'last_name'   => array(
				'description' => __( 'Donor last name.', 'ambassadorhub' ),
				'type'        => 'string',
				'required'    => $required,
			),
			'name'        => array(
				'description' => __( 'Donor full name (auto-composed when omitted).', 'ambassadorhub' ),
				'type'        => 'string',
				'required'    => false,
			),
			'email'       => array(
				'description' => __( 'Donor email address.', 'ambassadorhub' ),
				'type'        => 'string',
				'format'      => 'email',
				'required'    => $required,
			),
			'street'      => array(
				'description' => __( 'Street address.', 'ambassadorhub' ),
				'type'        => 'string',
				'required'    => false,
			),
			'city'        => array(
				'description' => __( 'City.', 'ambassadorhub' ),
				'type'        => 'string',
				'required'    => false,
			),
			'postal_code' => array(
				'description' => __( 'Postal / ZIP code.', 'ambassadorhub' ),
				'type'        => 'string',
				'required'    => false,
			),
			'state'       => array(
				'description' => __( 'State or province.', 'ambassadorhub' ),
				'type'        => 'string',
				'required'    => false,
			),
			'country'     => array(
				'description' => __( 'ISO 3166-1 alpha-2 country code (e.g. NL, DE, GB).', 'ambassadorhub' ),
				'type'        => 'string',
				'required'    => false,
				'maxLength'   => 2,
			),
		);
	}
}
