<?php
/**
 * Donors REST Controller
 *
 * REST API endpoints for donor management.
 *
 * @package DonorCore\API
 */

namespace DonorCore\API;

defined( 'ABSPATH' ) || exit;

/**
 * Donors Controller Class
 */
class Donors_Controller extends REST_Controller_Base {

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

	/**
	 * Analytics repository.
	 *
	 * @var \DonorCore\Database\Donor_Analytics_Repository
	 */
	private $analytics_repo;

	/**
	 * Donation repository.
	 *
	 * @var \DonorCore\Database\Donation_Log_Repository
	 */
	private $donation_repo;

	/**
	 * Constructor.
	 */
	public function __construct() {
		$this->analytics_repo = new \DonorCore\Database\Donor_Analytics_Repository();
		$this->donation_repo  = new \DonorCore\Database\Donation_Log_Repository();
	}

	/**
	 * Register routes.
	 */
	public function register_routes() {
		// List donors.
		register_rest_route(
			$this->namespace,
			'/' . $this->rest_base,
			array(
				'methods'             => \WP_REST_Server::READABLE,
				'callback'            => array( $this, 'get_items' ),
				'permission_callback' => array( $this, 'check_write_permissions' ),
				'args'                => array(
					'page'     => array( 'default' => 1 ),
					'per_page' => array( 'default' => 10 ),
					'search'   => array( 'default' => '' ),
				),
			)
		);

		// Single donor by email.
		register_rest_route(
			$this->namespace,
			'/' . $this->rest_base . '/(?P<email>[^/]+)',
			array(
				'methods'             => \WP_REST_Server::READABLE,
				'callback'            => array( $this, 'get_item' ),
				'permission_callback' => array( $this, 'check_write_permissions' ),
			)
		);

		// Donor donations history by email.
		register_rest_route(
			$this->namespace,
			'/' . $this->rest_base . '/(?P<email>[^/]+)/donations',
			array(
				'methods'             => \WP_REST_Server::READABLE,
				'callback'            => array( $this, 'get_donor_donations' ),
				'permission_callback' => array( $this, 'check_write_permissions' ),
			)
		);
	}

	/**
	 * Get donors list.
	 *
	 * @param \WP_REST_Request $request Request object.
	 * @return \WP_REST_Response
	 */
	public function get_items( $request ) {
		global $wpdb;
		$table = $wpdb->prefix . 'donorcore_donor_analytics';

		$pagination = $this->get_pagination_params( $request );
		$search     = $request->get_param( 'search' );

		$where = '';
		
		if ( $search ) {
			$search_term = '%' . $wpdb->esc_like( $search ) . '%';
			
			// Get all orders to search through billing info
			// WooCommerce HPOS stores billing data in order objects
			$all_orders = wc_get_orders( array(
				'limit' => -1,
				'return' => 'ids',
			) );
			
			$matching_emails = array();
			
			// Search through orders for matching names
			foreach ( $all_orders as $order_id ) {
				$order = wc_get_order( $order_id );
				if ( ! $order ) {
					continue;
				}
				
				$first_name = $order->get_billing_first_name();
				$last_name = $order->get_billing_last_name();
				$full_name = trim( $first_name . ' ' . $last_name );
				$email = $order->get_billing_email();
				
				// Check if name matches search term
				if ( 
					stripos( $first_name, $search ) !== false ||
					stripos( $last_name, $search ) !== false ||
					stripos( $full_name, $search ) !== false
				) {
					$matching_emails[] = $email;
				}
			}
			
			$matching_emails = array_unique( $matching_emails );
			
			// Build WHERE clause
			if ( ! empty( $matching_emails ) ) {
				// Include both name matches AND email matches
				$email_placeholders = implode( ',', array_fill( 0, count( $matching_emails ), '%s' ) );
				// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare -- Placeholders dynamically generated for IN clause
				$where = $wpdb->prepare( "WHERE donor_email IN ($email_placeholders) OR donor_email LIKE %s", array_merge( $matching_emails, array( $search_term ) ) );
			} else {
				// Only email search
				$where = $wpdb->prepare( 'WHERE donor_email LIKE %s', $search_term );
			}
		}

		// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
		$donors = $wpdb->get_results(
			// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
			$wpdb->prepare( "SELECT * FROM %i {$where} ORDER BY total_lifetime_value DESC LIMIT %d OFFSET %d", $table, $pagination['per_page'], $pagination['offset'] ),
			ARRAY_A
		);

		// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
		$total = $wpdb->get_var(
			// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
			$wpdb->prepare( "SELECT COUNT(*) FROM %i {$where}", $table )
		);

		$formatted = array();
		foreach ( $donors as $donor ) {
			$formatted[] = $this->prepare_item( $donor );
		}

		$response = $this->success( $formatted );
		return $this->add_pagination_headers( $response, $total, $pagination['page'], $pagination['per_page'] );
	}

	/**
	 * Get single donor.
	 *
	 * @param \WP_REST_Request $request Request object.
	 * @return \WP_REST_Response|\WP_Error
	 */
	public function get_item( $request ) {
		$donor_email = urldecode( $request->get_param( 'email' ) );
		
		$donor = $this->analytics_repo->get_by_email( $donor_email );

		if ( ! $donor ) {
			// Create a minimal donor object to pass to prepare_item
			// prepare_item will fetch name and phone from the most recent order
			$donor = array(
				'donor_email'           => $donor_email,
				'donor_id'              => 0,
				'total_lifetime_value'  => 0,
				'donation_count'        => 0,
				'first_donation_date'   => null,
				'last_donation_date'    => null,
			);
		}

		return $this->success( $this->prepare_item( $donor, true ) );
	}

	/**
	 * Get donor donations.
	 *
	 * @param \WP_REST_Request $request Request object.
	 * @return \WP_REST_Response|\WP_Error
	 */
	public function get_donor_donations( $request ) {
		$donor_email = urldecode( $request->get_param( 'email' ) );
		
		$donations = $this->donation_repo->get_by_donor_email( $donor_email );

		$formatted = array();
		foreach ( $donations as $donation ) {
			$formatted[] = array(
				'id'         => $donation['id'],
				'amount'     => floatval( $donation['amount'] ),
				'currency'   => $donation['currency'],
				'type'       => $donation['type'],
				'gateway'    => $donation['gateway'],
				'order_id'   => intval( $donation['order_id'] ),
				'campaign_id' => intval( $donation['campaign_id'] ),
				'created_at' => $donation['created_at'],
			);
		}

		return $this->success( $formatted );
	}



	/**
	 * Prepare donor item for response.
	 *
	 * @param object $donor        Donor data.
	 * @param bool   $full_details Include full details.
	 * @return array
	 */
	private function prepare_item( $donor, $full_details = false ) {
	// Convert array to object if necessary
	if ( is_array( $donor ) ) {
		$donor = (object) $donor;
	}
	
	// Get donor name and contact info from most recent order billing info
	$donor_name = '';
	$phone = '';

	// Use WooCommerce's order query to support both HPOS and traditional storage
	$orders = wc_get_orders( array(
		'billing_email' => $donor->donor_email,
		'limit'         => 1,
		'orderby'       => 'date',
		'order'         => 'DESC',
		'return'        => 'ids',
	) );
	
	$order_id = !empty( $orders ) ? $orders[0] : null;
	
	if ( $order_id ) {
		$order = wc_get_order( $order_id );
		
		if ( $order ) {
			$first_name = $order->get_billing_first_name();
			$last_name = $order->get_billing_last_name();
			$donor_name = trim( $first_name . ' ' . $last_name );
			$phone = $order->get_billing_phone();
		}
	}
	
	// Fallback to user display name if no order found or name is empty
	if ( empty( $donor_name ) ) {
		$user = get_user_by( 'email', $donor->donor_email );
		if ( $user ) {
			$donor_name = $user->display_name;
		}
	}
	
	// Final fallback to email
	if ( empty( $donor_name ) ) {
		$donor_name = $donor->donor_email;
	}

	// Get the correct WordPress user ID by email
	$correct_donor_id = 0;
	$user = get_user_by( 'email', $donor->donor_email );
	if ( $user ) {
		$correct_donor_id = $user->ID;
	}

		$data = array(
			'id'                   => sanitize_email( $donor->donor_email ), // Use email as unique ID (primary key in database)
			'donor_id'             => absint( $correct_donor_id ), // Use correct WordPress user ID
			'donor_name'           => sanitize_text_field( $donor_name ), // Add donor name
			'email'                => sanitize_email( $donor->donor_email ),
			'phone'                => sanitize_text_field( $phone ), // Add phone number
			'total_lifetime_value' => floatval( $donor->total_lifetime_value ),
			'total_donation_count' => isset( $donor->donation_count ) ? absint( $donor->donation_count ) : 0, // Fixed: use donation_count from DB
			'first_donation_date'  => sanitize_text_field( $donor->first_donation_date ),
			'last_donation_date'   => sanitize_text_field( $donor->last_donation_date ),
		);

		if ( $full_details ) {
			$user = get_user_by( 'id', $donor->donor_id );
			if ( $user ) {
				$data['username']   = sanitize_text_field( $user->user_login );
				$data['registered'] = sanitize_text_field( $user->user_registered );
			}
		}

		return $data;
	}
}
