<?php

/**
 * REST API controller for redirects.
 *
 * @link          https://aleksandrsamokhin.com
 * @since         1.0.0
 *
 * @author        Aleksandr Samokhin
 * @package       Redicl\REST_API
 *
 * @copyright (c) 2025, Aleksandr Samokhin
 */
namespace Redicl\REST_API;

use Redicl\Core\Redirects_Processor;
// Abort if called directly.
defined( 'WPINC' ) || die;
/**
 * REST API controller class.
 */
class Redirects_Controller {
    /**
     * The namespace for the REST API.
     *
     * @var string
     */
    private $namespace = 'redirect-cleanup/v1';

    /**
     * Register REST API routes.
     *
     * @return void
     * @since 1.0.0
     */
    public function register_routes() {
        register_rest_route( $this->namespace, '/scan', array(
            'methods'             => 'POST',
            'callback'            => array($this, 'scan_redirects'),
            'permission_callback' => array($this, 'check_permissions'),
            'args'                => array(
                'post_types' => array(
                    'default'           => array('post'),
                    'sanitize_callback' => function ( $param ) {
                        if ( !is_array( $param ) ) {
                            return array('post');
                        }
                        return array_map( 'sanitize_key', $param );
                    },
                ),
            ),
        ) );
        register_rest_route( $this->namespace, '/home-redirects', array(
            'methods'             => 'GET',
            'callback'            => array($this, 'get_home_redirects'),
            'permission_callback' => array($this, 'check_permissions'),
            'args'                => array(
                'page'       => array(
                    'default'           => 1,
                    'sanitize_callback' => 'absint',
                ),
                'per_page'   => array(
                    'default'           => 50,
                    'sanitize_callback' => 'absint',
                ),
                'post_types' => array(
                    'default'           => array('post'),
                    'sanitize_callback' => function ( $param ) {
                        // Handle comma-separated string from query params.
                        if ( is_string( $param ) ) {
                            $param = explode( ',', $param );
                        }
                        if ( !is_array( $param ) ) {
                            return array('post');
                        }
                        return array_map( 'sanitize_key', array_filter( $param ) );
                    },
                ),
            ),
        ) );
        register_rest_route( $this->namespace, '/post-types', array(
            'methods'             => 'GET',
            'callback'            => array($this, 'get_available_post_types'),
            'permission_callback' => array($this, 'check_permissions'),
        ) );
        register_rest_route( $this->namespace, '/chain-redirects', array(
            'methods'             => 'GET',
            'callback'            => array($this, 'get_chain_redirects'),
            'permission_callback' => array($this, 'check_permissions'),
            'args'                => array(
                'min_chain_length' => array(
                    'default'           => 3,
                    'sanitize_callback' => 'absint',
                ),
                'page'             => array(
                    'default'           => 1,
                    'sanitize_callback' => 'absint',
                ),
                'per_page'         => array(
                    'default'           => 50,
                    'sanitize_callback' => 'absint',
                ),
            ),
        ) );
        register_rest_route( $this->namespace, '/stats', array(
            'methods'             => 'GET',
            'callback'            => array($this, 'get_stats'),
            'permission_callback' => array($this, 'check_permissions'),
        ) );
    }

    /**
     * Check if user has permission to access the API.
     *
     * @return bool
     * @since 1.0.0
     */
    public function check_permissions() {
        return current_user_can( 'manage_options' );
    }

    /**
     * Scan for homepage redirects.
     *
     * Only counts redirects that are found in at least one post of the selected post types.
     *
     * @param \WP_REST_Request $request The REST request object.
     * @return \WP_REST_Response|\WP_Error
     * @since 1.0.0
     */
    public function scan_redirects( $request ) {
        $post_types = $request->get_param( 'post_types' );
        // Use cached method to get homepage redirect URLs.
        $homepage_redirect_urls = Redirects_Processor::get_homepage_redirect_urls();
        if ( empty( $homepage_redirect_urls ) ) {
            return new \WP_REST_Response(array(
                'success' => true,
                'total'   => 0,
                'message' => __( 'No redirects found.', 'redirect-cleanup' ),
            ), 200);
        }
        // Find posts containing these URLs, filtered by post types.
        $posts_by_url = Redirects_Processor::find_posts_for_urls( $homepage_redirect_urls, $post_types );
        // Count only redirects that are found in at least one post.
        $total = 0;
        foreach ( $posts_by_url as $url => $posts ) {
            if ( !empty( $posts ) ) {
                ++$total;
            }
        }
        if ( 0 === $total ) {
            return new \WP_REST_Response(array(
                'success' => true,
                'total'   => 0,
                'message' => __( 'No redirects found in posts.', 'redirect-cleanup' ),
            ), 200);
        }
        return new \WP_REST_Response(array(
            'success' => true,
            'total'   => $total,
            'message' => sprintf( 
                // translators: %d is the number of homepage redirects found.
                _n(
                    'Found %d homepage redirect in posts.',
                    'Found %d homepage redirects in posts.',
                    $total,
                    'redirect-cleanup'
                ),
                $total
             ),
        ), 200);
    }

    /**
     * Get paginated homepage redirects.
     *
     * Only returns redirects that are found in at least one post of the selected post types.
     *
     * @param \WP_REST_Request $request The REST request object.
     * @return \WP_REST_Response|\WP_Error
     * @since 1.0.0
     */
    public function get_home_redirects( $request ) {
        $page = $request->get_param( 'page' );
        $per_page = $request->get_param( 'per_page' );
        $post_types = $request->get_param( 'post_types' );
        // Use cached method to get homepage redirects.
        $homepage_redirects = Redirects_Processor::get_homepage_redirects();
        if ( empty( $homepage_redirects ) ) {
            return new \WP_REST_Response(array(
                'success'  => true,
                'data'     => array(),
                'total'    => 0,
                'pages'    => 0,
                'page'     => $page,
                'per_page' => $per_page,
            ), 200);
        }
        // Get all source URLs.
        $all_source_urls = array_keys( $homepage_redirects );
        // Find posts containing these URLs in batch (optimized), filtered by post types.
        $posts_by_url = Redirects_Processor::find_posts_for_urls( $all_source_urls, $post_types );
        // Filter to only include redirects found in at least one post.
        $filtered_redirects = array();
        foreach ( $homepage_redirects as $source_url => $redirect_data ) {
            if ( !empty( $posts_by_url[$source_url] ) ) {
                $filtered_redirects[$source_url] = $redirect_data;
            }
        }
        if ( empty( $filtered_redirects ) ) {
            return new \WP_REST_Response(array(
                'success'  => true,
                'data'     => array(),
                'total'    => 0,
                'pages'    => 0,
                'page'     => $page,
                'per_page' => $per_page,
            ), 200);
        }
        // Paginate the filtered results.
        $total = count( $filtered_redirects );
        $total_pages = ceil( $total / $per_page );
        $offset = ($page - 1) * $per_page;
        $paginated = array_slice(
            $filtered_redirects,
            $offset,
            $per_page,
            true
        );
        // Format the data for the response.
        $formatted = array();
        foreach ( $paginated as $source_url => $redirect_data ) {
            $formatted[] = array(
                'source_url' => '/' . $source_url,
                'found_in'   => $posts_by_url[$source_url],
                'type'       => ( isset( $redirect_data['type'] ) ? $redirect_data['type'] : '301' ),
            );
        }
        return new \WP_REST_Response(array(
            'success'  => true,
            'data'     => $formatted,
            'total'    => $total,
            'pages'    => $total_pages,
            'page'     => $page,
            'per_page' => $per_page,
        ), 200);
    }

    /**
     * Get available post types for scanning.
     *
     * @return \WP_REST_Response|\WP_Error
     * @since 1.0.0
     */
    public function get_available_post_types() {
        $public_post_types = get_post_types( array(
            'public' => true,
        ), 'objects' );
        $excluded = array('attachment', 'e-floating-buttons', 'elementor_library');
        $available_types = array();
        foreach ( $public_post_types as $post_type_slug => $post_type_obj ) {
            if ( in_array( $post_type_slug, $excluded, true ) ) {
                continue;
            }
            $available_types[] = array(
                'label' => $post_type_obj->label,
                'value' => $post_type_slug,
                'name'  => $post_type_obj->name,
            );
        }
        return new \WP_REST_Response(array(
            'success' => true,
            'data'    => $available_types,
        ), 200);
    }

    /**
     * Get chain redirects.
     *
     * Returns redirect chains detected in the redirect rules.
     *
     * @param \WP_REST_Request $request The REST request object.
     * @return \WP_REST_Response|\WP_Error
     * @since 1.0.0
     */
    public function get_chain_redirects( \WP_REST_Request $request ) {
        $min_chain_length = $request->get_param( 'min_chain_length' );
        $page = $request->get_param( 'page' );
        $per_page = $request->get_param( 'per_page' );
        // Get chain redirects using the processor.
        $chains = Redirects_Processor::detect_redirect_chains( $min_chain_length );
        if ( empty( $chains ) ) {
            return new \WP_REST_Response(array(
                'success'  => true,
                'data'     => array(),
                'total'    => 0,
                'pages'    => 0,
                'page'     => $page,
                'per_page' => $per_page,
                'message'  => __( 'No redirect chains found.', 'redirect-cleanup' ),
            ), 200);
        }
        // Format the data for the response.
        $formatted = array();
        foreach ( $chains as $source_url => $chain_data ) {
            $formatted[] = array(
                'source_url' => $source_url,
                'chain'      => $chain_data['chain'],
                'length'     => $chain_data['length'],
                'loop'       => $chain_data['loop'],
            );
        }
        // Paginate the results.
        $total = count( $formatted );
        $total_pages = ceil( $total / $per_page );
        $offset = ($page - 1) * $per_page;
        $paginated = array_slice( $formatted, $offset, $per_page );
        return new \WP_REST_Response(array(
            'success'  => true,
            'data'     => $paginated,
            'total'    => $total,
            'pages'    => $total_pages,
            'page'     => $page,
            'per_page' => $per_page,
            'message'  => sprintf( 
                // translators: %d is the number of redirect chains found.
                _n(
                    'Found %d redirect chain.',
                    'Found %d redirect chains.',
                    $total,
                    'redirect-cleanup'
                ),
                $total
             ),
        ), 200);
    }

    /**
     * Get statistics about user status.
     *
     * @return \WP_REST_Response|\WP_Error
     * @since 1.0.0
     */
    public function get_stats() {
        return new \WP_REST_Response(array(
            'success'       => true,
            'is_not_paying' => redicl_fs()->is_not_paying(),
            'upgrade_url'   => redicl_fs()->get_upgrade_url(),
        ), 200);
    }

}
