<?php

// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedNamespaceFound -- APD is the established namespace shared with the Pro add-on and retained for backward compatibility.
namespace APD\WooCommerce;

use APD\Domain\Product\ProductConfigBinder;
use APD\Front\FrontContextBuilder;
use APD\Front\Renderer;
use APD\Repositories\ProductConfigRepository;
use APD\Support\Json;
use APD\Support\RequestData;

defined('ABSPATH') || exit;

class ProductBindingMetaBox
{
    public function register() : void
    {
        add_meta_box(
            'apd_product_designer_canvas',
            __('Custom product designer', 'asuka-product-designer'),
            [$this, 'renderCanvas'],
            'product',
            'normal',
            'high'
        );
    }

    public function registerProductDataTab(array $tabs) : array
    {
        $tabs['apd_custom_product'] = [
            'label' => __('Custom product', 'asuka-product-designer'),
            'target' => 'apd_custom_product_data',
            'class' => ['show_if_simple', 'show_if_variable'],
            'priority' => 72,
        ];

        return $tabs;
    }

    public function renderProductDataPanel() : void
    {
        global $post;

        if (! $post instanceof \WP_Post || $post->post_type !== 'product') {
            return;
        }

        $repository = new ProductConfigRepository();
        $configs = $repository->allForSelect();
        $binder = new ProductConfigBinder();
        $boundId = $binder->getExactConfigId($post->ID);
        $variationBindings = $binder->getVariationBindings($post->ID);
        $displayMode = $binder->getDisplayMode($post->ID);
        $modalPosition = $binder->getModalButtonPosition($post->ID);
        wp_nonce_field('apd_save_product_binding', 'apd_product_binding_nonce');
        ?>
        <div id="apd_custom_product_data" class="panel woocommerce_options_panel hidden">
            <div class="options_group apd-woo-panel">
                <p class="form-field">
                    <label for="_apd_custom_product_id"><?php esc_html_e('Custom product', 'asuka-product-designer'); ?></label>
                    <select id="_apd_custom_product_id" name="_apd_custom_product_id" class="wc-enhanced-select apd-woo-select-wide">
                        <option value="0"><?php esc_html_e('No linked custom product', 'asuka-product-designer'); ?></option>
                        <?php foreach ($configs as $config) : ?>
                            <option value="<?php echo esc_attr((string) $config['id']); ?>" <?php selected($boundId, $config['id']); ?>><?php echo esc_html($config['title']); ?></option>
                        <?php endforeach; ?>
                    </select>
                    <span class="description"><?php esc_html_e('Choose the custom product used by this WooCommerce product. On the frontend, the designer replaces the default product image area when a custom product is linked.', 'asuka-product-designer'); ?></span>
                </p>
                <p class="form-field">
                    <label for="_apd_custom_product_display_mode"><?php esc_html_e('Display mode', 'asuka-product-designer'); ?></label>
                    <select id="_apd_custom_product_display_mode" name="_apd_custom_product_display_mode" class="wc-enhanced-select apd-woo-select-wide">
                        <option value="condensed" <?php selected($displayMode, 'condensed'); ?>><?php esc_html_e('Condensed — replace only the product image', 'asuka-product-designer'); ?></option>
                        <option value="full_width" <?php selected($displayMode, 'full_width'); ?>><?php esc_html_e('Full width — show the designer across the full product width', 'asuka-product-designer'); ?></option>
                        <option value="modal" <?php selected($displayMode, 'modal'); ?>><?php esc_html_e('Fullscreen modal — open the designer from a button near the price', 'asuka-product-designer'); ?></option>
                    </select>
                    <span class="description"><?php esc_html_e('Choose how the designer should be displayed on the frontend product page.', 'asuka-product-designer'); ?></span>
                </p>
                <p class="form-field">
                    <label for="_apd_custom_product_modal_button_position"><?php esc_html_e('Modal button position', 'asuka-product-designer'); ?></label>
                    <select id="_apd_custom_product_modal_button_position" name="_apd_custom_product_modal_button_position" class="wc-enhanced-select apd-woo-select-wide">
                        <option value="above_price" <?php selected($modalPosition, 'above_price'); ?>><?php esc_html_e('Above price', 'asuka-product-designer'); ?></option>
                        <option value="below_price" <?php selected($modalPosition, 'below_price'); ?>><?php esc_html_e('Below price', 'asuka-product-designer'); ?></option>
                    </select>
                    <span class="description"><?php esc_html_e('Used only when the display mode is “Fullscreen modal”.', 'asuka-product-designer'); ?></span>
                </p>
                <p class="form-field apd-woo-panel-note">
                    <label><?php esc_html_e('Variation priority', 'asuka-product-designer'); ?></label>
                    <span class="description"><?php esc_html_e('Each variation can override the parent custom product. The variation binding is used first; otherwise the parent product binding is used.', 'asuka-product-designer'); ?></span>
                </p>
                <?php if (! empty($variationBindings)) : ?>
                    <p class="form-field apd-woo-panel-note">
                        <label><?php esc_html_e('Linked variations', 'asuka-product-designer'); ?></label>
                        <span class="description"><?php echo esc_html(sprintf(/* translators: Placeholder values are populated from the current WooCommerce product, cart, or order. */ _n('%d variation currently overrides the parent custom product.', '%d variations currently override the parent custom product.', count($variationBindings), 'asuka-product-designer'), count($variationBindings))); ?></span>
                    </p>
                <?php endif; ?>
            </div>
        </div>
        <?php
    }

    public function renderVariationField(int $loop, array $variationData, \WP_Post $variation) : void
    {
        $repository = new ProductConfigRepository();
        $configs = $repository->allForSelect();
        $boundId = (new ProductConfigBinder())->getExactConfigId($variation->ID);
        ?>
        <div class="form-row form-row-full apd-variation-custom-product">
            <label><?php esc_html_e('Custom product', 'asuka-product-designer'); ?></label>
            <select name="_apd_variation_custom_product_id[<?php echo esc_attr((string) $variation->ID); ?>]" class="wc-enhanced-select apd-woo-select-full">
                <option value="0"><?php esc_html_e('Use parent custom product', 'asuka-product-designer'); ?></option>
                <?php foreach ($configs as $config) : ?>
                    <option value="<?php echo esc_attr((string) $config['id']); ?>" <?php selected($boundId, $config['id']); ?>><?php echo esc_html($config['title']); ?></option>
                <?php endforeach; ?>
            </select>
            <p class="description"><?php esc_html_e('Override the parent binding for this variation only.', 'asuka-product-designer'); ?></p>
        </div>
        <?php
    }

    public function renderCanvas(\WP_Post $post) : void
    {
        $binder = new ProductConfigBinder();
        $boundId = $binder->getExactConfigId($post->ID);
        $variationBindings = $binder->getVariationBindings($post->ID);
        ?>
        <div class="apd-product-canvas-box">
            <?php if ($boundId <= 0 && empty($variationBindings)) : ?>
                <div class="apd-empty-state apd-empty-state-soft">
                    <h3><?php esc_html_e('No custom product linked yet', 'asuka-product-designer'); ?></h3>
                    <p><?php esc_html_e('Choose a custom product in the “Custom product” WooCommerce tab, save the product once, and this screen will show the linked designer canvas here.', 'asuka-product-designer'); ?></p>
                </div>
                <?php return; ?>
            <?php endif; ?>

            <?php if ($boundId > 0) : ?>
                <?php
                $renderer = new Renderer(new FrontContextBuilder());
                $markup = $renderer->render([
                    'product_id' => $post->ID,
                    'id' => $boundId,
                    'mode' => 'admin',
                    'height' => '820px',
                ]);
                ?>
                <div class="apd-product-canvas-stage js-apd-product-canvas">
                    <?php echo $markup; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
                </div>
                <p class="description"><?php esc_html_e('This builder edits the parent-level custom product linked to the WooCommerce product.', 'asuka-product-designer'); ?></p>
            <?php else : ?>
                <div class="apd-empty-state apd-empty-state-soft">
                    <h3><?php esc_html_e('Variation-driven custom products', 'asuka-product-designer'); ?></h3>
                    <p><?php esc_html_e('This product currently relies on variation-level custom products. Use the variation panels below to manage them individually.', 'asuka-product-designer'); ?></p>
                </div>
            <?php endif; ?>

            <textarea name="_apd_product_canvas_document" class="apd-product-canvas-store" hidden></textarea>
            <textarea name="_apd_product_canvas_state" class="apd-product-canvas-state-store" hidden></textarea>
        </div>
        <?php
    }

    public function save(int $postId, \WP_Post $post) : void
    {
        if ($post->post_type !== 'product') {
            return;
        }

        $request = RequestData::post();
        $nonce = sanitize_text_field((string) ($request['apd_product_binding_nonce'] ?? ''));
        if ($nonce === '' || ! wp_verify_nonce($nonce, 'apd_save_product_binding')) {
            return;
        }

        if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
            return;
        }

        if (! current_user_can('edit_post', $postId)) {
            return;
        }

        $binder = new ProductConfigBinder();
        $configId = $this->sanitizeConfigId($request['_apd_custom_product_id'] ?? 0);
        $binder->bind($postId, $configId);
        $binder->setDisplayMode($postId, sanitize_key((string) ($request['_apd_custom_product_display_mode'] ?? 'condensed')));
        $binder->setModalButtonPosition($postId, sanitize_key((string) ($request['_apd_custom_product_modal_button_position'] ?? 'below_price')));

        $document = isset($request['_apd_product_canvas_document']) ? (string) $request['_apd_product_canvas_document'] : '';
        $state = isset($request['_apd_product_canvas_state']) ? (string) $request['_apd_product_canvas_state'] : '';
        $this->debugSaveLog('product-binding:start', $postId, [
            'configId' => $configId,
            'document' => $this->summarizePostedCanvasPayload($document),
            'state' => $this->summarizePostedCanvasPayload($state),
        ]);
        if ($configId > 0 && trim($document) !== '') {
            $normalized = Json::normalize($document);
            if ($normalized !== null) {
                update_post_meta($configId, '_apd_initial_document', wp_slash($normalized));
            }
        }
        if ($configId > 0 && trim($state) !== '') {
            $normalized = Json::normalize($state);
            if ($normalized !== null) {
                update_post_meta($configId, '_apd_initial_state', wp_slash($normalized));
            }
        }
        $this->debugSaveLog('product-binding:after-update', $postId, [
            'configId' => $configId,
            'storedDocument' => $this->summarizePostedCanvasPayload($configId > 0 ? (string) get_post_meta($configId, '_apd_initial_document', true) : ''),
            'storedState' => $this->summarizePostedCanvasPayload($configId > 0 ? (string) get_post_meta($configId, '_apd_initial_state', true) : ''),
        ]);
    }

    public function saveVariation(int $variationId, int $loop) : void
    {
        $request = RequestData::post();
        $nonce = sanitize_text_field((string) ($request['apd_product_binding_nonce'] ?? ''));
        if ($nonce === '' || ! wp_verify_nonce($nonce, 'apd_save_product_binding')) {
            return;
        }

        if (! current_user_can('edit_post', $variationId)) {
            return;
        }

        $value = 0;
        if (isset($request['_apd_variation_custom_product_id'][$variationId])) {
            $value = $this->sanitizeConfigId($request['_apd_variation_custom_product_id'][$variationId]);
        }

        (new ProductConfigBinder())->bind($variationId, $value);
    }


    private function debugSaveLog(string $phase, int $postId, array $payload = []) : void
    {
        if (! defined('WP_DEBUG') || ! WP_DEBUG) {
            return;
        }

        // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- The apd_ hook is a documented integration API retained for backward compatibility.
        do_action('apd_admin_save_debug_log', [
            'phase' => $phase,
            'postId' => $postId,
            'payload' => $payload,
        ]);
    }

    /**
     * @return array<string, mixed>
     */
    private function summarizePostedCanvasPayload(string $value) : array
    {
        $trimmed = trim($value);
        $decoded = $trimmed !== '' ? json_decode($trimmed, true) : null;
        $validJson = $trimmed === '' ? null : json_last_error() === JSON_ERROR_NONE;
        $topKeys = is_array($decoded) ? array_slice(array_keys($decoded), 0, 12) : [];
        $viewsCount = 0;
        if (is_array($decoded) && isset($decoded['views']) && is_array($decoded['views'])) {
            $viewsCount = isset($decoded['views']['views']) && is_array($decoded['views']['views']) ? count($decoded['views']['views']) : count($decoded['views']);
        }

        return [
            'length' => strlen($value),
            'trimmedLength' => strlen($trimmed),
            'validJson' => $validJson,
            'topKeys' => $topKeys,
            'viewsCount' => $viewsCount,
        ];
    }

    private function sanitizeConfigId(mixed $value) : int
    {
        $configId = absint($value);
        if ($configId <= 0) {
            return 0;
        }

        return get_post_type($configId) === 'apd_product_config' ? $configId : 0;
    }
}
