<?php
defined('ABSPATH') or die('Direct access not allowed');

/**
 * VollstartRD_Frontend — Public-facing shortcode, standalone page + AJAX.
 *
 * SRP: Renders [repair_status] shortcode and standalone page,
 * handles public AJAX lookups. No admin logic here.
 */
class VollstartRD_Frontend {

    private $MAIN;

    public function __construct($MAIN) {
        $this->MAIN = $MAIN;

        add_shortcode('vollstart_rd_status', [$this, 'renderStatusPage']);

        // Rewrite rules — must be registered on every init
        $this->addRewriteRules();

        // Flush once after rules are registered (delayed to allow WP to process)
        if (get_option('vollstart_rd_rewrite_flushed') !== 'v9') {
            add_action('wp_loaded', function () {
                flush_rewrite_rules();
                update_option('vollstart_rd_rewrite_flushed', 'v9');
            });
        }
        add_filter('query_vars', [$this, 'addQueryVars']);
        add_action('wp', [$this, 'handleStandalonePage'], 1);
        add_action('wp', [$this, 'handleRatingPage'], 1);

        // Public AJAX (logged-in and not-logged-in)
        add_action('wp_ajax_vollstart_rd_public', [$this, 'handleAjax']);
        add_action('wp_ajax_nopriv_vollstart_rd_public', [$this, 'handleAjax']);
    }

    // --- Slug + URL helpers ---

    public function getSlug(): string {
        $slug = $this->MAIN->getOptions()->getOptionValue('statusPageSlug');
        return !empty($slug) ? sanitize_title($slug) : 'vollstart-repair-desk';
    }

    /**
     * Get public status page URL for a repair.
     */
    public function getStatusUrl(array $repair): string {
        return home_url($this->getSlug() . '/' . $repair['repair_number'] . '/' . $repair['access_code']);
    }

    // --- Rewrite rules ---

    public function addRewriteRules(): void {
        $slug = $this->getSlug();

        // Order matters: last added with 'top' = highest priority
        // Generic patterns first (lower priority), specific last (highest)

        // /repair-desk/A1B2-C3D4 → access code only
        add_rewrite_rule(
            '^' . preg_quote($slug, '/') . '/([A-Za-z0-9-]+)/?$',
            'index.php?vollstart_rd_status_page=1&vollstart_rd_access_code=$matches[1]',
            'top'
        );

        // /repair-desk/REP-0001/A1B2-C3D4 → direct lookup with both
        add_rewrite_rule(
            '^' . preg_quote($slug, '/') . '/([A-Za-z0-9-]+)/([A-Za-z0-9-]+)/?$',
            'index.php?vollstart_rd_status_page=1&vollstart_rd_repair_number=$matches[1]&vollstart_rd_access_code=$matches[2]',
            'top'
        );

        // /repair-desk/rate/TOKEN → rating page
        add_rewrite_rule(
            '^' . preg_quote($slug, '/') . '/rate/([a-f0-9]{32})/?$',
            'index.php?vollstart_rd_rating_page=1&vollstart_rd_rating_token=$matches[1]',
            'top'
        );

        // /repair-desk/ → lookup form
        add_rewrite_rule(
            '^' . preg_quote($slug, '/') . '/?$',
            'index.php?vollstart_rd_status_page=1',
            'top'
        );

        // Flush once per version
    }

    public function addQueryVars(array $vars): array {
        $vars[] = 'vollstart_rd_status_page';
        $vars[] = 'vollstart_rd_repair_number';
        $vars[] = 'vollstart_rd_access_code';
        $vars[] = 'vollstart_rd_rating_page';
        $vars[] = 'vollstart_rd_rating_token';
        return apply_filters('vollstart_rd_query_vars', $vars);
    }

    /**
     * Intercept standalone page request and render full HTML page.
     */
    public function handleStandalonePage(): void {
        if (!get_query_var('vollstart_rd_status_page')) return;

        // Redirect /rate/TOKEN and /intake/TOKEN that were caught by generic rules
        $repairNumber = get_query_var('vollstart_rd_repair_number', '');
        $accessCode = get_query_var('vollstart_rd_access_code', '');

        // /rate/TOKEN → 2-segment rule caught it
        if (strtolower($repairNumber) === 'rate') {
            set_query_var('vollstart_rd_status_page', '');
            set_query_var('vollstart_rd_rating_page', '1');
            set_query_var('vollstart_rd_rating_token', $accessCode);
            $this->handleRatingPage();
            return;
        }
        // A registered extension can intercept additional 2-segment routes via this filter.
        if (apply_filters('vollstart_rd_handle_two_segment_route', false, $repairNumber, $accessCode)) {
            return;
        }

        if (!$this->MAIN->getOptions()->isCheckboxActive('statusPageEnabled')) {
            status_header(404);
            return;
        }

        $repairNumber = strtoupper(sanitize_text_field(get_query_var('vollstart_rd_repair_number', '')));
        $accessCode = strtoupper(sanitize_text_field(get_query_var('vollstart_rd_access_code', '')));

        // Enqueue assets early
        $this->enqueueAssets();

        // Pass URL params to JS for auto-lookup
        if ($accessCode) {
            wp_localize_script('vollstart-rd-frontend', 'vollstartRdAutoLookup', [
                'repairNumber' => $repairNumber,
                'accessCode'   => $accessCode,
            ]);
        }

        add_filter('template_include', function() use ($accessCode) {
            $this->outputStandalonePage($accessCode);
            exit;
        }, 999);
    }

    /**
     * Render a standalone HTML page (no theme).
     */
    private function outputStandalonePage(string $accessCode = ''): void {
        $title = $this->MAIN->getOptions()->getOptionValue('businessName') ?: __('Repair Status', 'vollstart-repair-desk');
        ?>
        <!DOCTYPE html>
        <html <?php language_attributes(); ?>>
        <head>
            <meta charset="<?php bloginfo('charset'); ?>">
            <meta name="viewport" content="width=device-width, initial-scale=1">
            <meta name="robots" content="noindex, nofollow">
            <title><?php echo esc_html($title); ?> — <?php esc_html_e('Repair Status', 'vollstart-repair-desk'); ?></title>
            <?php wp_head(); ?>
        </head>
        <body style="margin:0;padding:40px 16px;background:#f8fafc;min-height:100vh">
            <div style="max-width:520px;margin:0 auto">
                <h1 style="text-align:center;font-size:22px;color:#1e293b;margin-bottom:24px"><?php echo esc_html($title); ?></h1>
                <?php echo $this->renderStatusPage([]); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- own HTML, escaped internally ?>
            </div>
            <?php wp_footer(); ?>
        </body>
        </html>
        <?php
    }

    // --- Assets ---

    private bool $assetsEnqueued = false;

    private function enqueueAssets(): void {
        if ($this->assetsEnqueued) return;
        $this->assetsEnqueued = true;
        $ver = VOLLSTART_RD_PLUGIN_VERSION;
        if ((defined('WP_DEBUG') && WP_DEBUG) || wp_get_environment_type() === 'development') {
            $ver .= '.' . time();
        }
        wp_enqueue_style('dashicons');
        wp_enqueue_style(
            'vollstart-rd-frontend',
            VOLLSTART_RD_PLUGIN_DIR_URL . 'assets/css/frontend.css',
            ['dashicons'],
            $ver
        );
        wp_register_script('qrcodejs', VOLLSTART_RD_PLUGIN_DIR_URL . 'assets/js/libs/qrcode/qrcode.min.js', [], '1.0.0', true);
        wp_enqueue_script(
            'vollstart-rd-frontend',
            VOLLSTART_RD_PLUGIN_DIR_URL . 'assets/js/frontend.js',
            ['jquery', 'wp-i18n', 'qrcodejs'],
            $ver,
            true
        );
        wp_localize_script('vollstart-rd-frontend', 'vollstartRdPublic', [
            'ajaxurl' => admin_url('admin-ajax.php'),
            'nonce'   => wp_create_nonce('vollstart_rd_public'),
            'siteUrl' => home_url('/'),
        ]);
        wp_set_script_translations('vollstart-rd-frontend', 'vollstart-repair-desk', VOLLSTART_RD_PLUGIN_DIR_PATH . 'languages');
    }

    // --- Shortcode ---

    public function renderStatusPage($atts): string {
        if (!$this->MAIN->getOptions()->isCheckboxActive('statusPageEnabled')) {
            return '';
        }

        $this->enqueueAssets();

        $introText = $this->MAIN->getOptions()->getOptionValue('statusPageIntroText') ?: '';

        ob_start();
        ?>
        <div id="rd-status-page" class="rd-public">
            <div id="rd-status-lookup">
                <?php if ($introText): ?>
                    <p class="rd-status-intro"><?php echo esc_html($introText); ?></p>
                <?php endif; ?>
                <form id="rd-status-form">
                    <div class="rd-status-fields">
                        <input type="text" id="rd-lookup-number" placeholder="<?php esc_attr_e('Repair number (e.g. REP-0001)', 'vollstart-repair-desk'); ?>" required autocomplete="off">
                        <input type="text" id="rd-lookup-code" placeholder="<?php esc_attr_e('Access code (e.g. A1B2-C3D4)', 'vollstart-repair-desk'); ?>" required autocomplete="off">
                    </div>
                    <button type="submit" class="rd-btn-lookup"><?php esc_html_e('Check Status', 'vollstart-repair-desk'); ?></button>
                </form>
                <div id="rd-status-error" style="display:none"></div>
            </div>
            <div id="rd-status-result" style="display:none"></div>
        </div>
        <?php
        return ob_get_clean();
    }

    // --- Rating Page ---

    public function handleRatingPage(): void {
        if (!get_query_var('vollstart_rd_rating_page')) return;
        if (!$this->MAIN->getOptions()->isCheckboxActive('enableRatings')) {
            status_header(404);
            return;
        }

        $token = sanitize_text_field(get_query_var('vollstart_rd_rating_token', ''));
        $this->enqueueAssets();

        if ($token) {
            wp_localize_script('vollstart-rd-frontend', 'vollstartRdRating', ['token' => $token]);
        }

        add_filter('template_include', function() use ($token) {
            $rating = $token ? $this->MAIN->getRatings()->getByToken($token) : null;
            $repair = $rating ? $this->MAIN->getRepairs()->getById((int) $rating['repair_id']) : null;
            $title = $this->MAIN->getOptions()->getOptionValue('businessName') ?: __('Rate your repair', 'vollstart-repair-desk');
            ?>
            <!DOCTYPE html>
            <html <?php language_attributes(); ?>>
            <head>
                <meta charset="<?php bloginfo('charset'); ?>">
                <meta name="viewport" content="width=device-width, initial-scale=1">
                <meta name="robots" content="noindex, nofollow">
                <title><?php echo esc_html($title); ?></title>
                <?php wp_head(); ?>
            </head>
            <body style="margin:0;padding:40px 16px;background:#f8fafc;min-height:100vh">
                <div style="max-width:520px;margin:0 auto">
                    <h1 style="text-align:center;font-size:22px;color:#1e293b;margin-bottom:24px"><?php echo esc_html($title); ?></h1>
                    <?php if (!$rating): ?>
                        <div class="rd-public" style="text-align:center;padding:40px 20px">
                            <p style="color:#dc2626"><?php esc_html_e('Invalid rating link.', 'vollstart-repair-desk'); ?></p>
                        </div>
                    <?php else: ?>
                        <div id="rd-rating-app" class="rd-public"
                            data-repair-number="<?php echo esc_attr($repair ? $repair['repair_number'] : ''); ?>"
                            data-existing-rating="<?php echo esc_attr($rating['rating']); ?>"
                            data-existing-comment="<?php echo esc_attr($rating['comment']); ?>"
                            data-allow-update="<?php echo esc_attr($this->MAIN->getOptions()->isCheckboxActive('ratingAllowUpdate') ? '1' : '0'); ?>">
                        </div>
                    <?php endif; ?>
                </div>
                <?php wp_footer(); ?>
            </body>
            </html>
            <?php
            exit;
        }, 999);
    }

    // --- AJAX ---

    // phpcs:disable WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.MissingUnslash -- nonce verified via check_ajax_referer() at method start; all values sanitized
    public function handleAjax(): void {
        check_ajax_referer('vollstart_rd_public', 'nonce');

        $action = sanitize_text_field(wp_unslash($_POST['sub_action'] ?? ''));

        switch ($action) {
            case 'lookup':
                $this->ajaxLookup();
                break;
            case 'reply':
                $this->ajaxReply();
                break;
            case 'submit_rating':
                $this->ajaxSubmitRating();
                break;
            case 'submit_status_rating':
                $this->ajaxSubmitStatusRating();
                break;
            default:
                wp_send_json_error(['message' => __('Unknown action', 'vollstart-repair-desk')]);
        }
    }
    // phpcs:enable WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.MissingUnslash

    // phpcs:disable WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.MissingUnslash -- nonce verified in handleAjax(); all values sanitized
    private function ajaxLookup(): void {
        if (!$this->MAIN->getOptions()->isCheckboxActive('statusPageEnabled')) {
            wp_send_json_error(['message' => __('Status page is disabled.', 'vollstart-repair-desk')]);
        }

        $number = strtoupper(trim(sanitize_text_field(wp_unslash($_POST['repair_number'] ?? ''))));
        $code = strtoupper(trim(sanitize_text_field(wp_unslash($_POST['access_code'] ?? ''))));

        if (empty($number) || empty($code)) {
            wp_send_json_error(['message' => __('Please enter both repair number and access code.', 'vollstart-repair-desk')]);
        }

        $repairs = $this->MAIN->getRepairs();
        $repair = $repairs->getByAccessCode($code);

        if (!$repair || strtoupper($repair['repair_number']) !== $number) {
            wp_send_json_error(['message' => __('Repair not found. Please check your repair number and access code.', 'vollstart-repair-desk')]);
        }

        // Mark staff messages as read (customer is viewing)
        $repairId = (int) $repair['id'];
        $db = $this->MAIN->getDB();
        $msgTbl = $db->getTabelle('messages');
        $db->getVar("UPDATE %i SET read_at = %s WHERE repair_id = %d AND sender_type = 'staff' AND read_at IS NULL", $msgTbl, current_time('mysql'), $repairId);

        // Build public response — only customer-safe data
        $isFinal = $repairs->isFinalStatus($repair['status']);
        $response = [
            'repair_number'   => $repair['repair_number'],
            'access_code'     => $repair['access_code'],
            'status_url'      => $this->getStatusUrl($repair),
            'status'          => $repair['status'],
            'status_label'    => $repairs->getStatusLabel($repair['status']),
            'status_color'    => $repairs->getStatusColor($repair['status']),
            'is_final'        => $isFinal,
            'device_brand'    => $repair['device_brand'],
            'device_model'    => $repair['device_model'],
            'device_serial'   => $repair['device_serial'],
            'defect'          => $repair['defect_description'],
            'priority'        => $repair['priority'],
            'estimated_date'  => $repair['estimated_date'],
            'estimated_price' => $repair['estimated_price'],
            'warranty_until'  => $repair['warranty_until'],
            'created_at'      => $repair['created_at'],
            'currency'        => $this->MAIN->getCurrency(),
        ];

        // Timeline (if enabled)
        $opts = $this->MAIN->getOptions();
        if ($opts->isCheckboxActive('statusPageShowTimeline')) {
            $log = $repairs->getStatusLog((int) $repair['id']);
            $timeline = [];
            foreach ($log as $entry) {
                if (($entry['event_type'] ?? '') !== 'status_change') continue;
                $timeline[] = [
                    'status'     => $repairs->getStatusLabel($entry['new_status']),
                    'color'      => $repairs->getStatusColor($entry['new_status']),
                    'created_at' => $entry['created_at'],
                    'note'       => $entry['note'] ?? '',
                ];
            }
            $response['timeline'] = $timeline;
        }

        // Repair files (if enabled)
        $repairId = (int) $repair['id'];
        if ($opts->isCheckboxActive('statusPageShowFiles')) {
            $files = $this->MAIN->getFileUpload()->getByEntity('repair', $repairId);
            $publicFiles = [];
            foreach ($files as $f) {
                $publicFiles[] = [
                    'name'     => $f['original_name'],
                    'url'      => home_url('?vollstart_rd_file=' . $f['download_token']),
                    'is_image' => (bool) preg_match('/^image\//', $f['mime_type'] ?? ''),
                ];
            }
            $response['files'] = $publicFiles;
        }

        // Work steps (if enabled)
        if ($opts->isCheckboxActive('enableWorkSteps') && $opts->isCheckboxActive('statusPageShowWorkSteps')) {
            $steps = $this->MAIN->getChecklists()->getRepairSteps($repairId);
            $showStepTime = $opts->isCheckboxActive('statusPageShowStepTime');
            $showStepFiles = $opts->isCheckboxActive('statusPageShowStepFiles');
            $fileUpload = $this->MAIN->getFileUpload();
            $publicSteps = [];
            foreach ($steps as $groupName => $items) {
                $group = [];
                foreach ($items as $step) {
                    if (!empty($step['_removed'])) continue; // hide removed steps
                    $s = [
                        'title'      => $step['title'],
                        'is_checked' => !empty($step['is_checked']) && $step['is_checked'] !== '0',
                    ];
                    if ($showStepTime) {
                        $s['duration'] = (float) ($step['tracked_duration'] ?? 0);
                    }
                    // Attach instruction files from template checklist_item
                    if ($showStepFiles) {
                        $ciId = (int) ($step['checklist_item_id'] ?? 0);
                        if ($ciId > 0) {
                            $instrFiles = $fileUpload->getByEntity('checklist_item', $ciId);
                            $stepFiles = [];
                            foreach ($instrFiles as $sf) {
                                $stepFiles[] = [
                                    'name'     => $sf['original_name'],
                                    'url'      => home_url('?vollstart_rd_file=' . $sf['download_token']),
                                    'is_image' => (bool) preg_match('/^image\//', $sf['mime_type'] ?? ''),
                                ];
                            }
                            if ($stepFiles) $s['files'] = $stepFiles;
                        }
                    }
                    $group[] = $s;
                }
                if ($group) $publicSteps[$groupName] = $group;
            }
            $response['work_steps'] = $publicSteps;
        }

        // Messages (if message system + status page option both enabled)
        if ($opts->isCheckboxActive('enableMessages') && $opts->isCheckboxActive('statusPageShowMessages')) {
            $db = $this->MAIN->getDB();
            $tbl = $db->getTabelle('messages');
            $messages = $db->getResults(
                "SELECT sender_type, message, created_at FROM %i WHERE repair_id = %d ORDER BY created_at ASC",
                $tbl,
                $repairId
            );
            $response['messages'] = $messages ?: [];
            $response['allow_reply'] = !$isFinal && $opts->isCheckboxActive('statusPageAllowReply');
        }

        // Rating on status page
        if ($opts->isCheckboxActive('enableRatings') && $opts->isCheckboxActive('ratingShowOnStatusPage')) {
            $repairRating = $this->MAIN->getRatings()->getExisting('repair', $repairId, 0);
            $response['rating'] = $repairRating && (int) $repairRating['rating'] > 0 ? (int) $repairRating['rating'] : 0;
            $response['rating_comment'] = $repairRating ? $repairRating['comment'] : '';
            $response['rating_token'] = $repairRating && !empty($repairRating['token']) ? $repairRating['token'] : '';
            $hasRated = $response['rating'] > 0;
            $response['allow_rating'] = !$hasRated || $opts->isCheckboxActive('ratingAllowUpdate');
        }

        wp_send_json_success($response);
    }

    /**
     * Customer reply from public status page.
     */
    private function ajaxReply(): void {
        $opts = $this->MAIN->getOptions();
        if (!$opts->isCheckboxActive('statusPageEnabled') || !$opts->isCheckboxActive('enableMessages') || !$opts->isCheckboxActive('statusPageAllowReply')) {
            wp_send_json_error(['message' => __('Replies are not enabled.', 'vollstart-repair-desk')]);
        }

        $code = strtoupper(trim(sanitize_text_field(wp_unslash($_POST['access_code'] ?? ''))));
        $message = sanitize_textarea_field(wp_unslash($_POST['message'] ?? ''));

        if (empty($code) || empty($message)) {
            wp_send_json_error(['message' => __('Please enter a message.', 'vollstart-repair-desk')]);
        }

        $repair = $this->MAIN->getRepairs()->getByAccessCode($code);
        if (!$repair) {
            wp_send_json_error(['message' => __('Invalid access code.', 'vollstart-repair-desk')]);
        }
        if ($this->MAIN->getRepairs()->isFinalStatus($repair['status'])) {
            wp_send_json_error(['message' => __('This repair is closed.', 'vollstart-repair-desk')]);
        }

        // Get customer name
        $customerName = __('Customer', 'vollstart-repair-desk');
        if (!empty($repair['customer_id'])) {
            $customer = $this->MAIN->getCustomers()->getById((int) $repair['customer_id']);
            if ($customer) {
                $customerName = trim($customer['first_name'] . ' ' . $customer['last_name']) ?: $customerName;
            }
        }

        $this->MAIN->getDB()->insert('messages', [
            'repair_id'   => (int) $repair['id'],
            'sender_type' => 'customer',
            'sender_name' => $customerName,
            'message'     => $message,
            'created_at'  => current_time('mysql'),
        ]);

        // Notify business about new customer message
        $this->MAIN->getNotifications()->sendNewMessageNotification((int) $repair['id'], $message);

        wp_send_json_success(['message' => __('Message sent.', 'vollstart-repair-desk')]);
    }

    // --- Rating AJAX ---

    private function ajaxSubmitRating(): void {
        if (!$this->MAIN->getOptions()->isCheckboxActive('enableRatings')) {
            wp_send_json_error(['message' => __('Ratings are disabled.', 'vollstart-repair-desk')]);
        }
        $token = sanitize_text_field(wp_unslash($_POST['token'] ?? ''));
        $rating = $this->MAIN->getRatings()->getByToken($token);
        if (!$rating) wp_send_json_error(['message' => __('Invalid rating link.', 'vollstart-repair-desk')]);

        $allowUpdate = $this->MAIN->getOptions()->isCheckboxActive('ratingAllowUpdate');
        if ($rating['rating'] > 0 && $rating['rated_by'] !== 'pending' && !$allowUpdate) {
            wp_send_json_error(['message' => __('You have already rated this repair.', 'vollstart-repair-desk')]);
        }

        $this->MAIN->getRatings()->submit([
            'type'        => $rating['type'],
            'repair_id'   => (int) $rating['repair_id'],
            'customer_id' => (int) $rating['customer_id'],
            'rating'      => intval(wp_unslash($_POST['rating'] ?? 0)),
            'comment'     => sanitize_textarea_field(wp_unslash($_POST['comment'] ?? '')),
            'phase'       => $rating['phase'],
            'rated_by'    => 'customer',
        ]);

        wp_send_json_success(['message' => __('Thank you for your feedback!', 'vollstart-repair-desk')]);
    }

    private function ajaxSubmitStatusRating(): void {
        $opts = $this->MAIN->getOptions();
        if (!$opts->isCheckboxActive('enableRatings') || !$opts->isCheckboxActive('ratingShowOnStatusPage')) {
            wp_send_json_error(['message' => __('Ratings are disabled.', 'vollstart-repair-desk')]);
        }

        $number = strtoupper(trim(sanitize_text_field(wp_unslash($_POST['repair_number'] ?? ''))));
        $code = strtoupper(trim(sanitize_text_field(wp_unslash($_POST['access_code'] ?? ''))));
        $repair = $this->MAIN->getRepairs()->getByAccessCode($code);
        if (!$repair || strtoupper($repair['repair_number']) !== $number) {
            wp_send_json_error(['message' => __('Repair not found. Please check your repair number and access code.', 'vollstart-repair-desk')]);
        }

        $this->MAIN->getRatings()->submit([
            'type'        => 'repair',
            'repair_id'   => (int) $repair['id'],
            'customer_id' => (int) ($repair['customer_id'] ?? 0),
            'rating'      => intval(wp_unslash($_POST['rating'] ?? 0)),
            'comment'     => sanitize_textarea_field(wp_unslash($_POST['comment'] ?? '')),
            'phase'       => $repair['status'],
            'rated_by'    => 'customer',
        ]);

        wp_send_json_success(['message' => __('Thank you for your feedback!', 'vollstart-repair-desk')]);
    }
    // phpcs:enable WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.MissingUnslash
}
