<?php
/**
 * ReviewsModule — bootstrapper for Module 11: Product Reviews.
 *
 * Registers:
 *   - [titancart_reviews] shortcode rendered below a product (or standalone)
 *   - "Write a Review" form shortcode [titancart_review_form]
 *   - REST routes via ReviewController
 *   - Frontend script (reviews.js) + inline settings object
 *   - titancart_product_single_after hook to auto-append reviews to product pages
 *
 * @package TitanCart\Modules\Reviews
 */

namespace TitanCart\Modules\Reviews;

use TitanCart\Storefront\TemplateLoader;
use TitanCart\Modules\Accounts\AccountManager;
use TitanCart\REST\Reviews\ReviewController;
use TitanCart\REST\Extensions\ExtensionsController;

defined( 'ABSPATH' ) || exit;

class ReviewsModule {

    private static ReviewManager $manager;

    public static function init(): void {
        // Extension guard — skip module if "reviews" extension is disabled.
        if ( ! ExtensionsController::is_active( 'reviews' ) ) {
            return;
        }

        $instance      = new self();
        self::$manager = new ReviewManager();

        // Shortcodes.
        add_shortcode( 'titancart_reviews',     [ $instance, 'render_reviews' ] );
        add_shortcode( 'titancart_review_form', [ $instance, 'render_review_form' ] );

        // Auto-inject below the product detail on single product pages.
        add_action( 'titancart_product_single_after', [ $instance, 'inject_reviews' ], 20 );

        // Enqueue frontend script.
        add_action( 'wp_enqueue_scripts', [ $instance, 'enqueue_scripts' ] );

        // REST routes.
        add_action( 'rest_api_init', [ $instance, 'register_routes' ] );
    }

    // ══════════════════════════════════════════════════════════════════════════
    // SHORTCODES
    // ══════════════════════════════════════════════════════════════════════════

    /**
     * [titancart_reviews product_id="42" per_page="10" sort="newest"]
     *
     * Renders the paginated review list with rating summary bar.
     *
     * @param  array $atts  Shortcode attributes.
     * @return string
     */
    public function render_reviews( array $atts = [] ): string {
        $default_epp = \TitanCart\Services\SettingsService::int( 'appearance', 'elements_per_page', 10 );
        $atts = shortcode_atts(
            [
                'product_id' => 0,
                'per_page'   => $default_epp,
                'sort'       => 'newest',
            ],
            $atts,
            'titancart_reviews'
        );

        $product_id = (int) ( $atts['product_id'] ?: get_query_var( 'tc_product_id', 0 ) );
        if ( ! $product_id ) {
            return '';
        }

        ob_start();
        $page   = max( 1, absint( wp_unslash( $_GET['reviews_page'] ?? 1 ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- idempotent GET view-state (pagination), see reviewer notes §6.
        $sort   = in_array( $atts['sort'], [ 'newest', 'oldest', 'highest', 'lowest', 'helpful' ], true )
                    ? $atts['sort']
                    : 'newest';

        $result = self::$manager->get_reviews( $product_id, $page, (int) $atts['per_page'], $sort );
        $stats  = self::$manager->get_review_stats( $product_id );

        TemplateLoader::get( 'product/reviews.php', [
            'product_id'   => $product_id,
            'reviews'      => $result['reviews'],
            'total'        => $result['total'],
            'total_pages'  => $result['pages'],
            'current_page' => $page,
            'stats'        => $stats,
            'sort'         => $sort,
        ] );

        return (string) ob_get_clean();
    }

    /**
     * [titancart_review_form product_id="42"]
     *
     * Renders the star-picker review submission form.
     *
     * @param  array $atts
     * @return string
     */
    public function render_review_form( array $atts = [] ): string {
        $atts = shortcode_atts(
            [ 'product_id' => 0 ],
            $atts,
            'titancart_review_form'
        );

        $product_id = (int) ( $atts['product_id'] ?: get_query_var( 'tc_product_id', 0 ) );
        if ( ! $product_id ) {
            return '';
        }

        ob_start();

        $accounts    = new AccountManager();
        $customer    = $accounts->get_current_customer();
        $customer_id = $customer ? (int) $customer['id'] : null;
        $ip          = titancart_client_ip(); // WP.org R1 🅱2: validated capture (was sanitize_text_field, which is not IP validation).

        $can_review = self::$manager->can_review( $product_id, $customer_id, $ip );

        TemplateLoader::get( 'product/review-form.php', [
            'product_id'  => $product_id,
            'customer_id' => $customer_id,
            'can_review'  => $can_review,
            'is_logged_in' => is_user_logged_in(),
        ] );

        return (string) ob_get_clean();
    }

    /**
     * Auto-inject reviews section after the product single template.
     *
     * Hooked on 'titancart_product_single_after' with priority 20.
     * The product template fires this action and passes the product_id.
     *
     * @param  int $product_id
     * @return void
     */
    public function inject_reviews( int $product_id ): void {
        // WP.org R2 item 6: real kses at echo. The shortcodes render markup
        // only (reviews JS moved to enqueued handles in the R1 sweep), so the
        // post-content allowlist extended with form controls + the star SVGs
        // covers the full output without stripping anything.
        $common  = [ 'id' => true, 'class' => true, 'style' => true, 'data-*' => true, 'aria-hidden' => true, 'aria-label' => true, 'role' => true ];
        $allowed = wp_kses_allowed_html( 'post' );
        $allowed['form']     = $common + [ 'action' => true, 'method' => true, 'novalidate' => true ];
        $allowed['input']    = $common + [ 'type' => true, 'name' => true, 'value' => true, 'placeholder' => true, 'required' => true, 'checked' => true, 'readonly' => true, 'disabled' => true, 'maxlength' => true, 'min' => true, 'max' => true, 'step' => true, 'autocomplete' => true ];
        $allowed['textarea'] = $common + [ 'name' => true, 'rows' => true, 'cols' => true, 'placeholder' => true, 'required' => true, 'maxlength' => true ];
        $allowed['select']   = $common + [ 'name' => true, 'required' => true, 'disabled' => true ];
        $allowed['option']   = $common + [ 'value' => true, 'selected' => true, 'disabled' => true ];
        $allowed['button']   = $common + [ 'type' => true, 'name' => true, 'value' => true, 'disabled' => true ];
        $allowed['label']    = $common + [ 'for' => true ];
        $allowed['fieldset'] = $common;
        $allowed['legend']   = $common;
        $allowed['svg']      = [ 'width' => true, 'height' => true, 'viewbox' => true, 'fill' => true, 'xmlns' => true, 'class' => true, 'aria-hidden' => true ];
        $allowed['path']     = [ 'd' => true, 'fill' => true ];

        echo wp_kses( do_shortcode( '[titancart_reviews product_id="' . (int) $product_id . '"]' ), $allowed );
        echo wp_kses( do_shortcode( '[titancart_review_form product_id="' . (int) $product_id . '"]' ), $allowed );
    }

    // ══════════════════════════════════════════════════════════════════════════
    // SCRIPTS
    // ══════════════════════════════════════════════════════════════════════════

    /**
     * Enqueue reviews.js on any storefront page.
     *
     * Only the JS is loaded — CSS is expected to come from the active
     * TitanCart theme or the site's stylesheet. The localized object
     * 'titancartReviews' exposes REST endpoints, the nonce, and translated strings.
     */
    public function enqueue_scripts(): void {
        if ( is_admin() ) {
            return;
        }

        wp_enqueue_script(
            'titancart-reviews',
            TITANCART_ASSETS_URL . 'js/reviews.js',
            [],
            TITANCART_VERSION,
            true
        );

        $accounts    = new AccountManager();
        $customer    = $accounts->get_current_customer();
        $customer_id = $customer ? (int) $customer['id'] : 0;

        wp_localize_script( 'titancart-reviews', 'titancartReviews', [
            'restBase'   => esc_url_raw( rest_url( 'titancart/v1' ) ),
            'nonce'      => wp_create_nonce( 'wp_rest' ),
            'customerId' => $customer_id,
            'isLoggedIn' => is_user_logged_in(),
            'loginUrl'   => titancart_login_url(),
            // Mirror the server-side reviews_auto_approve setting so reviews.js
            // can pick the right success message ("Thank you" vs "Awaiting
            // moderation") after a successful submission. Default false matches
            // ReviewManager::create()'s default — reviews go to pending unless
            // an admin enables auto-approve in Settings → Reviews.
            'autoApprove' => \TitanCart\Services\SettingsService::bool( 'reviews', 'reviews_auto_approve', false ),
            'recaptcha'  => \TitanCart\Extensions\RecaptchaExtension::client_config( 'review' ),
            'i18n'       => [
                'submitting'       => __( 'Submitting…',                        'titancart-lite' ),
                'submitted'        => __( 'Thank you for your review!',          'titancart-lite' ),
                'pendingNote'      => __( 'Your review is awaiting moderation.', 'titancart-lite' ),
                'errorGeneric'     => __( 'Something went wrong. Please try again.', 'titancart-lite' ),
                'recaptcha'        => __( 'Please complete the reCAPTCHA.',          'titancart-lite' ),
                'loginRequired'    => __( 'Please log in to leave a review.',    'titancart-lite' ),
                'alreadyVoted'     => __( 'You have already voted on this review.', 'titancart-lite' ),
                'voteRecorded'     => __( 'Thanks for your feedback!',           'titancart-lite' ),
                'selectRating'     => __( 'Please select a star rating.',        'titancart-lite' ),
                'writeReview'      => __( 'Please write your review.',           'titancart-lite' ),
                'stars'            => [
                    1 => __( 'Poor',      'titancart-lite' ),
                    2 => __( 'Fair',      'titancart-lite' ),
                    3 => __( 'Average',   'titancart-lite' ),
                    4 => __( 'Good',      'titancart-lite' ),
                    5 => __( 'Excellent', 'titancart-lite' ),
                ],
            ],
        ] );
    }

    // ══════════════════════════════════════════════════════════════════════════
    // REST ROUTES
    // ══════════════════════════════════════════════════════════════════════════

    public function register_routes(): void {
        ( new ReviewController() )->register_routes();
    }
}
