<?php
/**
 * API admin importer class.
 *
 * @package SaveToWishlist\Classes\API
 * @since 1.0.3
 */
namespace SaveToWishlist\Classes\API;

use SaveToWishlist\Abstracts\Singleton;
use SaveToWishlist\Classes\Importers\Importer_Factory;

/**
 * Class API_Admin_Importer
 *
 * This class creates REST API endpoints for the importer.
 */
class API_Admin_Importer extends Singleton {
    use \SaveToWishlist\Traits\API_Permissions;

    /**
     * The API namespace.
     *
     * @since 1.0.3
     * @access private
     * @var string
     */
    private $api_namespace = 'saveto-wishlist/v1';

    /**
     * Base route.
     *
     * @since 1.0.3
     * @access private
     * @var string
     */
    private $base = 'admin/importer';

    /**
     * Run the application.
     *
     * @since 1.0.3
     * @access public
     */
    public function run() {
        // Register the API.
        add_action( 'rest_api_init', array( $this, 'register_api' ) );
    }

    /**
     * Register the API.
     *
     * @since 1.0.3
     */
    public function register_api() {

        // Get available sources.
        \register_rest_route(
            $this->api_namespace,
            '/' . $this->base . '/sources',
            array(
                array(
                    'methods'             => \WP_REST_Server::READABLE,
                    'permission_callback' => array( $this, 'check_admin_permission' ),
                    'callback'            => array( $this, 'get_sources' ),
                ),
            )
        );

        // Preview source data.
        \register_rest_route(
            $this->api_namespace,
            '/' . $this->base . '/preview/(?P<source>[a-zA-Z0-9-]+)',
            array(
                array(
                    'methods'             => \WP_REST_Server::READABLE,
                    'permission_callback' => array( $this, 'check_admin_permission' ),
                    'callback'            => array( $this, 'get_preview' ),
                    'args'                => array(
                        'source' => array(
                            'required'          => true,
                            'type'              => 'string',
                            'sanitize_callback' => 'sanitize_text_field',
                        ),
                    ),
                ),
            )
        );

        // Start import.
        \register_rest_route(
            $this->api_namespace,
            '/' . $this->base . '/import',
            array(
                array(
                    'methods'             => \WP_REST_Server::CREATABLE,
                    'permission_callback' => array( $this, 'check_admin_permission' ),
                    'callback'            => array( $this, 'start_import' ),
                    'args'                => array(
                        'source'  => array(
                            'required'          => true,
                            'type'              => 'string',
                            'sanitize_callback' => 'sanitize_text_field',
                        ),
                        'options' => array(
                            'required'          => false,
                            'type'              => 'object',
                            'default'           => array(),
                            'sanitize_callback' => function ( $options ) {
                                if ( ! is_array( $options ) ) {
                                    return array();
                                }
                                return array(
                                    'merge_existing'   => ! empty( $options['merge_existing'] ),
                                    'preserve_default' => isset( $options['preserve_default'] ) ? (bool) $options['preserve_default'] : true,
                                    'preserve_privacy' => isset( $options['preserve_privacy'] ) ? (bool) $options['preserve_privacy'] : true,
                                    'batch_number'     => isset( $options['batch_number'] ) ? absint( $options['batch_number'] ) : null,
                                    'job_id'           => isset( $options['job_id'] ) ? sanitize_text_field( $options['job_id'] ) : '',
                                );
                            },
                        ),
                    ),
                ),
            )
        );

        // Get import progress.
        \register_rest_route(
            $this->api_namespace,
            '/' . $this->base . '/import/(?P<job_id>[a-zA-Z0-9-]+)',
            array(
                array(
                    'methods'             => \WP_REST_Server::READABLE,
                    'permission_callback' => array( $this, 'check_admin_permission' ),
                    'callback'            => array( $this, 'get_import_progress' ),
                    'args'                => array(
                        'job_id' => array(
                            'required'          => true,
                            'type'              => 'string',
                            'sanitize_callback' => 'sanitize_text_field',
                        ),
                    ),
                ),
                array(
                    'methods'             => \WP_REST_Server::DELETABLE,
                    'permission_callback' => array( $this, 'check_admin_permission' ),
                    'callback'            => array( $this, 'cancel_import' ),
                    'args'                => array(
                        'job_id' => array(
                            'required'          => true,
                            'type'              => 'string',
                            'sanitize_callback' => 'sanitize_text_field',
                        ),
                    ),
                ),
            )
        );
    }

    /**
     * Get available import sources.
     *
     * @param \WP_REST_Request $request Request object.
     * @since 1.0.3
     * @access public
     * @return \WP_REST_Response
     */
    public function get_sources( $request ) {
        $sources = Importer_Factory::get_detected_importers();

        return rest_ensure_response(
            array(
                'sources' => $sources,
            )
        );
    }

    /**
     * Validate import source and return importer instance.
     *
     * @param string $source Source slug.
     * @since 1.0.3
     * @access protected
     * @return Abstract_Importer|\WP_Error Returns importer instance or WP_Error.
     */
    protected function validate_import_source( $source ) {
        $importer = Importer_Factory::get_importer( $source );

        if ( ! $importer ) {
            return new \WP_Error(
                'invalid_source',
                __( 'Invalid import source.', 'saveto-wishlist-lite-for-woocommerce' ),
                array( 'status' => 400 )
            );
        }

        if ( ! $importer->is_source_active() ) {
            return new \WP_Error(
                'source_not_active',
                __( 'Import source is not active.', 'saveto-wishlist-lite-for-woocommerce' ),
                array( 'status' => 400 )
            );
        }

        return $importer;
    }

    /**
     * Get preview data for a source.
     *
     * @param \WP_REST_Request $request Request object.
     * @since 1.0.3
     * @access public
     * @return \WP_REST_Response
     */
    public function get_preview( $request ) {
        $source   = $request->get_param( 'source' );
        $importer = $this->validate_import_source( $source );

        if ( is_wp_error( $importer ) ) {
            return $importer;
        }

        $counts  = $importer->get_source_data_count();
        $preview = $importer->get_preview_data();

        return rest_ensure_response(
            array(
                'counts'  => $counts,
                'preview' => $preview,
            )
        );
    }

    /**
     * Start import process.
     *
     * @param \WP_REST_Request $request Request object.
     * @since 1.0.3
     * @access public
     * @return \WP_REST_Response
     */
    public function start_import( $request ) {
        $source  = $request->get_param( 'source' );
        $options = $request->get_param( 'options' );

        $importer = $this->validate_import_source( $source );

        if ( is_wp_error( $importer ) ) {
            return $importer;
        }

        // Check rate limiting (1 import per 5 minutes).
        $current_user_id = get_current_user_id();
        $last_import     = get_transient( STWLITE_LAST_IMPORT_TIME_GROUP . $current_user_id );
        if ( $last_import && ( time() - $last_import ) < STWLITE_IMPORT_RATE_LIMIT ) {
            return new \WP_Error(
                'rate_limit',
                __( 'Please wait before starting another import.', 'saveto-wishlist-lite-for-woocommerce' ),
                array( 'status' => 429 )
            );
        }

        // Start import.
        $result = $importer->import( $options ?? array() );

        if ( ! $result['success'] ) {
            return new \WP_Error(
                'import_failed',
                $result['message'] ?? __( 'Import failed.', 'saveto-wishlist-lite-for-woocommerce' ),
                array( 'status' => 500 )
            );
        }

        // Set rate limit after successful import.
        set_transient( STWLITE_LAST_IMPORT_TIME_GROUP . $current_user_id, time(), STWLITE_IMPORT_RATE_LIMIT );

        return rest_ensure_response(
            array(
                'success' => true,
                'stats'   => $result['stats'],
                'log'     => $result['log'],
            )
        );
    }

    /**
     * Get import progress.
     *
     * @param \WP_REST_Request $request Request object.
     * @since 1.0.3
     * @access public
     * @return \WP_REST_Response
     */
    public function get_import_progress( $request ) {
        $job_id   = $request->get_param( 'job_id' );
        $progress = get_transient( STWLITE_IMPORT_PROGRESS_GROUP . $job_id );

        if ( false === $progress ) {
            return new \WP_Error(
                'job_not_found',
                __( 'Import job not found.', 'saveto-wishlist-lite-for-woocommerce' ),
                array( 'status' => 404 )
            );
        }

        return rest_ensure_response( $progress );
    }

    /**
     * Cancel import.
     *
     * @param \WP_REST_Request $request Request object.
     * @since 1.0.3
     * @access public
     * @return \WP_REST_Response
     */
    public function cancel_import( $request ) {
        $job_id   = $request->get_param( 'job_id' );
        $progress = get_transient( STWLITE_IMPORT_PROGRESS_GROUP . $job_id );
        if ( false === $progress ) {
            return new \WP_Error( 'job_not_found', __( 'Import job not found.', 'saveto-wishlist-lite-for-woocommerce' ), array( 'status' => 404 ) );
        }

        $progress_user_id = $progress['user_id'] ?? 0;
        if ( get_current_user_id() !== $progress_user_id && ! current_user_can( 'manage_options' ) ) {
            return new \WP_Error( 'not_authorized', __( 'You are not authorized to cancel this import.', 'saveto-wishlist-lite-for-woocommerce' ), array( 'status' => 403 ) );
        }

        // Clear targeted caches for affected users.
        delete_transient( STWLITE_IMPORT_PROGRESS_GROUP . $job_id );

        return rest_ensure_response(
            array(
                'success' => true,
                'message' => __( 'Import cancelled.', 'saveto-wishlist-lite-for-woocommerce' ),
            )
        );
    }
}
