<?php
/**
 * Mock Spektrix API endpoints.
 *
 * Registers WordPress REST API routes that mirror the real Spektrix API v3
 * response structure, but serve data from local JSON files.
 *
 * The frontend JavaScript code is identical to what would run against
 * real Spektrix — only this backend data source differs.
 *
 * Routes:
 *   GET    /wp-json/spektrix-mock/v1/events
 *   GET    /wp-json/spektrix-mock/v1/events/{id}
 *   GET    /wp-json/spektrix-mock/v1/instances
 *   GET    /wp-json/spektrix-mock/v1/ticket-types/{event_id}
 *   GET    /wp-json/spektrix-mock/v1/basket
 *   POST   /wp-json/spektrix-mock/v1/basket/items
 *   PATCH  /wp-json/spektrix-mock/v1/basket/items/{id}
 *   DELETE /wp-json/spektrix-mock/v1/basket/items/{id}
 *
 * @package Northfield_Theatre
 * @since 1.0.0
 */

/**
 * Register all REST API routes.
 */
function northfield_register_api_routes() {
	$namespace = 'spektrix-mock/v1';

	// GET /events
	register_rest_route( $namespace, '/events', array(
		'methods'             => WP_REST_Server::READABLE,
		'callback'            => 'northfield_api_get_events',
		'permission_callback' => '__return_true',
		'args'                => array(
			'category' => array(
				'type'              => 'string',
				'sanitize_callback' => 'sanitize_text_field',
			),
			'venue' => array(
				'type'              => 'string',
				'sanitize_callback' => 'sanitize_text_field',
			),
			'featured' => array(
				'type'              => 'boolean',
				'sanitize_callback' => 'rest_sanitize_boolean',
			),
			'search' => array(
				'type'              => 'string',
				'sanitize_callback' => 'sanitize_text_field',
			),
			'limit' => array(
				'type'              => 'integer',
				'sanitize_callback' => 'absint',
				'default'           => 0,
			),
			'offset' => array(
				'type'              => 'integer',
				'sanitize_callback' => 'absint',
				'default'           => 0,
			),
			'orderby' => array(
				'type'              => 'string',
				'sanitize_callback' => 'sanitize_text_field',
				'default'           => 'date',
				'enum'              => array( 'name', 'date', 'price' ),
			),
			'order' => array(
				'type'              => 'string',
				'sanitize_callback' => 'sanitize_text_field',
				'default'           => 'ASC',
				'enum'              => array( 'ASC', 'DESC' ),
			),
		),
	) );

	// GET /events/{id}
	register_rest_route( $namespace, '/events/(?P<id>[a-z0-9_]+)', array(
		'methods'             => WP_REST_Server::READABLE,
		'callback'            => 'northfield_api_get_event',
		'permission_callback' => '__return_true',
		'args'                => array(
			'id' => array(
				'required'          => true,
				'type'              => 'string',
				'sanitize_callback' => 'sanitize_text_field',
			),
		),
	) );

	// GET /instances
	register_rest_route( $namespace, '/instances', array(
		'methods'             => WP_REST_Server::READABLE,
		'callback'            => 'northfield_api_get_instances',
		'permission_callback' => '__return_true',
		'args'                => array(
			'event_id' => array(
				'type'              => 'string',
				'sanitize_callback' => 'sanitize_text_field',
			),
			'from' => array(
				'type'              => 'string',
				'sanitize_callback' => 'sanitize_text_field',
			),
			'to' => array(
				'type'              => 'string',
				'sanitize_callback' => 'sanitize_text_field',
			),
		),
	) );

	// GET /ticket-types/{event_id}
	register_rest_route( $namespace, '/ticket-types/(?P<event_id>[a-z0-9_]+)', array(
		'methods'             => WP_REST_Server::READABLE,
		'callback'            => 'northfield_api_get_ticket_types',
		'permission_callback' => '__return_true',
		'args'                => array(
			'event_id' => array(
				'required'          => true,
				'type'              => 'string',
				'sanitize_callback' => 'sanitize_text_field',
			),
		),
	) );

	// GET /basket
	register_rest_route( $namespace, '/basket', array(
		'methods'             => WP_REST_Server::READABLE,
		'callback'            => 'northfield_api_get_basket',
		'permission_callback' => '__return_true',
	) );

	// POST /basket/items
	register_rest_route( $namespace, '/basket/items', array(
		'methods'             => WP_REST_Server::CREATABLE,
		'callback'            => 'northfield_api_add_basket_item',
		'permission_callback' => '__return_true',
		'args'                => array(
			'eventId' => array(
				'required'          => true,
				'type'              => 'string',
				'sanitize_callback' => 'sanitize_text_field',
			),
			'instanceId' => array(
				'required'          => true,
				'type'              => 'string',
				'sanitize_callback' => 'sanitize_text_field',
			),
			'ticketTypeId' => array(
				'required'          => true,
				'type'              => 'string',
				'sanitize_callback' => 'sanitize_text_field',
			),
			'quantity' => array(
				'required'          => true,
				'type'              => 'integer',
				'sanitize_callback' => 'absint',
			),
		),
	) );

	// PATCH /basket/items/{id}
	register_rest_route( $namespace, '/basket/items/(?P<id>[a-z0-9_]+)', array(
		'methods'             => 'PATCH',
		'callback'            => 'northfield_api_update_basket_item',
		'permission_callback' => '__return_true',
		'args'                => array(
			'id' => array(
				'required'          => true,
				'type'              => 'string',
				'sanitize_callback' => 'sanitize_text_field',
			),
			'quantity' => array(
				'required'          => true,
				'type'              => 'integer',
				'sanitize_callback' => 'absint',
			),
		),
	) );

	// DELETE /basket/items/{id}
	register_rest_route( $namespace, '/basket/items/(?P<id>[a-z0-9_]+)', array(
		'methods'             => WP_REST_Server::DELETABLE,
		'callback'            => 'northfield_api_delete_basket_item',
		'permission_callback' => '__return_true',
		'args'                => array(
			'id' => array(
				'required'          => true,
				'type'              => 'string',
				'sanitize_callback' => 'sanitize_text_field',
			),
		),
	) );
}
add_action( 'rest_api_init', 'northfield_register_api_routes' );

/* =========================================================================
   EVENT ENDPOINTS
   ========================================================================= */

/**
 * GET /events — List all events with optional filtering.
 *
 * @param WP_REST_Request $request The request object.
 * @return WP_REST_Response
 */
function northfield_api_get_events( $request ) {
	$args = array(
		'category'    => $request->get_param( 'category' ) ?? '',
		'venue'       => $request->get_param( 'venue' ) ?? '',
		'featured'    => $request->get_param( 'featured' ),
		'search'      => $request->get_param( 'search' ) ?? '',
		'limit'       => $request->get_param( 'limit' ) ?? 0,
		'offset'      => $request->get_param( 'offset' ) ?? 0,
		'orderby'     => $request->get_param( 'orderby' ) ?? 'date',
		'order'       => $request->get_param( 'order' ) ?? 'ASC',
	);

	$events = northfield_get_events( $args );

	// Enrich each event with computed fields.
	$enriched = array_map( 'northfield_enrich_event', $events );

	return rest_ensure_response( array(
		'data'  => $enriched,
		'total' => count( $enriched ),
	) );
}

/**
 * GET /events/{id} — Get a single event.
 *
 * @param WP_REST_Request $request The request object.
 * @return WP_REST_Response|WP_Error
 */
function northfield_api_get_event( $request ) {
	$event_id = $request->get_param( 'id' );
	$event    = northfield_get_event( $event_id );

	if ( ! $event ) {
		return new WP_Error(
			'event_not_found',
			__( 'Event not found.', 'northfield-theatre' ),
			array( 'status' => 404 )
		);
	}

	$enriched = northfield_enrich_event( $event );

	// Include full instances and ticket types for single event view.
	$enriched['instances']   = northfield_get_instances( $event_id );
	$enriched['ticketTypes'] = northfield_get_event_ticket_types( $event_id );

	return rest_ensure_response( $enriched );
}

/**
 * Enrich an event with computed display fields.
 *
 * @param array $event The raw event data.
 * @return array Enriched event data.
 */
function northfield_enrich_event( $event ) {
	$first_date = northfield_get_event_first_date( $event['id'] );
	$last_date  = northfield_get_event_last_date( $event['id'] );

	$event['firstDate']     = $first_date;
	$event['lastDate']      = $last_date;
	$event['priceDisplay']  = northfield_format_event_price_range( $event );
	$event['dateDisplay']   = northfield_format_event_date_range( $first_date, $last_date );
	$event['url']           = home_url( '/events/' . $event['slug'] . '/' );
	$event['instanceCount'] = count( northfield_get_instances( $event['id'] ) );

	return $event;
}

/**
 * Format a price range for display.
 *
 * @param array $event The event data.
 * @return string Formatted price string.
 */
function northfield_format_event_price_range( $event ) {
	if ( $event['minPrice'] <= 0 && $event['maxPrice'] <= 0 ) {
		return 'Free';
	}

	if ( $event['minPrice'] <= 0 ) {
		return 'Free – ' . northfield_format_price( $event['maxPrice'] );
	}

	if ( $event['minPrice'] === $event['maxPrice'] ) {
		return northfield_format_price( $event['minPrice'] );
	}

	return northfield_format_price( $event['minPrice'] ) . ' – ' . northfield_format_price( $event['maxPrice'] );
}

/**
 * Format a date range for display.
 *
 * @param string $first_date ISO datetime.
 * @param string $last_date  ISO datetime.
 * @return string Formatted date range.
 */
function northfield_format_event_date_range( $first_date, $last_date ) {
	if ( empty( $first_date ) ) {
		return '';
	}

	$first = new DateTime( $first_date );
	$last  = new DateTime( $last_date );

	if ( $first->format( 'Y-m-d' ) === $last->format( 'Y-m-d' ) ) {
		return $first->format( 'D j M Y' );
	}

	if ( $first->format( 'M Y' ) === $last->format( 'M Y' ) ) {
		return $first->format( 'j' ) . ' – ' . $last->format( 'j M Y' );
	}

	if ( $first->format( 'Y' ) === $last->format( 'Y' ) ) {
		return $first->format( 'j M' ) . ' – ' . $last->format( 'j M Y' );
	}

	return $first->format( 'j M Y' ) . ' – ' . $last->format( 'j M Y' );
}

/* =========================================================================
   INSTANCE ENDPOINTS
   ========================================================================= */

/**
 * GET /instances — List instances, optionally filtered by event.
 *
 * @param WP_REST_Request $request The request object.
 * @return WP_REST_Response
 */
function northfield_api_get_instances( $request ) {
	$event_id = $request->get_param( 'event_id' ) ?? '';
	$args     = array(
		'from' => $request->get_param( 'from' ) ?? '',
		'to'   => $request->get_param( 'to' ) ?? '',
	);

	$instances = northfield_get_instances( $event_id, $args );

	return rest_ensure_response( array(
		'data'  => $instances,
		'total' => count( $instances ),
	) );
}

/* =========================================================================
   TICKET TYPE ENDPOINTS
   ========================================================================= */

/**
 * GET /ticket-types/{event_id} — Get ticket types with prices for an event.
 *
 * @param WP_REST_Request $request The request object.
 * @return WP_REST_Response|WP_Error
 */
function northfield_api_get_ticket_types( $request ) {
	$event_id     = $request->get_param( 'event_id' );
	$ticket_types = northfield_get_event_ticket_types( $event_id );

	if ( empty( $ticket_types ) ) {
		return new WP_Error(
			'event_not_found',
			__( 'Event not found or no ticket types available.', 'northfield-theatre' ),
			array( 'status' => 404 )
		);
	}

	return rest_ensure_response( $ticket_types );
}

/* =========================================================================
   BASKET ENDPOINTS
   Basket state is stored server-side using WordPress transients,
   identified by a session cookie. This mirrors how Spektrix manages
   basket sessions.
   ========================================================================= */

/**
 * Get or create a basket session ID.
 *
 * @return string The session ID.
 */
function northfield_get_basket_session_id() {
	$cookie_name = 'northfield_basket_session';

	if ( isset( $_COOKIE[ $cookie_name ] ) ) {
		return sanitize_text_field( $_COOKIE[ $cookie_name ] );
	}

	$session_id = wp_generate_uuid4();

	// Set cookie for 24 hours.
	setcookie(
		$cookie_name,
		$session_id,
		time() + DAY_IN_SECONDS,
		COOKIEPATH,
		COOKIE_DOMAIN,
		is_ssl(),
		true
	);

	return $session_id;
}

/**
 * Get the current basket from transients.
 *
 * @return array The basket data.
 */
function northfield_get_basket_data() {
	$session_id = northfield_get_basket_session_id();
	$basket     = get_transient( 'northfield_basket_' . $session_id );

	if ( false === $basket ) {
		return array(
			'items'    => array(),
			'subtotal' => 0,
			'donation' => 0,
			'total'    => 0,
		);
	}

	return $basket;
}

/**
 * Save the basket to transients.
 *
 * @param array $basket The basket data.
 */
function northfield_save_basket_data( $basket ) {
	$session_id = northfield_get_basket_session_id();
	set_transient( 'northfield_basket_' . $session_id, $basket, DAY_IN_SECONDS );
}

/**
 * Recalculate basket totals.
 *
 * @param array $basket The basket data.
 * @return array Updated basket with recalculated totals.
 */
function northfield_recalculate_basket( $basket ) {
	$subtotal = 0;

	foreach ( $basket['items'] as &$item ) {
		$item['lineTotal'] = round( $item['price'] * $item['quantity'], 2 );
		$subtotal         += $item['lineTotal'];
	}
	unset( $item );

	$basket['subtotal'] = round( $subtotal, 2 );
	$basket['total']    = round( $subtotal + $basket['donation'], 2 );

	return $basket;
}

/**
 * GET /basket — Return the current basket.
 *
 * @param WP_REST_Request $request The request object.
 * @return WP_REST_Response
 */
function northfield_api_get_basket( $request ) {
	$basket = northfield_get_basket_data();
	return rest_ensure_response( $basket );
}

/**
 * POST /basket/items — Add an item to the basket.
 *
 * @param WP_REST_Request $request The request object.
 * @return WP_REST_Response|WP_Error
 */
function northfield_api_add_basket_item( $request ) {
	$event_id       = $request->get_param( 'eventId' );
	$instance_id    = $request->get_param( 'instanceId' );
	$ticket_type_id = $request->get_param( 'ticketTypeId' );
	$quantity       = $request->get_param( 'quantity' );

	// Validate event exists.
	$event = northfield_get_event( $event_id );
	if ( ! $event ) {
		return new WP_Error( 'invalid_event', __( 'Event not found.', 'northfield-theatre' ), array( 'status' => 400 ) );
	}

	// Validate instance exists and belongs to event.
	$instance = northfield_get_instance( $instance_id );
	if ( ! $instance || $instance['eventId'] !== $event_id ) {
		return new WP_Error( 'invalid_instance', __( 'Performance not found.', 'northfield-theatre' ), array( 'status' => 400 ) );
	}

	// Validate instance is on sale.
	if ( $instance['saleStatus'] !== 'OnSale' ) {
		return new WP_Error( 'not_on_sale', __( 'This performance is not currently on sale.', 'northfield-theatre' ), array( 'status' => 400 ) );
	}

	// Validate ticket type and get price.
	$ticket_types = northfield_get_event_ticket_types( $event_id );
	$ticket_type  = null;
	foreach ( $ticket_types as $tt ) {
		if ( $tt['id'] === $ticket_type_id ) {
			$ticket_type = $tt;
			break;
		}
	}

	if ( ! $ticket_type ) {
		return new WP_Error( 'invalid_ticket_type', __( 'Ticket type not found.', 'northfield-theatre' ), array( 'status' => 400 ) );
	}

	// Validate quantity.
	if ( $quantity < 1 || $quantity > 10 ) {
		return new WP_Error( 'invalid_quantity', __( 'Quantity must be between 1 and 10.', 'northfield-theatre' ), array( 'status' => 400 ) );
	}

	$basket = northfield_get_basket_data();

	// Check if this exact combination already exists in the basket.
	$existing_index = null;
	foreach ( $basket['items'] as $index => $item ) {
		if (
			$item['eventId'] === $event_id &&
			$item['instanceId'] === $instance_id &&
			$item['ticketTypeId'] === $ticket_type_id
		) {
			$existing_index = $index;
			break;
		}
	}

	if ( null !== $existing_index ) {
		// Update quantity of existing item.
		$basket['items'][ $existing_index ]['quantity'] += $quantity;
	} else {
		// Add new item.
		$basket['items'][] = array(
			'id'             => 'bi_' . wp_generate_uuid4(),
			'eventId'        => $event_id,
			'eventName'      => $event['name'],
			'eventSlug'      => $event['slug'],
			'eventImage'     => $event['thumbnail'],
			'instanceId'     => $instance_id,
			'datetime'       => $instance['datetime'],
			'venue'          => $instance['venue'],
			'ticketTypeId'   => $ticket_type_id,
			'ticketTypeName' => $ticket_type['name'],
			'price'          => $ticket_type['price'],
			'quantity'       => $quantity,
			'lineTotal'      => round( $ticket_type['price'] * $quantity, 2 ),
		);
	}

	$basket = northfield_recalculate_basket( $basket );
	northfield_save_basket_data( $basket );

	return rest_ensure_response( $basket );
}

/**
 * PATCH /basket/items/{id} — Update item quantity.
 *
 * @param WP_REST_Request $request The request object.
 * @return WP_REST_Response|WP_Error
 */
function northfield_api_update_basket_item( $request ) {
	$item_id  = $request->get_param( 'id' );
	$quantity = $request->get_param( 'quantity' );

	if ( $quantity < 0 || $quantity > 10 ) {
		return new WP_Error( 'invalid_quantity', __( 'Quantity must be between 0 and 10.', 'northfield-theatre' ), array( 'status' => 400 ) );
	}

	$basket = northfield_get_basket_data();

	$found = false;
	foreach ( $basket['items'] as $index => &$item ) {
		if ( $item['id'] === $item_id ) {
			if ( $quantity === 0 ) {
				// Remove item if quantity is 0.
				array_splice( $basket['items'], $index, 1 );
			} else {
				$item['quantity'] = $quantity;
			}
			$found = true;
			break;
		}
	}
	unset( $item );

	if ( ! $found ) {
		return new WP_Error( 'item_not_found', __( 'Basket item not found.', 'northfield-theatre' ), array( 'status' => 404 ) );
	}

	$basket = northfield_recalculate_basket( $basket );
	northfield_save_basket_data( $basket );

	return rest_ensure_response( $basket );
}

/**
 * DELETE /basket/items/{id} — Remove an item from the basket.
 *
 * @param WP_REST_Request $request The request object.
 * @return WP_REST_Response|WP_Error
 */
function northfield_api_delete_basket_item( $request ) {
	$item_id = $request->get_param( 'id' );
	$basket  = northfield_get_basket_data();

	$found = false;
	foreach ( $basket['items'] as $index => $item ) {
		if ( $item['id'] === $item_id ) {
			array_splice( $basket['items'], $index, 1 );
			$found = true;
			break;
		}
	}

	if ( ! $found ) {
		return new WP_Error( 'item_not_found', __( 'Basket item not found.', 'northfield-theatre' ), array( 'status' => 404 ) );
	}

	$basket = northfield_recalculate_basket( $basket );
	northfield_save_basket_data( $basket );

	return rest_ensure_response( $basket );
}
