<?php

namespace WPDRMS\ASP\Synonyms;

use Exception;
use WP_Error;
use WP_REST_Request;
use WP_REST_Response;
use WPDRMS\ASP\Synonyms\Exporters\SynonymsJSONExporter;
use WPDRMS\ASP\Synonyms\Importers\SynonymsJSONImporter;
use WPDRMS\PluginCore\Rest\AbstractRest;

class SynonymsRoute extends AbstractRest {
	public function registerRoutes( string $route_namespace ): void {
		register_rest_route(
			$route_namespace,
			'synonyms',
			array(
				array(
					'methods'             => 'GET',
					'callback'            => array( $this, 'listSynonyms' ),
					'permission_callback' => array( $this, 'allowOnlyAdmins' ),
				),
				array(
					'methods'             => 'POST',
					'callback'            => array( $this, 'saveSynonym' ),
					'permission_callback' => array( $this, 'allowOnlyAdmins' ),
				),
			),
		);

		register_rest_route(
			$route_namespace,
			'synonyms/(?P<id>\d+)',
			array(
				'methods'             => 'DELETE',
				'callback'            => array( $this, 'deleteSynonym' ),
				'permission_callback' => array( $this, 'allowOnlyAdmins' ),
			),
		);

		register_rest_route(
			$route_namespace,
			'synonyms/wipe',
			array(
				'methods'             => 'POST',
				'callback'            => array( $this, 'wipeSynonyms' ),
				'permission_callback' => array( $this, 'allowOnlyAdmins' ),
			),
		);

		register_rest_route(
			$route_namespace,
			'synonyms/export',
			array(
				'methods'             => 'GET',
				'callback'            => array( $this, 'exportSynonyms' ),
				'permission_callback' => array( $this, 'allowOnlyAdmins' ),
			),
		);

		register_rest_route(
			$route_namespace,
			'synonyms/import',
			array(
				'methods'             => 'POST',
				'callback'            => array( $this, 'importSynonyms' ),
				'permission_callback' => array( $this, 'allowOnlyAdmins' ),
			),
		);
	}

	/**
	 * GET /synonyms — list synonyms with pagination
	 *
	 * @param WP_REST_Request $request
	 * @return WP_Error|WP_REST_Response
	 */
	public function listSynonyms( WP_REST_Request $request ) {
		try {
			$search   = sanitize_text_field( $request->get_param( 'search' ) ?? '' );
			$lang     = sanitize_text_field( $request->get_param( 'lang' ) ?? 'any' );
			$per_page = min( 200, max( 1, (int) ( $request->get_param( 'per_page' ) ?? 25 ) ) );
			$page     = max( 1, (int) ( $request->get_param( 'page' ) ?? 1 ) );
			$offset   = ( $page - 1 ) * $per_page;

			$service = SynonymsService::getInstance();
			$total   = $service->count( $search, $lang );
			$pages   = max( 1, (int) ceil( $total / $per_page ) );
			$items   = $service->find( $search, $lang, $per_page, false, $offset );

			return new WP_REST_Response(
				array(
					'items'       => $items,
					'total'       => $total,
					'pages'       => $pages,
					'index_stale' => (bool) get_option( 'asp_synonyms_index_stale', false ),
				),
				200
			);
		} catch ( Exception $e ) {
			return new WP_Error( 'asp_synonyms_list', $e->getMessage() );
		}
	}

	/**
	 * POST /synonyms — create or update a synonym
	 *
	 * @param WP_REST_Request $request
	 * @return WP_Error|WP_REST_Response
	 */
	public function saveSynonym( WP_REST_Request $request ) {
		try {
			$params    = (array) $request->get_json_params();
			$keyword   = sanitize_text_field( $params['keyword'] ?? '' );
			$lang      = sanitize_text_field( $params['lang'] ?? '' );
			$overwrite = (bool) ( $params['overwrite_existing'] ?? true );

			$synonyms_raw = $params['synonyms'] ?? array();
			if ( is_string( $synonyms_raw ) ) {
				$synonyms = $synonyms_raw;
			} elseif ( is_array( $synonyms_raw ) ) {
				$synonyms = array_map( 'sanitize_text_field', $synonyms_raw );
			} else {
				$synonyms = array();
			}

			if ( $keyword === '' ) {
				return new WP_Error( 'asp_synonyms_save', __( 'Keyword is required.', 'ajax-search-pro' ) );
			}

			SynonymsService::getInstance()->update( $keyword, $synonyms, $lang, $overwrite );
			update_option( 'asp_synonyms_index_stale', 1 );

			$rows = SynonymsService::getInstance()->find( $keyword, $lang, 1, true );
			return new WP_REST_Response( $rows[0] ?? null, 200 );
		} catch ( Exception $e ) {
			return new WP_Error( 'asp_synonyms_save', $e->getMessage() );
		}
	}

	/**
	 * DELETE /synonyms/{id} — delete a synonym by ID
	 *
	 * @param WP_REST_Request $request
	 * @return WP_Error|WP_REST_Response
	 */
	public function deleteSynonym( WP_REST_Request $request ) {
		try {
			$id      = (int) $request->get_param( 'id' );
			$deleted = SynonymsService::getInstance()->deleteByID( $id );
			update_option( 'asp_synonyms_index_stale', 1 );
			return new WP_REST_Response( array( 'success' => $deleted > 0 ), 200 );
		} catch ( Exception $e ) {
			return new WP_Error( 'asp_synonyms_delete', $e->getMessage() );
		}
	}

	/**
	 * POST /synonyms/wipe — wipe all synonyms
	 *
	 * @return WP_Error|WP_REST_Response
	 */
	public function wipeSynonyms() {
		try {
			SynonymsService::getInstance()->wipe();
			update_option( 'asp_synonyms_index_stale', 1 );
			return new WP_REST_Response( array( 'success' => true ), 200 );
		} catch ( Exception $e ) {
			return new WP_Error( 'asp_synonyms_wipe', $e->getMessage() );
		}
	}

	/**
	 * GET /synonyms/export — stream synonyms as a JSON file download
	 *
	 * @return WP_Error|void  Returns WP_Error only when there is nothing to export.
	 */
	public function exportSynonyms() {
		try {
			SynonymsJSONExporter::instance()->download();
		} catch ( Exception $e ) {
			return new WP_Error( 'asp_synonyms_export', $e->getMessage() );
		}
	}

	/**
	 * POST /synonyms/import — import synonyms from a file upload
	 *
	 * @return WP_Error|WP_REST_Response
	 */
	public function importSynonyms() {
		try {
			if ( empty( $_FILES['file'] ) ) {
				return new WP_Error( 'asp_synonyms_import', __( 'No file uploaded.', 'ajax-search-pro' ) );
			}

			// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
			$imported = SynonymsJSONImporter::instance()->importFromUploadedFile( $_FILES['file'] );
			update_option( 'asp_synonyms_index_stale', 1 );
			return new WP_REST_Response( array( 'imported' => $imported ), 200 );
		} catch ( Exception $e ) {
			return new WP_Error( 'asp_synonyms_import', $e->getMessage() );
		}
	}
}
