<?php

namespace RadiusTheme\RadiusBooking\ExportImport;

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

use WP_REST_Request;
use RadiusTheme\RadiusBooking\Common\Keys;
use RadiusTheme\RadiusBooking\Core\Api\ApiResponse;
use RadiusTheme\RadiusBooking\Core\Api\Middleware\PermissionMiddleware;
use RadiusTheme\RadiusBooking\Core\Container\Container;

/**
 * Class ExportImportController
 *
 * REST API controller for export/import operations.
 *
 * @package RadiusTheme\RadiusBooking\ExportImport
 */
class ExportImportController {

	/**
	 * Middleware stack.
	 *
	 * @var array
	 */
	private array $middleware = array();

	/**
	 * Constructor.
	 */
	public function __construct() {
		$this->middleware[] = new PermissionMiddleware( 'manage_options' );
	}

	/**
	 * Apply middleware stack to a request.
	 *
	 * @param WP_REST_Request $request Request.
	 * @param callable        $handler Handler callback.
	 *
	 * @return mixed
	 */
	private function applyMiddleware( WP_REST_Request $request, callable $handler ) {
		$stack = array_reverse( $this->middleware );
		$next  = $handler;

		foreach ( $stack as $mw ) {
			$next = function ( $req ) use ( $mw, $next ) {
				return $mw->handle( $req, $next );
			};
		}

		return $next( $request );
	}

	/**
	 * Get the service instance.
	 *
	 * @return ExportImportService
	 */
	private function getService(): ExportImportService {
		return Container::resolve( ExportImportService::class );
	}

	/**
	 * GET /export-import/modules
	 *
	 * List available modules with record counts.
	 *
	 * @param WP_REST_Request $request Request.
	 *
	 * @return ApiResponse
	 */
	public function getModules( WP_REST_Request $request ) {
		return $this->applyMiddleware(
			$request,
			function () {
				try {
					$modules = $this->getService()->getAvailableModules();
					return ApiResponse::success( array( 'modules' => $modules ) )->send();
				} catch ( \Exception $e ) {
					return ApiResponse::error( $e->getMessage(), 500 )->send();
				}
			}
		);
	}

	/**
	 * POST /export-import/export/init
	 *
	 * Initialize export with selected modules.
	 * Expects: { modules: ['category', 'service', ...] }
	 *
	 * @param WP_REST_Request $request Request.
	 *
	 * @return ApiResponse
	 */
	public function initExport( WP_REST_Request $request ) {
		return $this->applyMiddleware(
			$request,
			function ( $request ) {
				try {
					$params  = $request->get_json_params();
					$modules = $params['modules'] ?? array();

					if ( empty( $modules ) || ! is_array( $modules ) ) {
						return ApiResponse::error( __( 'Please select at least one module to export.', 'radius-booking' ) )->send();
					}

					$service = $this->getService();
					$ordered = $service->resolveDependencyOrder( $modules );
					$counts  = $service->getExportCounts( $ordered );

					return ApiResponse::success(
						array(
							'metadata' => $service->buildExportMetadata( $ordered, $counts ),
							'modules'  => $ordered,
							'counts'   => $counts,
						)
					)->send();
				} catch ( \Exception $e ) {
					return ApiResponse::error( $e->getMessage(), 500 )->send();
				}
			}
		);
	}

	/**
	 * GET /export-import/export/batch
	 *
	 * Export one batch of records.
	 * Params: module, offset, limit
	 *
	 * @param WP_REST_Request $request Request.
	 *
	 * @return ApiResponse
	 */
	public function exportBatch( WP_REST_Request $request ) {
		return $this->applyMiddleware(
			$request,
			function ( $request ) {
				try {
					$module = sanitize_text_field( $request->get_param( 'module' ) );
					$offset = absint( $request->get_param( 'offset' ) ?? 0 );
					$limit  = absint( $request->get_param( 'limit' ) ?? 500 );

					if ( empty( $module ) ) {
						return ApiResponse::error( __( 'Module parameter is required.', 'radius-booking' ) )->send();
					}

					$service  = $this->getService();
					$exporter = $service->getExporter( $module );

					if ( ! $exporter ) {
						return ApiResponse::error(
							/* translators: %s: module name */
							sprintf( __( 'Unknown module: %s', 'radius-booking' ), $module ),
							404
						)->send();
					}

					$records  = $service->exportBatch( $module, $offset, $limit );
					$total    = $exporter->count();
					$has_more = ( $offset + $limit ) < $total;

					return ApiResponse::success(
						array(
							'module'   => $module,
							'records'  => $records,
							'offset'   => $offset,
							'limit'    => $limit,
							'total'    => $total,
							'has_more' => $has_more,
						)
					)->send();
				} catch ( \Exception $e ) {
					return ApiResponse::error( $e->getMessage(), 500 )->send();
				}
			}
		);
	}

	/**
	 * POST /export-import/import/init
	 *
	 * Validate import file and return import plan.
	 * Expects: { metadata: {...}, data: {...} } — full JSON structure.
	 *
	 * @param WP_REST_Request $request Request.
	 *
	 * @return ApiResponse
	 */
	public function initImport( WP_REST_Request $request ) {
		return $this->applyMiddleware(
			$request,
			function ( $request ) {
				try {
					$data = $request->get_json_params();

					if ( empty( $data ) ) {
						return ApiResponse::error( __( 'No import data provided.', 'radius-booking' ) )->send();
					}

					$service    = $this->getService();
					$validation = $service->validateImportFile( $data );

					if ( ! $validation['valid'] ) {
						return ApiResponse::error(
							__( 'Invalid import file.', 'radius-booking' ),
							422,
							$validation['errors']
						)->send();
					}

					$plan        = $service->getImportPlan( $data );
					$session_key = IdMapper::generateSessionKey();

					// Create the IdMapper transient to reserve the session.
					$id_mapper = new IdMapper( $session_key );
					$id_mapper->save();

					return ApiResponse::success(
						array(
							'session_key' => $session_key,
							'plan'        => $plan,
						)
					)->send();
				} catch ( \Exception $e ) {
					return ApiResponse::error( $e->getMessage(), 500 )->send();
				}
			}
		);
	}

	/**
	 * POST /export-import/import/batch
	 *
	 * Import one batch of records.
	 * Expects: { session_key: string, module: string, records: array }
	 *
	 * @param WP_REST_Request $request Request.
	 *
	 * @return ApiResponse
	 */
	public function importBatch( WP_REST_Request $request ) {
		return $this->applyMiddleware(
			$request,
			function ( $request ) {
				try {
					$params      = $request->get_json_params();
					$session_key = sanitize_text_field( $params['session_key'] ?? '' );
					$module      = sanitize_text_field( $params['module'] ?? '' );
					$records     = $params['records'] ?? array();

					if ( empty( $session_key ) || empty( $module ) ) {
						return ApiResponse::error( __( 'Session key and module are required.', 'radius-booking' ) )->send();
					}

					if ( empty( $records ) || ! is_array( $records ) ) {
						return ApiResponse::error( __( 'No records provided for import.', 'radius-booking' ) )->send();
					}

					$service   = $this->getService();
					$id_mapper = new IdMapper( $session_key );

					$imported = $service->importBatch( $module, $records, $id_mapper );

					// Persist updated mappings.
					$id_mapper->save();

					return ApiResponse::success(
						array(
							'module'   => $module,
							'imported' => $imported,
						)
					)->send();
				} catch ( \Exception $e ) {
					return ApiResponse::error( $e->getMessage(), 500 )->send();
				}
			}
		);
	}

	/**
	 * POST /export-import/import/cleanup
	 *
	 * Clean up import session transient.
	 * Expects: { session_key: string }
	 *
	 * @param WP_REST_Request $request Request.
	 *
	 * @return ApiResponse
	 */
	public function cleanupImport( WP_REST_Request $request ) {
		return $this->applyMiddleware(
			$request,
			function ( $request ) {
				try {
					$params      = $request->get_json_params();
					$session_key = sanitize_text_field( $params['session_key'] ?? '' );

					if ( empty( $session_key ) ) {
						return ApiResponse::error( __( 'Session key is required.', 'radius-booking' ) )->send();
					}

					$id_mapper = new IdMapper( $session_key );
					$id_mapper->cleanup();

					update_option( Keys::RADIUS_BOOKING_SETUP_COMPLETED, true );

					return ApiResponse::success(
						array(),
						__( 'Import session cleaned up successfully.', 'radius-booking' )
					)->send();
				} catch ( \Exception $e ) {
					return ApiResponse::error( $e->getMessage(), 500 )->send();
				}
			}
		);
	}
}
