<?php
declare(strict_types=1);

namespace Help4BuilderSuite\Modules\Commerce;

use Help4BuilderSuite\Support\AdminRequest;
use WP_REST_Request;
use WP_REST_Response;

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

final class ProductReviewsAddon
{
    private ProductRepository $products;
    private ProductReviewRepository $reviews;

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

    public function boot(): void
    {
        add_action('admin_menu', [$this, 'registerAdminPage']);
        add_action('admin_init', [$this, 'handleAdminActions']);
        add_action('admin_post_h4bs_submit_product_review', [$this, 'handleFrontendReviewSubmit']);
        add_action('admin_post_nopriv_h4bs_submit_product_review', [$this, 'handleFrontendReviewSubmit']);
        add_action('rest_api_init', [$this, 'registerRestRoutes']);
        add_shortcode('h4_product_reviews', [$this, 'renderProductReviewsShortcode']);
    }

    public function registerAdminPage(): void
    {
        add_submenu_page(
            'h4bs-commerce',
            __('Product Reviews', 'help4-builder-suite'),
            __('Reviews', 'help4-builder-suite'),
            'manage_options',
            'h4bs-commerce-reviews',
            [$this, 'renderAdminPage']
        );
    }

    public function handleAdminActions(): void
    {
        if (! is_admin() || ! current_user_can('manage_options')) {
            return;
        }

        $action = AdminRequest::queryKey('h4bs_review_action');
        if ($action === '') {
            return;
        }

        $reviewId = AdminRequest::queryAbsInt('review_id');
        if ($reviewId <= 0) {
            $this->redirectAdmin(['h4bs_notice' => 'review_invalid']);
        }
        check_admin_referer('h4bs_review_action_' . $reviewId);

        if ($action === 'approve') {
            $this->reviews->setStatus($reviewId, 'approved');
            $this->redirectAdmin(['h4bs_notice' => 'review_approved']);
        }
        if ($action === 'reject') {
            $this->reviews->setStatus($reviewId, 'rejected');
            $this->redirectAdmin(['h4bs_notice' => 'review_rejected']);
        }
        if ($action === 'delete') {
            $this->reviews->delete($reviewId);
            $this->redirectAdmin(['h4bs_notice' => 'review_deleted']);
        }
    }

    public function renderAdminPage(): void
    {
        if (! current_user_can('manage_options')) {
            return;
        }

        $status = AdminRequest::queryKey('status', 'all');
        if (! in_array($status, ['all', 'pending', 'approved', 'rejected', 'spam'], true)) {
            $status = 'all';
        }
        $rows = $this->reviews->listAll($status, 200, 0);

        ?>
        <div class="wrap h4bs-admin-wrap">
            <h1><?php esc_html_e('Commerce Product Reviews', 'help4-builder-suite'); ?></h1>
            <p><?php esc_html_e('Only verified customers can submit reviews. New reviews are moderated here.', 'help4-builder-suite'); ?></p>
            <p>
                <a class="button <?php echo $status === 'all' ? 'button-primary' : ''; ?>" href="<?php echo esc_url(admin_url('admin.php?page=h4bs-commerce-reviews&status=all')); ?>"><?php esc_html_e('All', 'help4-builder-suite'); ?></a>
                <a class="button <?php echo $status === 'pending' ? 'button-primary' : ''; ?>" href="<?php echo esc_url(admin_url('admin.php?page=h4bs-commerce-reviews&status=pending')); ?>"><?php esc_html_e('Pending', 'help4-builder-suite'); ?></a>
                <a class="button <?php echo $status === 'approved' ? 'button-primary' : ''; ?>" href="<?php echo esc_url(admin_url('admin.php?page=h4bs-commerce-reviews&status=approved')); ?>"><?php esc_html_e('Approved', 'help4-builder-suite'); ?></a>
                <a class="button <?php echo $status === 'rejected' ? 'button-primary' : ''; ?>" href="<?php echo esc_url(admin_url('admin.php?page=h4bs-commerce-reviews&status=rejected')); ?>"><?php esc_html_e('Rejected', 'help4-builder-suite'); ?></a>
            </p>
            <?php $this->renderAdminNotice(); ?>
            <table class="widefat striped">
                <thead>
                    <tr>
                        <th><?php esc_html_e('ID', 'help4-builder-suite'); ?></th>
                        <th><?php esc_html_e('Product', 'help4-builder-suite'); ?></th>
                        <th><?php esc_html_e('Customer', 'help4-builder-suite'); ?></th>
                        <th><?php esc_html_e('Rating', 'help4-builder-suite'); ?></th>
                        <th><?php esc_html_e('Review', 'help4-builder-suite'); ?></th>
                        <th><?php esc_html_e('Status', 'help4-builder-suite'); ?></th>
                        <th><?php esc_html_e('Verified', 'help4-builder-suite'); ?></th>
                        <th><?php esc_html_e('Actions', 'help4-builder-suite'); ?></th>
                    </tr>
                </thead>
                <tbody>
                    <?php if (! $rows) : ?>
                        <tr>
                            <td colspan="8"><?php esc_html_e('No reviews found.', 'help4-builder-suite'); ?></td>
                        </tr>
                    <?php endif; ?>
                    <?php foreach ($rows as $row) : ?>
                        <?php
                        $reviewId = absint($row['id'] ?? 0);
                        $productId = absint($row['product_id'] ?? 0);
                        $product = $productId > 0 ? $this->products->get($productId) : null;
                        $productName = is_array($product) ? (string) ($product['name'] ?? '') : '';
                        $approveUrl = wp_nonce_url(
                            add_query_arg(
                                [
                                    'page' => 'h4bs-commerce-reviews',
                                    'h4bs_review_action' => 'approve',
                                    'review_id' => $reviewId,
                                ],
                                admin_url('admin.php')
                            ),
                            'h4bs_review_action_' . $reviewId
                        );
                        $rejectUrl = wp_nonce_url(
                            add_query_arg(
                                [
                                    'page' => 'h4bs-commerce-reviews',
                                    'h4bs_review_action' => 'reject',
                                    'review_id' => $reviewId,
                                ],
                                admin_url('admin.php')
                            ),
                            'h4bs_review_action_' . $reviewId
                        );
                        $deleteUrl = wp_nonce_url(
                            add_query_arg(
                                [
                                    'page' => 'h4bs-commerce-reviews',
                                    'h4bs_review_action' => 'delete',
                                    'review_id' => $reviewId,
                                ],
                                admin_url('admin.php')
                            ),
                            'h4bs_review_action_' . $reviewId
                        );
                        ?>
                        <tr>
                            <td><?php echo esc_html((string) $reviewId); ?></td>
                            <td>
                                <?php echo esc_html($productName !== '' ? $productName : ('#' . $productId)); ?>
                                <br><small><?php echo esc_html('ID ' . $productId); ?></small>
                            </td>
                            <td>
                                <?php echo esc_html((string) ($row['customer_email'] ?? '')); ?>
                                <?php if (! empty($row['customer_user_id'])) : ?>
                                    <br><small><?php echo esc_html('User #' . absint($row['customer_user_id'])); ?></small>
                                <?php endif; ?>
                            </td>
                            <td><?php echo esc_html(str_repeat('★', max(1, min(5, absint($row['rating'] ?? 5))))); ?></td>
                            <td>
                                <strong><?php echo esc_html((string) ($row['title'] ?? '')); ?></strong>
                                <p style="margin:.35rem 0 0;"><?php echo esc_html((string) ($row['review_text'] ?? '')); ?></p>
                            </td>
                            <td><?php echo esc_html((string) ($row['status'] ?? 'pending')); ?></td>
                            <td><?php echo ! empty($row['verified_purchase']) ? esc_html__('Yes', 'help4-builder-suite') : esc_html__('No', 'help4-builder-suite'); ?></td>
                            <td>
                                <a class="button button-small" href="<?php echo esc_url($approveUrl); ?>"><?php esc_html_e('Approve', 'help4-builder-suite'); ?></a>
                                <a class="button button-small" href="<?php echo esc_url($rejectUrl); ?>"><?php esc_html_e('Reject', 'help4-builder-suite'); ?></a>
                                <a class="button button-small" href="<?php echo esc_url($deleteUrl); ?>" onclick="return confirm('<?php echo esc_js(__('Delete this review?', 'help4-builder-suite')); ?>');"><?php esc_html_e('Delete', 'help4-builder-suite'); ?></a>
                            </td>
                        </tr>
                    <?php endforeach; ?>
                </tbody>
            </table>
        </div>
        <?php
    }

    public function registerRestRoutes(): void
    {
        register_rest_route(
            'h4bs/v1',
            '/products/(?P<id>\d+)/reviews',
            [
                [
                    'methods' => 'GET',
                    'callback' => [$this, 'listProductReviews'],
                    'permission_callback' => '__return_true',
                ],
                [
                    'methods' => 'POST',
                    'callback' => [$this, 'submitReviewRest'],
                    'permission_callback' => static fn (): bool => is_user_logged_in(),
                ],
            ]
        );
    }

    public function listProductReviews(WP_REST_Request $request): WP_REST_Response
    {
        $productId = absint($request->get_param('id'));
        $limit = max(1, min(50, (int) $request->get_param('limit')));
        $offset = max(0, (int) $request->get_param('offset'));
        $rows = $this->reviews->listForProduct($productId, 'approved', $limit, $offset);
        $summary = $this->reviews->getSummaryForProduct($productId, 'approved');

        return new WP_REST_Response(
            [
                'product_id' => $productId,
                'summary' => $summary,
                'items' => array_map([$this, 'formatReviewForPublic'], $rows),
            ]
        );
    }

    public function submitReviewRest(WP_REST_Request $request): WP_REST_Response
    {
        $user = wp_get_current_user();
        $userId = absint($user->ID ?? 0);
        $email = sanitize_email((string) ($user->user_email ?? ''));
        if ($userId <= 0 || $email === '') {
            return new WP_REST_Response(['message' => 'Login required'], 401);
        }

        $productId = absint($request->get_param('id'));
        $reviewText = sanitize_textarea_field((string) $request->get_param('review_text'));
        $title = sanitize_text_field((string) $request->get_param('title'));
        $rating = max(1, min(5, (int) $request->get_param('rating')));
        if ($productId <= 0 || $reviewText === '') {
            return new WP_REST_Response(['message' => 'Missing product or review text'], 422);
        }

        $verification = $this->reviews->verifyPurchaseForCustomer($productId, $userId, $email);
        if (! $verification['verified']) {
            return new WP_REST_Response(['message' => 'Only verified customers can review this product'], 403);
        }

        if ($this->reviews->hasExistingReviewForOrderProduct($verification['order_id'], $productId, $userId, $email)) {
            return new WP_REST_Response(['message' => 'Review already submitted for this purchase'], 409);
        }

        $reviewId = $this->reviews->create(
            [
                'product_id' => $productId,
                'order_id' => $verification['order_id'],
                'customer_user_id' => $userId,
                'customer_email' => $email,
                'rating' => $rating,
                'title' => $title,
                'review_text' => $reviewText,
                'status' => 'pending',
                'verified_purchase' => true,
                'payload' => [
                    'source' => 'rest',
                ],
            ]
        );

        if ($reviewId <= 0) {
            return new WP_REST_Response(['message' => 'Unable to save review'], 500);
        }

        return new WP_REST_Response(
            [
                'ok' => true,
                'message' => 'Review submitted and awaiting moderation',
                'review_id' => $reviewId,
                'status' => 'pending',
            ],
            201
        );
    }

    public function handleFrontendReviewSubmit(): void
    {
        if (! is_user_logged_in()) {
            $this->redirectToRefererWithQuery('h4_review', 'login_required');
        }

        check_admin_referer('h4bs_submit_product_review', 'h4bs_submit_product_review_nonce');
        $post = wp_unslash($_POST);
        $productId = absint($post['product_id'] ?? 0);
        $title = sanitize_text_field((string) ($post['title'] ?? ''));
        $reviewText = sanitize_textarea_field((string) ($post['review_text'] ?? ''));
        $rating = max(1, min(5, (int) ($post['rating'] ?? 5)));
        if ($productId <= 0 || $reviewText === '') {
            $this->redirectToRefererWithQuery('h4_review', 'invalid');
        }

        $user = wp_get_current_user();
        $userId = absint($user->ID ?? 0);
        $email = sanitize_email((string) ($user->user_email ?? ''));
        $verification = $this->reviews->verifyPurchaseForCustomer($productId, $userId, $email);
        if (! $verification['verified']) {
            $this->redirectToRefererWithQuery('h4_review', 'not_verified');
        }

        if ($this->reviews->hasExistingReviewForOrderProduct($verification['order_id'], $productId, $userId, $email)) {
            $this->redirectToRefererWithQuery('h4_review', 'exists');
        }

        $reviewId = $this->reviews->create(
            [
                'product_id' => $productId,
                'order_id' => $verification['order_id'],
                'customer_user_id' => $userId,
                'customer_email' => $email,
                'rating' => $rating,
                'title' => $title,
                'review_text' => $reviewText,
                'status' => 'pending',
                'verified_purchase' => true,
                'payload' => [
                    'source' => 'shortcode_form',
                ],
            ]
        );

        if ($reviewId <= 0) {
            $this->redirectToRefererWithQuery('h4_review', 'error');
        }

        $this->redirectToRefererWithQuery('h4_review', 'submitted');
    }

    /**
     * @param array<string, string> $atts
     */
    public function renderProductReviewsShortcode(array $atts): string
    {
        $atts = shortcode_atts(
            [
                'product_id' => '0',
                'limit' => '5',
                'show_form' => '1',
                'show_summary' => '1',
                'title' => '',
                'empty_text' => '',
            ],
            $atts,
            'h4_product_reviews'
        );

        $productId = absint($atts['product_id'] ?? 0);
        $limit = max(1, min(20, (int) ($atts['limit'] ?? 5)));
        $showSummary = rest_sanitize_boolean($atts['show_summary'] ?? '1');
        $title = sanitize_text_field((string) ($atts['title'] ?? ''));
        $emptyText = sanitize_text_field((string) ($atts['empty_text'] ?? ''));
        if ($emptyText === '') {
            $emptyText = __('No reviews yet.', 'help4-builder-suite');
        }
        if ($productId <= 0) {
            return '<div class="h4-reviews-empty">' . esc_html($emptyText) . '</div>';
        }

        $summary = $this->reviews->getSummaryForProduct($productId, 'approved');
        $rows = $this->reviews->listForProduct($productId, 'approved', $limit, 0);

        ob_start();
        ?>
        <div class="h4-product-reviews">
            <?php if ($title !== '') : ?>
                <h3 class="h4-product-reviews-title" style="margin:0 0 .75rem;"><?php echo esc_html($title); ?></h3>
            <?php endif; ?>
            <?php if ($showSummary) : ?>
                <div class="h4-product-reviews-summary">
                    <strong><?php echo esc_html(number_format_i18n((float) ($summary['average'] ?? 0), 1)); ?>/5</strong>
                    <?php /* translators: %d: Review count. */ ?>
                    <span><?php echo esc_html(sprintf(_n('%d review', '%d reviews', (int) ($summary['count'] ?? 0), 'help4-builder-suite'), (int) ($summary['count'] ?? 0))); ?></span>
                </div>
            <?php endif; ?>
            <div class="h4-product-reviews-list">
                <?php if (! $rows) : ?>
                    <p><?php echo esc_html($emptyText); ?></p>
                <?php endif; ?>
                <?php foreach ($rows as $row) : ?>
                    <article class="h4-product-review-card" style="border:1px solid #dbe7e6;border-radius:12px;padding:1rem;margin-bottom:.85rem;">
                        <header style="display:flex;justify-content:space-between;gap:1rem;">
                            <strong><?php echo esc_html((string) ($row['title'] ?? __('Verified customer review', 'help4-builder-suite'))); ?></strong>
                            <span aria-label="<?php esc_attr_e('Rating', 'help4-builder-suite'); ?>"><?php echo esc_html(str_repeat('★', max(1, min(5, absint($row['rating'] ?? 5))))); ?></span>
                        </header>
                        <p style="margin:.6rem 0;"><?php echo esc_html((string) ($row['review_text'] ?? '')); ?></p>
                        <footer style="font-size:12px;opacity:.72;">
                            <?php echo esc_html($this->maskEmail((string) ($row['customer_email'] ?? ''))); ?>
                            <?php if (! empty($row['verified_purchase'])) : ?>
                                · <?php esc_html_e('Verified Purchase', 'help4-builder-suite'); ?>
                            <?php endif; ?>
                        </footer>
                    </article>
                <?php endforeach; ?>
            </div>
            <?php if (rest_sanitize_boolean($atts['show_form'] ?? '1')) : ?>
                <?php echo $this->renderShortcodeReviewForm($productId); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
            <?php endif; ?>
        </div>
        <?php
        return (string) ob_get_clean();
    }

    private function renderShortcodeReviewForm(int $productId): string
    {
        if (! is_user_logged_in()) {
            return '<p><em>' . esc_html__('Log in to leave a verified review.', 'help4-builder-suite') . '</em></p>';
        }
        $user = wp_get_current_user();
        $email = sanitize_email((string) ($user->user_email ?? ''));
        $verification = $this->reviews->verifyPurchaseForCustomer($productId, get_current_user_id(), $email);
        if (! $verification['verified']) {
            return '<p><em>' . esc_html__('Only verified customers can review this product.', 'help4-builder-suite') . '</em></p>';
        }

        ob_start();
        ?>
        <form method="post" action="<?php echo esc_url(admin_url('admin-post.php')); ?>" class="h4-product-review-form" style="margin-top:1rem;border:1px solid #dbe7e6;border-radius:12px;padding:1rem;">
            <h4 style="margin-top:0;"><?php esc_html_e('Leave a review', 'help4-builder-suite'); ?></h4>
            <?php $this->renderFrontendReviewNotice(); ?>
            <input type="hidden" name="action" value="h4bs_submit_product_review">
            <input type="hidden" name="product_id" value="<?php echo esc_attr((string) $productId); ?>">
            <?php wp_nonce_field('h4bs_submit_product_review', 'h4bs_submit_product_review_nonce'); ?>
            <p>
                <label><?php esc_html_e('Rating', 'help4-builder-suite'); ?></label><br>
                <select name="rating">
                    <option value="5">5 - Excellent</option>
                    <option value="4">4 - Great</option>
                    <option value="3">3 - Good</option>
                    <option value="2">2 - Fair</option>
                    <option value="1">1 - Poor</option>
                </select>
            </p>
            <p>
                <label><?php esc_html_e('Title', 'help4-builder-suite'); ?></label><br>
                <input type="text" name="title" class="regular-text" maxlength="190">
            </p>
            <p>
                <label><?php esc_html_e('Your Review', 'help4-builder-suite'); ?></label><br>
                <textarea name="review_text" rows="5" class="large-text" required></textarea>
            </p>
            <p><button type="submit" class="button button-primary"><?php esc_html_e('Submit Review', 'help4-builder-suite'); ?></button></p>
        </form>
        <?php
        return (string) ob_get_clean();
    }

    /**
     * @param array<string, mixed> $row
     * @return array<string, mixed>
     */
    private function formatReviewForPublic(array $row): array
    {
        return [
            'id' => absint($row['id'] ?? 0),
            'product_id' => absint($row['product_id'] ?? 0),
            'rating' => max(1, min(5, absint($row['rating'] ?? 5))),
            'title' => sanitize_text_field((string) ($row['title'] ?? '')),
            'review_text' => sanitize_textarea_field((string) ($row['review_text'] ?? '')),
            'customer_email_masked' => $this->maskEmail((string) ($row['customer_email'] ?? '')),
            'verified_purchase' => ! empty($row['verified_purchase']),
            'created_at' => sanitize_text_field((string) ($row['created_at'] ?? '')),
        ];
    }

    private function renderAdminNotice(): void
    {
        $notice = AdminRequest::queryKey('h4bs_notice');
        $messages = [
            'review_approved' => __('Review approved.', 'help4-builder-suite'),
            'review_rejected' => __('Review rejected.', 'help4-builder-suite'),
            'review_deleted' => __('Review deleted.', 'help4-builder-suite'),
            'review_invalid' => __('Invalid review request.', 'help4-builder-suite'),
        ];
        if ($notice === '' || ! isset($messages[$notice])) {
            return;
        }
        echo '<div class="notice notice-success is-dismissible"><p>' . esc_html($messages[$notice]) . '</p></div>';
    }

    private function renderFrontendReviewNotice(): void
    {
        $notice = AdminRequest::queryKey('h4_review');
        $messages = [
            'submitted' => __('Review submitted and pending moderation.', 'help4-builder-suite'),
            'exists' => __('You already reviewed this purchased item.', 'help4-builder-suite'),
            'not_verified' => __('Only verified customers can review this product.', 'help4-builder-suite'),
            'invalid' => __('Please complete all required review fields.', 'help4-builder-suite'),
            'error' => __('Unable to submit review right now. Try again.', 'help4-builder-suite'),
            'login_required' => __('Please log in before reviewing.', 'help4-builder-suite'),
        ];
        if ($notice === '' || ! isset($messages[$notice])) {
            return;
        }
        echo '<p style="padding:.6rem .75rem;border:1px solid #dbe7e6;border-radius:8px;background:#f8fbfa;">' . esc_html($messages[$notice]) . '</p>';
    }

    /**
     * @param array<string, string> $query
     */
    private function redirectAdmin(array $query): void
    {
        $query = array_merge(['page' => 'h4bs-commerce-reviews'], $query);
        wp_safe_redirect(add_query_arg($query, admin_url('admin.php')));
        exit;
    }

    private function redirectToRefererWithQuery(string $key, string $value): void
    {
        $referer = wp_get_referer();
        if (! is_string($referer) || $referer === '') {
            $referer = home_url('/');
        }
        $target = add_query_arg([$key => sanitize_key($value)], $referer);
        wp_safe_redirect($target);
        exit;
    }

    private function maskEmail(string $email): string
    {
        $email = sanitize_email($email);
        if ($email === '' || ! str_contains($email, '@')) {
            return '';
        }
        [$user, $domain] = explode('@', $email, 2);
        if ($user === '') {
            return '***@' . $domain;
        }
        if (strlen($user) <= 2) {
            return substr($user, 0, 1) . '*@' . $domain;
        }
        return substr($user, 0, 2) . str_repeat('*', max(1, strlen($user) - 2)) . '@' . $domain;
    }
}
