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

/**
 * Public-facing functionality and shortcode rendering.
 * Lite version: displays full table with Excel cell formatting applied.
 * No sort/filter/search/pagination.
 */
class CDTV_Public {

    private $plugin_name;
    private $version;

    public function __construct( $plugin_name, $version ) {
        $this->plugin_name = $plugin_name;
        $this->version     = $version;
    }

    /* -----------------------------------------------------------------------
     * Assets – loaded only on pages containing the shortcode
     * -------------------------------------------------------------------- */

    private function should_enqueue(): bool {
        if ( ! is_singular() ) return false;
        global $post;
        if ( ! ( $post instanceof WP_Post ) ) return false;
        if ( has_shortcode( $post->post_content, 'cdtv' ) ) return true;
        foreach ( get_post_meta( $post->ID ) as $values ) {
            foreach ( (array) $values as $value ) {
                if ( is_string( $value ) && false !== strpos( $value, '[cdtv' ) ) {
                    return true;
                }
            }
        }
        return false;
    }

    public function enqueue_styles() {
        if ( is_admin() ) return;
        wp_enqueue_style(
            $this->plugin_name,
            CDTV_PLUGIN_URL . 'public/css/cdtv-public.css',
            array(),
            $this->version
        );
        // Output global design CSS as inline style on top of base CSS
        if ( cdtv_is_licensed() ) {
            $global_css = (string) get_option( 'cdtv_global_design_css', '' );
            if ( $global_css ) {
                wp_add_inline_style( $this->plugin_name, wp_strip_all_tags( $global_css ) );
            }
        }
    }

    public function enqueue_scripts() {
        if ( is_admin() ) return;
        wp_enqueue_script(
            $this->plugin_name,
            CDTV_PLUGIN_URL . 'public/js/cdtv-public.js',
            array(),
            $this->version,
            true
        );
    }

    /* -----------------------------------------------------------------------
     * Shortcode [cdtv id="X"]
     * -------------------------------------------------------------------- */

    public function register_shortcode() {
        add_shortcode( 'cdtv', array( $this, 'shortcode_handler' ) );
    }

    public function shortcode_handler( $atts ) {
        $atts     = shortcode_atts( array( 'id' => 0 ), $atts, 'cdtv' );
        $table_id = absint( $atts['id'] );
        if ( ! $table_id ) return '';

        $parsed = get_post_meta( $table_id, '_cdtv_parsed_data', true );
        if ( empty( $parsed ) ) return '';

        return $this->render_table( $table_id, $parsed );
    }

    /* -----------------------------------------------------------------------
     * Inline style builder helpers
     * -------------------------------------------------------------------- */

    /**
     * Build an inline CSS style string from a cell-style array.
     *
     * @param array|null $style  { bg, color, bold, italic, underline, font_name }
     * @param string     $halign 'left'|'right'|'center'|'justify'|'general'
     * @return string  Ready for use in style="..."
     */
    private function build_inline_style( $style, string $halign = 'general' ): string {
        $parts = array();

        if ( 'general' !== $halign && '' !== $halign ) {
            // 'center', 'left', 'right', 'justify' map directly to CSS
            $parts[] = 'text-align:' . esc_attr( $halign );
        }

        if ( ! is_array( $style ) ) {
            return implode( ';', $parts );
        }

        if ( ! empty( $style['bg'] ) ) {
            $parts[] = 'background-color:' . esc_attr( $style['bg'] );
        }
        if ( ! empty( $style['color'] ) ) {
            $parts[] = 'color:' . esc_attr( $style['color'] );
        }
        if ( ! empty( $style['bold'] ) ) {
            $parts[] = 'font-weight:bold';
        }
        if ( ! empty( $style['italic'] ) ) {
            $parts[] = 'font-style:italic';
        }
        if ( ! empty( $style['underline'] ) ) {
            $parts[] = 'text-decoration:underline';
        }
        if ( ! empty( $style['font_name'] ) ) {
            // Wrap font name in quotes; safe because we esc_attr the whole string.
            $parts[] = 'font-family:"' . esc_attr( $style['font_name'] ) . '",sans-serif';
        }
        if ( ! empty( $style['size'] ) && $style['size'] > 0 ) {
            // Excel font sizes are in pt – pass through to CSS as pt
            $parts[] = 'font-size:' . (float) $style['size'] . 'pt';
        }

        return implode( ';', $parts );
    }

    /**
     * Build a border CSS block from stored border settings.
     *
     * @param array $b Border settings: { preset, style, color, width }
     * @return string  CSS properties (no selector/braces)
     */
    private function build_border_css( array $b ): string {
        $preset = $b['preset'] ?? 'none';
        if ( 'none' === $preset ) {
            return 'border:none;';
        }

        $style = in_array( $b['style'] ?? '', array( 'solid', 'dashed', 'dotted', 'double' ), true )
            ? $b['style'] : 'solid';
        $color = preg_match( '/^#[0-9a-fA-F]{3,6}$/', $b['color'] ?? '' )
            ? $b['color'] : '#dddddd';
        $width = max( 1, min( 5, (int) ( $b['width'] ?? 1 ) ) ) . 'px';

        $rule = "{$width} {$style} {$color}";

        if ( 'outer' === $preset ) {
            return "border:{$rule};border-collapse:collapse;";
        }
        // 'all' = outer border + cell borders
        return "border:{$rule};border-collapse:collapse;";
    }

    /* -----------------------------------------------------------------------
     * Decimal separator
     * -------------------------------------------------------------------- */

    /**
     * Replace "." with the configured separator in plain decimal numbers.
     * Does not touch dates, URLs, or already-formatted strings.
     */
    private function apply_decimal_separator( string $cell, string $target_sep ): string {
        if ( '.' === $target_sep ) {
            return $cell;
        }
        if ( preg_match( '/^-?\d{1,3}(?:\.\d+)?$/', trim( $cell ) ) ) {
            return str_replace( '.', $target_sep, $cell );
        }
        return $cell;
    }

    /* -----------------------------------------------------------------------
     * Table Rendering
     * -------------------------------------------------------------------- */

    public function render_table( $table_id, $parsed ) {
        $is_pro           = cdtv_is_licensed();
        $headers          = $parsed['headers']       ?? array();
        $all_rows         = $parsed['rows']          ?? array();
        $col_widths       = $parsed['col_widths']    ?? array();
        $col_haligns      = $parsed['col_haligns']   ?? array();
        $cell_haligns     = $parsed['cell_haligns']  ?? array();  // sparse [row][col] => halign (always available)
        $header_styles_raw = $parsed['header_styles'] ?? array(); // full styles including alignment
        // Pro: apply full Excel formatting only when the per-table toggle is enabled.
        $enable_excel_format = $is_pro && (bool) get_post_meta( $table_id, '_cdtv_enable_excel_format', true );
        $cell_styles    = $enable_excel_format ? ( $parsed['cell_styles'] ?? array() ) : array();
        $header_styles  = $enable_excel_format ? $header_styles_raw : array();
        $custom_css     = (string) get_post_meta( $table_id, '_cdtv_custom_css', true );
        $border_raw     = get_post_meta( $table_id, '_cdtv_border_settings', true );
        $border         = is_array( $border_raw ) ? $border_raw : array();
        $decimal_sep    = (string) get_option( 'cdtv_decimal_separator', '.' );
        $rows_per_page   = max( 0, (int) get_post_meta( $table_id, '_cdtv_rows_per_page', true ) );
        $scroll_mode_raw = (string) get_post_meta( $table_id, '_cdtv_scroll_mode', true );
        $scroll_mode     = in_array( $scroll_mode_raw, array( 'auto', 'always', 'off' ), true ) ? $scroll_mode_raw : 'auto';
        $reset_styles    = (bool) get_post_meta( $table_id, '_cdtv_reset_styles', true );
        $enable_search   = $is_pro && (bool) get_post_meta( $table_id, '_cdtv_enable_search', true );
        $enable_sort     = $is_pro && (bool) get_post_meta( $table_id, '_cdtv_enable_sort',   true );
        $filter_cols_raw = $is_pro ? (string) get_post_meta( $table_id, '_cdtv_filter_cols', true ) : '';
        $filter_cols     = $filter_cols_raw !== '' ? $filter_cols_raw : '';
        $sort_style_raw  = $is_pro ? (string) get_post_meta( $table_id, '_cdtv_sort_indicator_style', true ) : 'badge';
        $sort_style      = in_array( $sort_style_raw, array( 'badge', 'outline', 'text', 'none' ), true ) ? $sort_style_raw : 'badge';
        // If reset_styles is active, ignore Excel cell formatting even in Pro
        if ( $reset_styles ) {
            $cell_styles   = array();
            $header_styles = array();
        }
        $wrap_id = 'cdtv-table-' . $table_id;

        // --- Build border CSS ---
        $border_css = '';
        if ( ! empty( $border ) && ( $border['preset'] ?? 'none' ) !== 'none' ) {
            $preset = $border['preset'] ?? 'all';
            $style  = in_array( $border['style'] ?? '', array( 'solid', 'dashed', 'dotted', 'double' ), true )
                ? $border['style'] : 'solid';
            $color  = preg_match( '/^#[0-9a-fA-F]{3,6}$/', $border['color'] ?? '' )
                ? $border['color'] : '#dddddd';
            $width  = max( 1, min( 5, (int) ( $border['width'] ?? 1 ) ) ) . 'px';
            $rule   = "{$width} {$style} {$color}";

            if ( 'outer' === $preset ) {
                $border_css = "#{$wrap_id} .cdtv-table { border: {$rule}; border-collapse: collapse; }";
            } else {
                // 'all' = every cell border
                $border_css = "#{$wrap_id} .cdtv-table { border-collapse: collapse; }"
                    . " #{$wrap_id} .cdtv-table th, #{$wrap_id} .cdtv-table td { border: {$rule}; }";
            }
        }

        ob_start();
        ?>
        <div class="cdtv-table-wrap cdtv-scroll-<?php echo esc_attr( $scroll_mode ); ?>" id="<?php echo esc_attr( $wrap_id ); ?>"<?php echo $rows_per_page > 0 ? ' data-rows-per-page="' . esc_attr( $rows_per_page ) . '"' : ''; ?><?php echo $enable_search ? ' data-search="1"' : ''; ?><?php echo $enable_sort ? ' data-sort="1"' : ''; ?><?php echo $filter_cols !== '' ? ' data-filter-cols="' . esc_attr( $filter_cols ) . '"' : ''; ?><?php echo $enable_sort ? ' data-sort-style="' . esc_attr( $sort_style ) . '"' : ''; ?>>
            <?php
            /*
             * Scoped <style> in the body – valid HTML5.
             * Always output so scroll-mode, pagination and custom CSS rules
             * are reliably applied regardless of other settings.
             * wp_add_inline_style() cannot be used here because shortcodes
             * execute after wp_head has already fired.
             */
            ?>
            <style>
                <?php if ( $custom_css ) :
                    $scoped_css = str_replace(
                        '.cdtv-table',
                        '#' . esc_attr( $wrap_id ) . ' .cdtv-table',
                        wp_strip_all_tags( $custom_css )
                    );
                    echo $scoped_css; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- sanitized above
                endif; ?>
                <?php if ( $border_css ) :
                    echo wp_strip_all_tags( $border_css ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- built from sanitized values
                endif; ?>
                <?php if ( 'off' !== $scroll_mode ) : ?>
                #<?php echo esc_attr( $wrap_id ); ?> { overflow-x: <?php echo 'always' === $scroll_mode ? 'scroll' : 'auto'; ?> !important; }
                #<?php echo esc_attr( $wrap_id ); ?> .cdtv-table-scroll { overflow-x: <?php echo 'always' === $scroll_mode ? 'scroll' : 'auto'; ?> !important; }
                <?php endif; ?>
                <?php if ( $rows_per_page > 0 ) :
                    $first_hidden = $rows_per_page + 1;
                ?>
                #<?php echo esc_attr( $wrap_id ); ?> .cdtv-table tbody tr:nth-child(n+<?php echo (int) $first_hidden; ?>) { display: none; }
                <?php endif; ?>
            </style>

            <div class="cdtv-table-scroll cdtv-scroll-<?php echo esc_attr( $scroll_mode ); ?>">
                <table class="cdtv-table">
                    <?php if ( ! empty( $col_widths ) ) : ?>
                    <colgroup>
                        <?php foreach ( $col_widths as $w ) : ?>
                        <col <?php echo $w ? 'style="width:' . esc_attr( $w ) . 'px"' : ''; ?>>
                        <?php endforeach; ?>
                    </colgroup>
                    <?php endif; ?>

                    <?php if ( ! empty( $headers ) ) : ?>
                    <thead>
                        <tr>
                            <?php foreach ( $headers as $col_idx => $header ) :
                                $h_style_raw = $header_styles_raw[ $col_idx ] ?? null;
                                $h_style     = $header_styles[ $col_idx ] ?? null; // null for Lite
                                $h_align     = is_array( $h_style_raw ) ? ( $h_style_raw['halign'] ?? 'general' ) : 'general';
                                // Strip color and bg from Excel header styles.
                                // Design Generator CSS is the authority for header colors;
                                // Excel's "automatic" font color (usually #000000) must not
                                // override the Designer's chosen text color via inline style.
                                $h_style_filtered = is_array( $h_style )
                                    ? array_diff_key( $h_style, array_flip( array( 'color', 'bg' ) ) )
                                    : $h_style;
                                $h_inline    = $this->build_inline_style( $h_style_filtered, $h_align );
                            ?>
                            <th<?php echo $h_inline ? ' style="' . esc_attr( $h_inline ) . '"' : ''; ?>>
                                <?php echo esc_html( $header ); ?>
                            </th>
                            <?php endforeach; ?>
                        </tr>
                    </thead>
                    <?php endif; ?>

                    <tbody>
                        <?php if ( empty( $all_rows ) ) : ?>
                        <tr>
                            <td colspan="<?php echo esc_attr( max( 1, count( $headers ) ) ); ?>">
                                <?php esc_html_e( 'No data available.', 'codede-table-viewer' ); ?>
                            </td>
                        </tr>
                        <?php else : ?>
                            <?php foreach ( $all_rows as $row_idx => $row ) : ?>
                            <tr>
                                <?php foreach ( $row as $col_idx => $cell ) :
                                    // Alignment: per-cell overrides column-level default
                                    $halign = $cell_haligns[ $row_idx ][ $col_idx ]
                                        ?? $col_haligns[ $col_idx ]
                                        ?? 'general';
                                    // Visual style: bg, font color, bold, italic, etc.
                                    $cstyle  = $cell_styles[ $row_idx ][ $col_idx ] ?? null;
                                    $inline  = $this->build_inline_style( $cstyle, $halign );
                                    $display = $this->apply_decimal_separator( $cell, $decimal_sep );
                                ?>
                                <td<?php echo $inline ? ' style="' . esc_attr( $inline ) . '"' : ''; ?>>
                                    <?php echo esc_html( $display ); ?>
                                </td>
                                <?php endforeach; ?>
                            </tr>
                            <?php endforeach; ?>
                        <?php endif; ?>
                    </tbody>
                </table>
            </div><!-- .cdtv-table-scroll -->
        </div><!-- .cdtv-table-wrap -->
        <?php
        return ob_get_clean();
    }
}
