<?php
declare(strict_types=1);

namespace Help4BuilderSuite\Modules\Search;

use Help4BuilderSuite\Contracts\ModuleContract;
use Help4BuilderSuite\Modules\Commerce\ProductRepository;
use WP_Query;
use WP_REST_Request;
use WP_REST_Response;

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

final class Module implements ModuleContract
{
    private ProductRepository $products;

    public function __construct()
    {
        $this->products = new ProductRepository();
    }

    public function key(): string
    {
        return 'search';
    }

    public function boot(): void
    {
        add_action('rest_api_init', [$this, 'registerRestRoutes']);
        add_shortcode('h4_search', [$this, 'renderSearchShortcode']);
    }

    public function registerRestRoutes(): void
    {
        register_rest_route(
            'h4bs/v1',
            '/search',
            [
                'methods'             => 'GET',
                'callback'            => [$this, 'search'],
                'permission_callback' => '__return_true',
            ]
        );
    }

    public function search(WP_REST_Request $request): WP_REST_Response
    {
        $query = sanitize_text_field((string) $request->get_param('q'));
        $type  = sanitize_key((string) $request->get_param('type'));
        $limit = max(1, min(50, (int) $request->get_param('limit')));

        if ($type === '') {
            $type = 'all';
        }

        $results = [
            'query'    => $query,
            'type'     => $type,
            'pages'    => [],
            'posts'    => [],
            'products' => [],
        ];

        if ($type === 'pages' || $type === 'all') {
            $exclude = array_filter(array_map('absint', explode(',', (string) $request->get_param('exclude_pages'))));
            $loop = new WP_Query(
                [
                    'post_type'      => 'page',
                    's'              => $query,
                    'posts_per_page' => $limit + count($exclude),
                    'post_status'    => 'publish',
                ]
            );

            foreach ($loop->posts as $post) {
                if (in_array((int) $post->ID, $exclude, true)) {
                    continue;
                }

                $results['pages'][] = [
                    'id'      => $post->ID,
                    'title'   => $post->post_title,
                    'type'    => $post->post_type,
                    'url'     => get_permalink($post->ID),
                    'excerpt' => wp_trim_words(wp_strip_all_tags($post->post_excerpt ?: $post->post_content), 22),
                ];
                if (count($results['pages']) >= $limit) {
                    break;
                }
            }
        }

        if ($type === 'posts' || $type === 'all') {
            $exclude = array_filter(array_map('absint', explode(',', (string) $request->get_param('exclude_posts'))));

            $loop = new WP_Query(
                [
                    'post_type'      => 'post',
                    's'              => $query,
                    'posts_per_page' => $limit + count($exclude),
                    'post_status'    => 'publish',
                ]
            );

            foreach ($loop->posts as $post) {
                if (in_array((int) $post->ID, $exclude, true)) {
                    continue;
                }

                $results['posts'][] = [
                    'id'      => $post->ID,
                    'title'   => $post->post_title,
                    'type'    => $post->post_type,
                    'url'     => get_permalink($post->ID),
                    'excerpt' => wp_trim_words(wp_strip_all_tags($post->post_excerpt ?: $post->post_content), 22),
                ];
                if (count($results['posts']) >= $limit) {
                    break;
                }
            }
        }

        if ($type === 'products' || $type === 'all') {
            $exclude = array_filter(array_map('absint', explode(',', (string) $request->get_param('exclude_products'))));
            $products = $this->products->list(
                [
                    'search' => $query,
                    'status' => 'active',
                    'limit'  => $limit,
                ]
            );

            foreach ($products as $product) {
                if (in_array((int) ($product['id'] ?? 0), $exclude, true)) {
                    continue;
                }
                $results['products'][] = [
                    'id'       => (int) ($product['id'] ?? 0),
                    'name'     => (string) ($product['name'] ?? ''),
                    'sku'      => (string) ($product['sku'] ?? ''),
                    'slug'     => (string) ($product['slug'] ?? ''),
                    'price'    => (float) ($product['price'] ?? 0),
                    'currency' => (string) ($product['currency'] ?? 'USD'),
                ];
            }
        }

        return new WP_REST_Response($results);
    }

    /**
     * @param array<string, mixed> $atts
     */
    public function renderSearchShortcode(array $atts): string
    {
        $atts = shortcode_atts(
            [
                'type'             => 'all',
                'placeholder'      => 'Search posts and products...',
                'exclude_posts'    => '',
                'exclude_pages'    => '',
                'exclude_products' => '',
                'google_fallback'  => '0',
                'google_site'      => home_url('/'),
                'google_extra'     => '',
                'show_scope'       => '1',
            ],
            $atts,
            'h4_search'
        );

        $type = sanitize_key((string) $atts['type']);
        if (! in_array($type, ['all', 'products', 'posts', 'pages', 'google'], true)) {
            $type = 'all';
        }

        $showScope = ! in_array((string) $atts['show_scope'], ['0', 'false', 'no', 'off'], true);
        $googleFallback = ! in_array((string) $atts['google_fallback'], ['0', 'false', 'no', 'off'], true);

        ob_start();
        ?>
        <form
            class="h4bs-search-form"
            data-h4-search
            data-type="<?php echo esc_attr($type); ?>"
            data-exclude-posts="<?php echo esc_attr((string) $atts['exclude_posts']); ?>"
            data-exclude-pages="<?php echo esc_attr((string) $atts['exclude_pages']); ?>"
            data-exclude-products="<?php echo esc_attr((string) $atts['exclude_products']); ?>"
            data-google-fallback="<?php echo $googleFallback ? '1' : '0'; ?>"
            data-google-site="<?php echo esc_attr((string) $atts['google_site']); ?>"
            data-google-extra="<?php echo esc_attr((string) $atts['google_extra']); ?>"
        >
            <label class="screen-reader-text" for="h4bs-search-input"><?php esc_html_e('Search', 'help4-builder-suite'); ?></label>
            <input
                id="h4bs-search-input"
                type="search"
                name="q"
                placeholder="<?php echo esc_attr((string) $atts['placeholder']); ?>"
                required
            >
            <?php if ($showScope) : ?>
                <label class="screen-reader-text" for="h4bs-search-type"><?php esc_html_e('Scope', 'help4-builder-suite'); ?></label>
                <select id="h4bs-search-type" name="type">
                    <option value="all" <?php selected($type, 'all'); ?>><?php esc_html_e('All', 'help4-builder-suite'); ?></option>
                    <option value="products" <?php selected($type, 'products'); ?>><?php esc_html_e('Products', 'help4-builder-suite'); ?></option>
                    <option value="pages" <?php selected($type, 'pages'); ?>><?php esc_html_e('Pages', 'help4-builder-suite'); ?></option>
                    <option value="posts" <?php selected($type, 'posts'); ?>><?php esc_html_e('Posts', 'help4-builder-suite'); ?></option>
                    <option value="google" <?php selected($type, 'google'); ?>><?php esc_html_e('Google', 'help4-builder-suite'); ?></option>
                </select>
            <?php endif; ?>
            <button type="submit"><?php esc_html_e('Search', 'help4-builder-suite'); ?></button>
            <div class="h4bs-search-results" data-h4-search-results></div>
        </form>
        <?php
        return (string) ob_get_clean();
    }
}
