<?php
if ( ! defined( 'ABSPATH' ) ) { exit; }

/**
 * Merges post meta + global defaults into the JS config object passed to TNCFlipbook.
 * Lite version - Pro-only config sections are skipped.
 */
class TNC_Flipbook_3D_Config_Builder {

    /** All chrome surface palettes shipped by the viewer engine. */
    private static $valid_chromes = array( 'slate', 'paper', 'midnight', 'ocean', 'forest', 'glass', 'sepia' );

    /** Legacy chrome names → new names. Stored values from before the rename get migrated. */
    private static $chrome_migrate = array( 'dark' => 'slate', 'light' => 'paper' );

    /** Pro-only toolbar items disabled in Lite */
    private static $pro_toolbar = array( 'notes', 'formViewer', 'tilt', 'rotate', 'readAloud' );

    /**
     * Build the full config + options arrays for a given flipbook post.
     *
     * @param  int   $post_id
     * @return array { config: array, options: array }
     */
    public static function build( $post_id ) {
        $post = get_post( $post_id );
        if ( ! $post || TNC_FLIPBOOK_3D_CPT !== $post->post_type ) {
            return array( 'config' => array(), 'options' => array() );
        }

        $is_pro  = function_exists( 'tnc_flipbook_3d_is_pro' ) && tnc_flipbook_3d_is_pro();
        $p       = TNC_FLIPBOOK_3D_PREFIX;
        $schema  = TNC_Flipbook_3D_Meta_Schema::get();
        $global  = get_option( TNC_FLIPBOOK_3D_OPTION, array() );

        // ── 1. Collect effective values ───────────────────────────────────────
        $effective = array();
        foreach ( $schema as $meta_key => $spec ) {
            $short     = str_replace( $p, '', $meta_key );
            $override  = get_post_meta( $post_id, $meta_key . '_override', true );
            $post_val  = get_post_meta( $post_id, $meta_key, true );

            $is_bool = isset( $spec['type'] ) && 'bool' === $spec['type'];
            if ( $override && ( $is_bool || ( '' !== $post_val && false !== $post_val ) ) ) {
                $effective[ $short ] = $is_bool ? ! empty( $post_val ) : $post_val;
            } elseif ( ! empty( $spec['overridable'] ) ) {
                $global_key = isset( $spec['global_key'] ) ? $spec['global_key'] : $short;
                if ( isset( $global[ $global_key ] ) ) {
                    $effective[ $short ] = $global[ $global_key ];
                } else {
                    $effective[ $short ] = $spec['default'];
                }
            } else {
                $effective[ $short ] = '' !== $post_val && false !== $post_val
                    ? $post_val
                    : $spec['default'];
            }
        }

        $effective = apply_filters( 'tncfb3d_config_effective_values', $effective, $post_id, $schema, $global );

        // ── 2. Build content source ───────────────────────────────────────────
        $source_type = isset( $effective['source_type'] ) ? $effective['source_type'] : 'pdf';

        $config = array(
            'pdfSource'    => '',
            'pdfSources'   => null,
            'imageSources' => null,
        );

        if ( 'pdf' === $source_type ) {
            $pdf_id = absint( $effective['pdf_id'] ?? 0 );
            if ( $pdf_id ) {
                $config['pdfSource'] = TNC_Flipbook_3D_Helpers::proxy_url( $post_id, 'pdf', 0 );
            }
        } elseif ( 'images' === $source_type ) {
            $image_ids = is_array( $effective['image_ids'] ?? null ) ? $effective['image_ids'] : array();
            if ( ! empty( $image_ids ) ) {
                $config['imageSources'] = array();
                foreach ( array_values( $image_ids ) as $idx => $img_id ) {
                    $config['imageSources'][] = TNC_Flipbook_3D_Helpers::proxy_url( $post_id, 'image', $idx );
                }
            }
        }

        // ── 2b. Download filename ────────────────────────────────────────────
        $title     = get_the_title( $post_id );
        $site_name = get_bloginfo( 'name' );
        $config['downloadFilename'] = sanitize_file_name( $title . ' - ' . $site_name ) . '.pdf';

        // ── 3. Toolbar ────────────────────────────────────────────────────────
        $toolbar = array();
        $toolbar_keys = array(
            'share','download','print','search','tilt','rotate','zoom','readingMode','readAloud',
            'fullscreen','themeToggle','moreMenu','pageIndicator','logo','autoPlay',
            'sound','singlePage','bookmarks','notes','thumbnails','viewModes','formViewer',
            'flipbookStyles','rtl','navigation',
        );
        foreach ( $toolbar_keys as $tk ) {
            $key = 'toolbar_' . $tk;
            // Items not shipped in the free engine stay off; everything else
            // honours the merchant's saved show/hide choice.
            if ( in_array( $tk, self::$pro_toolbar, true ) ) {
                $toolbar[ $tk ] = false;
                continue;
            }
            $toolbar[ $tk ] = isset( $effective[ $key ] ) ? ! empty( $effective[ $key ] ) : true;
        }
        // Bookmarks (TOC) is always available in Free - override any stale saved value
        $toolbar['bookmarks'] = true;

        $config['toolbar'] = $toolbar;

        // ── 4. Flat schema fields → nested config paths ───────────────────────
        foreach ( $schema as $meta_key => $spec ) {
            if ( empty( $spec['config_path'] ) ) {
                continue;
            }
            $short = str_replace( $p, '', $meta_key );
            if ( ! isset( $effective[ $short ] ) ) {
                continue;
            }

            // Lite: toolbar visibility is a Pro-only control, fully populated from
            // schema defaults in the dedicated block above. Skip ALL toolbar
            // config paths here so a stale/forced value in the shared settings
            // option (e.g. saved by an older build before the sanitizer fix) can
            // never overwrite the schema-default toolbar and blank the bar.
            if ( ! $is_pro
                && isset( $spec['config_path'][0] ) && 'toolbar' === $spec['config_path'][0]
            ) {
                continue;
            }

            $value = $effective[ $short ];
            self::set_nested( $config, $spec['config_path'], $value );
        }

        // Force-enable toolbar items that have no settings UI (always on/off).
        // Must run after the config_path loop which can overwrite toolbar values.
        $config['toolbar']['moreMenu']       = true;
        $config['toolbar']['flipbookStyles'] = true;

        // ── 4a. Image-based flipbooks: hide PDF-only toolbar items ───────────
        if ( 'images' === $source_type ) {
            $config['toolbar']['download']   = false;
            $config['toolbar']['search']     = false;
            $config['toolbar']['print']      = false;
            $config['toolbar']['formViewer'] = false;
            $config['toolbar']['readAloud']  = false;
        }

        // ── 4b. Lite overrides (after schema loop so they stick) ─────────────
        if ( ! $is_pro ) {
            // Accessibility always on in Free
            if ( ! isset( $config['accessibility'] ) ) {
                $config['accessibility'] = array();
            }
            $config['accessibility']['enabled']                   = true;
            $config['accessibility']['skipLinks']                  = true;
            $config['accessibility']['keyboardShortcuts']          = true;
            $config['accessibility']['screenReaderAnnouncements']  = true;
            $config['accessibility']['focusIndicators']            = true;
            $config['accessibility']['reducedMotion']              = true;
            $config['accessibility']['highContrastMode']           = true;
            $config['accessibility']['keyboardShortcutsHelp']      = true;
        }

        // ── 4b. RTL detection from language ──────────────────────────────────
        $rtl_langs = array( 'ar', 'he', 'fa', 'ur', 'ku', 'ps', 'sd', 'yi', 'ckb', 'ug' );
        $lang = isset( $config['language'] ) ? $config['language'] : '';
        if ( in_array( $lang, $rtl_langs, true ) ) {
            $config['isRTL'] = true;
        }

        // ── 5. Content protection ────────────────────────────────────────────
        // Lite: only hide source paths (basic security). Full DRM is Pro.
        if ( ! isset( $config['contentProtection'] ) ) {
            $config['contentProtection'] = array();
        }
        $config['contentProtection']['hideSourcePaths'] = true;

        if ( ! $is_pro ) {
            // Strip any DRM config that may have leaked from schema defaults
            unset( $config['contentProtection']['watermark'] );
            unset( $config['contentProtection']['allowedDomains'] );
            unset( $config['contentProtection']['disableRightClick'] );
            unset( $config['contentProtection']['disableKeyboardShortcuts'] );
            unset( $config['contentProtection']['disableImageDrag'] );
            unset( $config['contentProtection']['devToolsDetection'] );
            unset( $config['contentProtection']['printProtection'] );
            unset( $config['contentProtection']['screenshotDeterrent'] );

            // Slide/Fade flip effects are Pro-only — their viewer code
            // (_effectFlipPage) is stripped from the Lite engine. Clamp any
            // non-free value (e.g. carried over from a Pro -> Lite downgrade)
            // to 'realistic' so the viewer never calls the missing method.
            if ( isset( $config['flipEffect'] )
                && ! in_array( $config['flipEffect'], array( 'realistic', 'hard' ), true ) ) {
                $config['flipEffect'] = 'realistic';
            }
        }

        // ── 6. Page videos (Pro only) ───────────────────────────────────────
        if ( $is_pro ) {
            $page_videos = is_array( $effective['page_videos'] ?? null ) ? $effective['page_videos'] : array();
            if ( ! empty( $page_videos ) ) {
                $config['pageVideos'] = array();
                foreach ( $page_videos as $idx => $pv ) {
                    $vid_id = absint( $pv['video_id'] ?? 0 );
                    if ( ! $vid_id ) { continue; }
                    $entry = $pv;
                    $entry['src'] = TNC_Flipbook_3D_Helpers::proxy_url( $post_id, 'video', absint( $idx ) );
                    unset( $entry['video_id'] );
                    $config['pageVideos'][] = $entry;
                }
            }
        }

        // ── 6b. Custom table of contents ────────────────────────────────────
        $toc_custom = is_array( $effective['toc_custom'] ?? null ) ? $effective['toc_custom'] : array();
        if ( ! empty( $toc_custom ) ) {
            $config['tableOfContents'] = array_values( $toc_custom );
        }

        // ── 7. Hotspots (Pro only) ──────────────────────────────────────────
        if ( $is_pro ) {
            $hotspots = is_array( $effective['hotspots'] ?? null ) ? $effective['hotspots'] : array();
            if ( ! empty( $hotspots ) ) {
                $config['hotspots'] = array_values( $hotspots );
            }
        }

        // ── 7b. Content access gating (extensible) ─────────────────────────
        $access = array(
            'status'       => 'full',
            'previewPages' => 0,
            'message'      => '',
            'purchaseUrl'  => '',
            'provider'     => '',
        );

        // Built-in WooCommerce gating (Pro only)
        if ( $is_pro && class_exists( 'WooCommerce' ) && class_exists( 'TNC_Flipbook_3D_WooCommerce' ) ) {
            $woo_product_id = absint( $effective['woo_product_id'] ?? 0 );
            if ( $woo_product_id > 0 ) {
                $woo_status = TNC_Flipbook_3D_WooCommerce::check_access( $post_id );
                if ( 'preview' === $woo_status ) {
                    $preview_pages = absint( $effective['preview_pages'] ?? 0 );
                    if ( $preview_pages > 0 ) {
                        $access['status']       = 'preview';
                        $access['previewPages'] = $preview_pages;
                        $access['message']      = ! empty( $effective['gating_message'] )
                            ? $effective['gating_message']
                            : __( 'Purchase to continue reading', 'tnc-flipbook-3d-lite' );
                        $access['purchaseUrl']  = get_permalink( $woo_product_id );
                        $access['provider']     = 'woocommerce';
                    }
                }
            }
        }

        // Let addons override or set their own gating
        $access = apply_filters( 'tncfb3d_content_access', $access, $post_id, $effective );

        if ( 'preview' === $access['status'] && $access['previewPages'] > 0 ) {
            $config['previewPages']  = absint( $access['previewPages'] );
            $config['gatingMessage'] = sanitize_text_field( $access['message'] ?: __( 'Purchase to continue reading', 'tnc-flipbook-3d-lite' ) );
            $config['purchaseUrl']   = esc_url_raw( $access['purchaseUrl'] );
            $config['gatingProvider'] = sanitize_key( $access['provider'] );
        }

        // ── 8. Loading logo ─────────────────────────────────────────────────
        if ( $is_pro ) {
            $logo_id = absint( $effective['loadingLogo_id'] ?? 0 );
            if ( $logo_id ) {
                $logo_url = wp_get_attachment_url( $logo_id );
                if ( $logo_url ) {
                    $config['loadingLogo'] = $logo_url;
                }
            }
        }
        if ( empty( $config['loadingLogo'] ) ) {
            $config['loadingLogo'] = TNC_FLIPBOOK_3D_URL . 'assets/flipbook/tnc-flipbook-icon-white.png';
        }
        if ( empty( $config['loadingLogoDark'] ) ) {
            $config['loadingLogoDark'] = TNC_FLIPBOOK_3D_URL . 'assets/flipbook/tnc-flipbook-icon-color.png';
        }

        // ── 8b. Watermark image (Pro only - resolve attachment ID → URL) ────
        if ( $is_pro ) {
            $wm_img_id = absint( $effective['watermark_image_id'] ?? 0 );
            if ( $wm_img_id ) {
                $wm_img_url = wp_get_attachment_url( $wm_img_id );
                if ( $wm_img_url ) {
                    if ( ! isset( $config['contentProtection']['watermark'] ) ) {
                        $config['contentProtection']['watermark'] = array();
                    }
                    $config['contentProtection']['watermark']['imageUrl'] = $wm_img_url;
                }
            }
        }

        // ── 9. PDF.js font/cmap paths ───────────────────────────────────────
        $base_url = TNC_FLIPBOOK_3D_URL;
        // PDF.js 5.x JPEG 2000 (OpenJPEG) + CMYK/ICC (qcms) WASM decoders.

        $config = apply_filters( 'tncfb3d_config', $config, $post_id, $effective );

        // ── 10. Options object ──────────────────────────────────────────────
        $chrome = $effective['chrome'] ?? 'slate';
        if ( isset( self::$chrome_migrate[ $chrome ] ) ) {
            $chrome = self::$chrome_migrate[ $chrome ];
        }
        if ( ! in_array( $chrome, self::$valid_chromes, true ) ) {
            $chrome = 'slate';
        }
        $color_mode = $effective['colorMode'] ?? 'auto';
        if ( ! in_array( $color_mode, array( 'auto', 'dark', 'light' ), true ) ) {
            $color_mode = 'auto';
        }
        $brand_color = $effective['brandColor'] ?? '#4a9eff';

        $options  = array(
            'workerSrc'          => $base_url . 'assets/lib/pdf.worker.mjs',
            'gltfLoaderPath'     => $base_url . 'assets/lib/GLTFLoader.js',
            'orbitControlsPath'  => $base_url . 'assets/lib/OrbitControls.js',
            'templatePath'       => $base_url . 'assets/flipbook/tnc-flipbook-template.html',
            'tts' => array(
                'defaultProvider' => $is_pro ? ( $effective['tts_provider'] ?? 'browser' ) : 'browser',
            ),
            'colors' => array(
                'chrome'     => $chrome,
                'brandColor' => $brand_color,
                'colorMode'  => $color_mode,
            ),
        );

        // ── Lite: strip monetization config ─────────────────────────────────
        if ( ! $is_pro ) {
            unset( $config['monetization'] );
            unset( $config['analytics'] );
            unset( $config['ga4MeasurementId'] );
        }

        $options = apply_filters( 'tncfb3d_config_options', $options, $post_id, $config );

        return apply_filters( 'tncfb3d_config_payload', array( 'config' => $config, 'options' => $options ), $post_id );
    }

    /**
     * Set a value at a nested array path.
     */
    private static function set_nested( &$arr, array $path, $value ) {
        $key = array_shift( $path );
        if ( empty( $path ) ) {
            $arr[ $key ] = $value;
        } else {
            if ( ! isset( $arr[ $key ] ) || ! is_array( $arr[ $key ] ) ) {
                $arr[ $key ] = array();
            }
            self::set_nested( $arr[ $key ], $path, $value );
        }
    }
}
