<?php
/**
 * EventController
 *
 * Handles admin CRUD for events and public event endpoints.
 * All methods are guarded by rtrb_is_module_active('event').
 *
 * @package RadiusTheme\RadiusBooking\Controllers
 * @since   1.3.0
 */

namespace RadiusTheme\RadiusBooking\Controllers;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

use RadiusTheme\RadiusBooking\Abstracts\BaseController;
use RadiusTheme\RadiusBooking\Core\Api\ApiResponse;
use RadiusTheme\RadiusBooking\Core\Api\Middleware\PermissionMiddleware;
use RadiusTheme\RadiusBooking\Core\Api\Validation\Rules\IntegerRule;
use RadiusTheme\RadiusBooking\Core\Api\Validation\Rules\RequiredRule;
use RadiusTheme\RadiusBooking\Core\Container\Container;
use RadiusTheme\RadiusBooking\Repositories\EventRepository;
use RadiusTheme\RadiusBooking\Repositories\EventRegistrationRepository;
use RadiusTheme\RadiusBooking\Resources\EventResource;
use RadiusTheme\RadiusBooking\Services\EventService;
use WP_REST_Request;

/**
 * Class EventController
 */
class EventController extends BaseController {

	/**
	 * EventController constructor.
	 */
	public function __construct() {
		parent::__construct( Container::resolve( EventRepository::class ) );
		$this->middleware[] = new PermissionMiddleware( 'manage_options' );
	}

	/**
	 * Transform a single item for API response.
	 *
	 * @param mixed $item The item to transform.
	 *
	 * @return array
	 */
	protected function transformItem( $item ): array {
		return ( new EventResource() )->transform( $item );
	}

	/**
	 * Transform a collection for API response.
	 *
	 * @param array $items Items to transform.
	 *
	 * @return array
	 */
	protected function transformCollection( array $items ): array {
		return EventResource::collection( $items );
	}

	/**
	 * Get validation rules for store/update.
	 *
	 * @param WP_REST_Request $request The request.
	 * @param string          $context 'create' or 'update'.
	 *
	 * @return array
	 */
	protected function getValidationRules( $request, string $context = 'create' ): array {
		return array(
			'name'         => array( new RequiredRule() ),
			'organizer_id' => array( new RequiredRule(), new IntegerRule() ),
			'start_date'   => array( new RequiredRule() ),
			'start_time'   => array( new RequiredRule() ),
			'end_time'     => array( new RequiredRule() ),
		);
	}

	/**
	 * Get the resource type identifier.
	 *
	 * @return string
	 */
	protected function getResourceType(): string {
		return 'event';
	}

	/**
	 * List all events (admin).
	 *
	 * @param WP_REST_Request $request The request.
	 *
	 * @return \WP_REST_Response|\WP_Error
	 */
	public function index( WP_REST_Request $request ) {
		if ( ! rtrb_is_module_active( 'event' ) ) {
			return ApiResponse::error( esc_html__( 'Event module is not active.', 'radius-booking' ), 403 )->send();
		}
		return parent::index( $request );
	}

	/**
	 * Store a new event (admin).
	 *
	 * Uses EventService to persist ticket types and sessions alongside the event.
	 *
	 * @param WP_REST_Request $request The request.
	 *
	 * @return \WP_REST_Response|\WP_Error
	 */
	public function store( WP_REST_Request $request ) {
		if ( ! rtrb_is_module_active( 'event' ) ) {
			return ApiResponse::error( esc_html__( 'Event module is not active.', 'radius-booking' ), 403 )->send();
		}

		return $this->applyMiddleware(
			$request,
			function ( $request ) {
				$validation = $this->validateRequest( $request, $this->getValidationRulesWithContext( 'create', $request ) );
				if ( $validation ) {
					return $validation;
				}

				try {
					$data    = $this->prepareDataForStorage( $request, 'create' );
					$service = Container::resolve( EventService::class );
					$item    = $service->createEvent( $data );

					do_action( 'radius_booking_item_created_' . $this->getResourceType(), $data, $item, $request, $this );

					return ApiResponse::created( $this->transformItem( $item ) )->send();
				} catch ( \Exception $e ) {
					return ApiResponse::error( $e->getMessage(), 500 )->send();
				}
			}
		);
	}

	/**
	 * Update an existing event (admin).
	 *
	 * Uses EventService to sync ticket types and sessions alongside the event.
	 *
	 * @param WP_REST_Request $request The request.
	 *
	 * @return \WP_REST_Response|\WP_Error
	 */
	public function update( WP_REST_Request $request ) {
		if ( ! rtrb_is_module_active( 'event' ) ) {
			return ApiResponse::error( esc_html__( 'Event module is not active.', 'radius-booking' ), 403 )->send();
		}

		return $this->applyMiddleware(
			$request,
			function ( $request ) {
				$id = (int) $request->get_param( 'id' );

				if ( ! $this->repository->exists( $id ) ) {
					return ApiResponse::notFound()->send();
				}

				$validation = $this->validateRequest( $request, $this->getValidationRulesWithContext( 'update', $request ) );
				if ( $validation ) {
					return $validation;
				}

				try {
					$data    = $this->prepareDataForStorage( $request, 'update' );
					$service = Container::resolve( EventService::class );
					$service->updateEvent( $id, $data );
					$item = $this->repository->find( $id );

					do_action( 'radius_booking_item_updated_' . $this->getResourceType(), $item, $request, $this );

					return ApiResponse::success( $this->transformItem( $item ) )->send();
				} catch ( \Exception $e ) {
					return ApiResponse::error( $e->getMessage(), 500 )->send();
				}
			}
		);
	}

	/**
	 * Publish an event (admin).
	 *
	 * @param WP_REST_Request $request The request.
	 *
	 * @return \WP_REST_Response|\WP_Error
	 */
	public function publish( WP_REST_Request $request ) {
		if ( ! rtrb_is_module_active( 'event' ) ) {
			return ApiResponse::error( esc_html__( 'Event module is not active.', 'radius-booking' ), 403 )->send();
		}

		return $this->applyMiddleware(
			$request,
			function ( $request ) {
				$id = (int) $request->get_param( 'id' );

				try {
					$service = Container::resolve( EventService::class );
					$result  = $service->publishEvent( $id );

					return ApiResponse::success( $this->transformItem( $result ), esc_html__( 'Event published successfully.', 'radius-booking' ) )->send();
				} catch ( \Exception $e ) {
					return ApiResponse::error( $e->getMessage(), 400 )->send();
				}
			}
		);
	}

	/**
	 * Get registrations for an event (admin).
	 *
	 * @param WP_REST_Request $request The request.
	 *
	 * @return \WP_REST_Response|\WP_Error
	 */
	public function getRegistrations( WP_REST_Request $request ) {
		if ( ! rtrb_is_module_active( 'event' ) ) {
			return ApiResponse::error( esc_html__( 'Event module is not active.', 'radius-booking' ), 403 )->send();
		}

		return $this->applyMiddleware(
			$request,
			function ( $request ) {
				$event_id = (int) $request->get_param( 'id' );
				$page     = $request->get_param( 'page' ) ? (int) $request->get_param( 'page' ) : 1;
				$per_page = $request->get_param( 'per_page' ) ? (int) $request->get_param( 'per_page' ) : 15;

				$repo   = Container::resolve( EventRegistrationRepository::class );
				$result = $repo->getByEventId( $event_id, $per_page, $page );

				return ApiResponse::success( $result )->send();
			}
		);
	}

	/**
	 * Check in a registration by token (admin).
	 *
	 * @param WP_REST_Request $request The request.
	 *
	 * @return \WP_REST_Response|\WP_Error
	 */
	public function checkIn( WP_REST_Request $request ) {
		if ( ! rtrb_is_module_active( 'event' ) ) {
			return ApiResponse::error( esc_html__( 'Event module is not active.', 'radius-booking' ), 403 )->send();
		}

		return $this->applyMiddleware(
			$request,
			function ( $request ) {
				$check_in_token = sanitize_text_field( $request->get_param( 'check_in_token' ) );

				if ( empty( $check_in_token ) ) {
					return ApiResponse::validationError(
						array( 'check_in_token' => esc_html__( 'Check-in token is required.', 'radius-booking' ) )
					)->send();
				}

				$repo         = Container::resolve( EventRegistrationRepository::class );
				$registration = $repo->findByCheckInToken( $check_in_token );

				if ( ! $registration ) {
					return ApiResponse::notFound( esc_html__( 'Registration not found.', 'radius-booking' ) )->send();
				}

				$repo->update(
					$registration->id,
					array(
						'checked_in_at' => current_time( 'mysql' ),
						'status'        => 'attended',
					)
				);

				$updated = $repo->find( $registration->id );

				return ApiResponse::success( $updated, esc_html__( 'Check-in successful.', 'radius-booking' ) )->send();
			}
		);
	}

	// --- Public Endpoints (no auth middleware) ---

	/**
	 * Get public event list (no auth).
	 *
	 * @param WP_REST_Request $request The request.
	 *
	 * @return \WP_REST_Response|\WP_Error
	 */
	public function getPublicEventList( WP_REST_Request $request ) {
		if ( ! rtrb_is_module_active( 'event' ) ) {
			return ApiResponse::error( esc_html__( 'Event module is not active.', 'radius-booking' ), 403 )->send();
		}

		return $this->applyBypass(
			$request,
			function ( $request ) {
				$page     = $request->get_param( 'page' ) ? (int) $request->get_param( 'page' ) : 1;
				$per_page = $request->get_param( 'per_page' ) ? (int) $request->get_param( 'per_page' ) : 12;
				$category = $request->get_param( 'category' ) ? sanitize_text_field( $request->get_param( 'category' ) ) : null;

				$service = Container::resolve( EventService::class );
				$result  = $service->getPublicEventList( array(
					'page'        => $page,
					'per_page'    => $per_page,
					'category_id' => $category,
				) );

				return ApiResponse::success( $result->toArray() )->send();
			}
		);
	}

	/**
	 * Get a single public event by slug (no auth).
	 *
	 * @param WP_REST_Request $request The request.
	 *
	 * @return \WP_REST_Response|\WP_Error
	 */
	public function getPublicEvent( WP_REST_Request $request ) {
		if ( ! rtrb_is_module_active( 'event' ) ) {
			return ApiResponse::error( esc_html__( 'Event module is not active.', 'radius-booking' ), 403 )->send();
		}

		return $this->applyBypass(
			$request,
			function ( $request ) {
				$slug = sanitize_text_field( $request->get_param( 'slug' ) );

				$service = Container::resolve( EventService::class );
				$result  = $service->getPublicEvent( $slug );

				if ( ! $result ) {
					return ApiResponse::notFound( esc_html__( 'Event not found.', 'radius-booking' ) )->send();
				}

				return ApiResponse::success( $result )->send();
			}
		);
	}
}
