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

class TMNL_Shortcode {

    private $adapters = array();

    private static $female_suffixes = array(
        '子', '美', '花', '華', '恵', '惠', '奈', '菜', '香', '佳',
        '代', '世', '江', '枝', '絵', '里', '理', '織', '乃', '穂',
        '帆', '葉', '実', '未', '望', '歩', '彩', '紗', '咲', '桜',
        '陽', '遥', '凛', '結', '愛', '優', '瑠', '璃', '音', '心',
    );

    private static $male_suffixes = array(
        '男', '雄', '夫', '郎', '朗', '太', '大', '平', '介', '助',
        '輔', '亮', '也', '哉', '樹', '翔', '斗', '人', '仁', '志',
        '司', '史', '嗣', '治', '二', '次', '三', '一', '壱',
    );

    public function __construct() {
        add_shortcode( 'tmnl_kuchikomi_wall', array( $this, 'render' ) );
        add_shortcode( 'tmnl_testimonials', array( $this, 'render' ) ); // backward compat alias
        add_action( 'wp_enqueue_scripts', array( $this, 'register_assets' ) );
        add_action( 'wp_footer', array( $this, 'expand_text_script' ) );
    }

    public function set_adapters( $adapters ) {
        $this->adapters = $adapters;
    }

    public function register_assets() {
        $css_url = TMNL_PLUGIN_URL . 'assets/css/';
        $js_url  = TMNL_PLUGIN_URL . 'assets/js/';
        $ver     = TMNL_VERSION;

        wp_register_style( 'tmnl-card',     $css_url . 'tmnl-card.css',     array(), $ver );
        wp_register_style( 'tmnl-slider',   $css_url . 'tmnl-slider.css',   array(), $ver );
        wp_register_style( 'tmnl-list',     $css_url . 'tmnl-list.css',     array(), $ver );
        wp_register_style( 'tmnl-badge',    $css_url . 'tmnl-badge.css',    array(), $ver );
        wp_register_style( 'tmnl-floating', $css_url . 'tmnl-floating.css', array(), $ver );

        wp_register_script( 'tmnl-slider',   $js_url . 'tmnl-slider.js',   array(), $ver, true );
        wp_register_script( 'tmnl-floating', $js_url . 'tmnl-floating.js', array(), $ver, true );
    }

    private function guess_gender( $name ) {
        $name = trim( $name );
        if ( empty( $name ) ) return null;

        $parts = preg_split( '/[\s　]+/u', $name );
        $given = end( $parts );
        if ( empty( $given ) ) return null;

        $last_char = mb_substr( $given, -1, 1, 'UTF-8' );

        if ( in_array( $last_char, self::$female_suffixes, true ) ) return 'w';
        if ( in_array( $last_char, self::$male_suffixes, true ) ) return 'm';
        return null;
    }

    private function get_avatar_url( $item, $index ) {
        $icons_url = TMNL_PLUGIN_URL . 'assets/icons/';
        $gender    = $this->guess_gender( $item['author_name'] );

        if ( $gender === 'w' ) {
            return $icons_url . 'icon-w' . ( ( $index % 3 ) + 1 ) . '.png';
        } elseif ( $gender === 'm' ) {
            return $icons_url . 'icon-m' . ( ( $index % 3 ) + 1 ) . '.png';
        } else {
            $prefix = ( $index % 2 === 0 ) ? 'm' : 'w';
            $num    = ( intval( $index / 2 ) % 3 ) + 1;
            return $icons_url . 'icon-' . $prefix . $num . '.png';
        }
    }

    /**
     * Render shortcode
     *
     * [tmnl_kuchikomi_wall]
     * [tmnl_kuchikomi_wall limit="6" source="all" template="card" color="light" columns="3"
     *   min_rating="4" show_photo="1" show_date="1" show_source="1" expand_text="0"]
     */
    public function render( $atts ) {
        $atts = shortcode_atts( array(
            'limit'       => get_option( 'tmnl_default_limit', 6 ),
            'source'      => 'all',
            'min_rating'  => get_option( 'tmnl_min_rating', 1 ),
            'columns'     => 3,
            'template'    => get_option( 'tmnl_template', 'card' ),
            'color'       => get_option( 'tmnl_color_scheme', 'light' ),
            'store_id'    => '',
            'show_photo'  => get_option( 'tmnl_show_photo', 1 ),
            'show_date'   => get_option( 'tmnl_show_date', 1 ),
            'show_source' => get_option( 'tmnl_show_source', 1 ),
            'expand_text' => get_option( 'tmnl_expand_text', 0 ),
        ), $atts, 'tmnl_kuchikomi_wall' );

        $limit      = intval( $atts['limit'] );
        $source     = sanitize_text_field( $atts['source'] );
        $min_rating = intval( $atts['min_rating'] );
        $columns    = max( 1, min( 4, intval( $atts['columns'] ) ) );
        $template   = sanitize_text_field( $atts['template'] );
        $color      = sanitize_text_field( $atts['color'] );
        $store_id   = sanitize_key( $atts['store_id'] );
        $opts = array(
            'show_photo'  => (bool) intval( $atts['show_photo'] ),
            'show_date'   => (bool) intval( $atts['show_date'] ),
            'show_source' => (bool) intval( $atts['show_source'] ),
            'expand_text' => (bool) intval( $atts['expand_text'] ),
        );

        // Collect items from adapters
        $items = array();
        foreach ( $this->adapters as $id => $adapter ) {
            if ( $source !== 'all' && $source !== $id ) continue;

            $status = $adapter->get_status();
            if ( ! $status['is_enabled'] ) continue;

            if ( $id === 'google' && $store_id !== '' && method_exists( $adapter, 'get_normalized_reviews' ) ) {
                $reviews = $adapter->get_normalized_reviews( $min_rating, $store_id );
            } else {
                $reviews = $adapter->get_normalized_reviews( $min_rating );
            }
            $items = array_merge( $items, $reviews );
        }

        // Sort: by sort_order then date
        usort( $items, function( $a, $b ) {
            if ( $a['sort_order'] !== $b['sort_order'] ) {
                return $a['sort_order'] - $b['sort_order'];
            }
            return strcmp( $b['date'], $a['date'] );
        });

        if ( $limit > 0 && count( $items ) > $limit ) {
            $items = array_slice( $items, 0, $limit );
        }

        if ( empty( $items ) ) {
            return '';
        }

        $this->enqueue_template_assets( $template, $items );
        $color_class = 'tmnl-color-' . esc_attr( $color );

        switch ( $template ) {
            case 'slider':
                return $this->render_slider( $items, $color_class, $opts );
            case 'list':
                return $this->render_list( $items, $color_class, $opts );
            case 'badge':
                return $this->render_badge( $items, $color_class );
            case 'floating':
                return $this->render_floating( $items, $color_class, $opts );
            case 'card':
            default:
                return $this->render_card_grid( $items, $columns, $color_class, $opts );
        }
    }

    private function enqueue_template_assets( $template, $items ) {
        switch ( $template ) {
            case 'slider':
                wp_enqueue_style( 'tmnl-slider' );
                wp_enqueue_script( 'tmnl-slider' );
                break;
            case 'list':
                wp_enqueue_style( 'tmnl-list' );
                break;
            case 'badge':
                wp_enqueue_style( 'tmnl-badge' );
                break;
            case 'floating':
                wp_enqueue_style( 'tmnl-floating' );
                wp_enqueue_script( 'tmnl-floating' );
                break;
            case 'card':
            default:
                wp_enqueue_style( 'tmnl-card' );
                break;
        }

        $has_embeds = false;
        foreach ( $items as $item ) {
            if ( ! empty( $item['embed_html'] ) ) {
                $has_embeds = true;
                break;
            }
        }
        if ( $has_embeds ) {
            wp_enqueue_script( 'tmnl-x-widgets', 'https://platform.x.com/widgets.js', array(), null, true );
        }
    }

    // =============================================
    // Card Grid Template
    // =============================================

    private function render_card_grid( $items, $columns, $color_class, $opts = array() ) {
        $html = '<div class="tmnl-grid tmnl-cols-' . $columns . ' ' . $color_class . '">';
        foreach ( $items as $index => $item ) {
            $html .= $this->render_card_item( $item, $index, $opts );
        }
        $html .= '</div>';
        return $html;
    }

    private function render_card_item( $item, $index, $opts = array() ) {
        $show_photo  = $opts['show_photo']  ?? true;
        $show_date   = $opts['show_date']   ?? true;
        $show_source = $opts['show_source'] ?? true;
        $expand_text = $opts['expand_text'] ?? false;

        if ( ! empty( $item['embed_html'] ) ) {
            $source_badge = $show_source ? '<span class="tmnl-source">' . esc_html( $item['source_label'] ) . '</span>' : '';
            return '
            <div class="tmnl-card">
                <div class="tmnl-card-header">' . $source_badge . '</div>
                <div class="tmnl-embed-wrap">' . wp_kses_post( $item['embed_html'] ) . '</div>
            </div>';
        }

        $stars = $this->render_stars( $item['rating'] );

        $source_badge = '';
        if ( $show_source && ! empty( $item['source_label'] ) ) {
            $source_badge = '<span class="tmnl-source">' . esc_html( $item['source_label'] ) . '</span>';
        }

        $date_html = '';
        if ( $show_date && ! empty( $item['date'] ) ) {
            $date_html = '<span class="tmnl-date">' . esc_html( $item['date'] ) . '</span>';
        }

        $avatar_html = '';
        if ( $show_photo ) {
            $avatar_url  = ! empty( $item['author_icon'] ) ? $item['author_icon'] : $this->get_avatar_url( $item, $index );
            $avatar_html = '<img src="' . esc_url( $avatar_url ) . '" alt="" class="tmnl-avatar">';
        }

        $text_html = $this->render_text( $item['text'], $index, $expand_text );

        return '
        <div class="tmnl-card">
            <div class="tmnl-card-header">
                ' . $stars . '
                ' . $source_badge . '
            </div>
            <div class="tmnl-card-body">
                ' . $text_html . '
            </div>
            <div class="tmnl-card-footer">
                <div class="tmnl-author-info">
                    ' . $avatar_html . '
                    <span class="tmnl-author">' . esc_html( $item['author_name'] ) . '</span>
                </div>
                ' . $date_html . '
            </div>
        </div>';
    }

    // =============================================
    // Slider Template
    // =============================================

    private function render_slider( $items, $color_class, $opts = array() ) {
        $html = '<div class="tmnl-slider-wrap ' . $color_class . '">';
        $html .= '<div class="tmnl-slider-track">';

        foreach ( $items as $index => $item ) {
            $html .= '<div class="tmnl-slide">';
            $html .= $this->render_slide_item( $item, $index, $opts );
            $html .= '</div>';
        }

        $html .= '</div>';

        if ( count( $items ) > 1 ) {
            $html .= '<button class="tmnl-slider-nav tmnl-slider-prev" aria-label="' . esc_attr__( 'Previous', 'elplan-kuchikomi-wall' ) . '">&#8249;</button>';
            $html .= '<button class="tmnl-slider-nav tmnl-slider-next" aria-label="' . esc_attr__( 'Next', 'elplan-kuchikomi-wall' ) . '">&#8250;</button>';

            $html .= '<div class="tmnl-slider-dots">';
            foreach ( $items as $i => $item ) {
                $active = $i === 0 ? ' active' : '';
                /* translators: %d: slide number */
                $html .= '<button class="tmnl-slider-dot' . $active . '" aria-label="' . esc_attr( sprintf( __( 'Slide %d', 'elplan-kuchikomi-wall' ), $i + 1 ) ) . '"></button>';
            }
            $html .= '</div>';
        }

        $html .= '</div>';
        return $html;
    }

    private function render_slide_item( $item, $index, $opts = array() ) {
        $show_photo  = $opts['show_photo']  ?? true;
        $show_date   = $opts['show_date']   ?? true;
        $show_source = $opts['show_source'] ?? true;

        $html = '<div class="tmnl-slide-inner">';

        if ( ! empty( $item['embed_html'] ) ) {
            $html .= '<div class="tmnl-embed-wrap">' . wp_kses_post( $item['embed_html'] ) . '</div>';
        } else {
            $html .= $this->render_stars( $item['rating'] );
            $html .= '<p class="tmnl-text">' . esc_html( $item['text'] ) . '</p>';

            $html .= '<div class="tmnl-author-info">';
            if ( $show_photo ) {
                $avatar_url = ! empty( $item['author_icon'] ) ? $item['author_icon'] : $this->get_avatar_url( $item, $index );
                $html      .= '<img src="' . esc_url( $avatar_url ) . '" alt="" class="tmnl-avatar">';
            }
            $html .= '<span class="tmnl-author">' . esc_html( $item['author_name'] ) . '</span>';
            if ( $show_source && ! empty( $item['source_label'] ) ) {
                $html .= '<span class="tmnl-source">' . esc_html( $item['source_label'] ) . '</span>';
            }
            $html .= '</div>';

            if ( $show_date && ! empty( $item['date'] ) ) {
                $html .= '<div class="tmnl-date">' . esc_html( $item['date'] ) . '</div>';
            }
        }

        $html .= '</div>';
        return $html;
    }

    // =============================================
    // List Template
    // =============================================

    private function render_list( $items, $color_class, $opts = array() ) {
        $html = '<div class="tmnl-list ' . $color_class . '">';
        foreach ( $items as $index => $item ) {
            $html .= $this->render_list_item( $item, $index, $opts );
        }
        $html .= '</div>';
        return $html;
    }

    private function render_list_item( $item, $index, $opts = array() ) {
        $show_photo  = $opts['show_photo']  ?? true;
        $show_date   = $opts['show_date']   ?? true;
        $show_source = $opts['show_source'] ?? true;
        $expand_text = $opts['expand_text'] ?? false;

        if ( ! empty( $item['embed_html'] ) ) {
            $source_badge = $show_source ? '<span class="tmnl-source">' . esc_html( $item['source_label'] ) . '</span>' : '';
            return '<div class="tmnl-list-item">
                <div class="tmnl-list-content">
                    <div class="tmnl-list-meta">' . $source_badge . '</div>
                    <div class="tmnl-embed-wrap">' . wp_kses_post( $item['embed_html'] ) . '</div>
                </div>
            </div>';
        }

        $avatar_url = ! empty( $item['author_icon'] ) ? $item['author_icon'] : $this->get_avatar_url( $item, $index );

        $html = '<div class="tmnl-list-item">';
        if ( $show_photo ) {
            $html .= '<div class="tmnl-list-avatar"><img src="' . esc_url( $avatar_url ) . '" alt="" class="tmnl-avatar"></div>';
        }
        $html .= '<div class="tmnl-list-content">';
        $html .= '<div class="tmnl-list-meta">';
        $html .= '<span class="tmnl-author">' . esc_html( $item['author_name'] ) . '</span>';
        if ( $item['rating'] ) {
            $html .= $this->render_stars( $item['rating'] );
        }
        if ( $show_source && ! empty( $item['source_label'] ) ) {
            $html .= '<span class="tmnl-source">' . esc_html( $item['source_label'] ) . '</span>';
        }
        if ( $show_date && ! empty( $item['date'] ) ) {
            $html .= '<span class="tmnl-date">' . esc_html( $item['date'] ) . '</span>';
        }
        $html .= '</div>';
        $html .= $this->render_text( $item['text'], $index, $expand_text, 'tmnl-list-text' );
        $html .= '</div>';
        $html .= '</div>';

        return $html;
    }

    // =============================================
    // Badge Template
    // =============================================

    private function render_badge( $items, $color_class ) {
        $total = count( $items );
        $sum   = 0;
        foreach ( $items as $item ) {
            $sum += floatval( $item['rating'] ?? 0 );
        }
        $avg = $total > 0 ? round( $sum / $total, 1 ) : 0;

        $source_label = '';
        foreach ( $items as $item ) {
            if ( ! empty( $item['source_label'] ) ) {
                $source_label = $item['source_label'];
                break;
            }
        }

        $count_text = sprintf(
            /* translators: %d: review count */
            _n( '%d review', '%d reviews', $total, 'elplan-kuchikomi-wall' ),
            $total
        );

        return '
        <div class="tmnl-badge-widget ' . $color_class . '">
            <div class="tmnl-badge-inner">
                <div class="tmnl-badge-score">
                    <span class="tmnl-badge-rating">' . esc_html( number_format( $avg, 1 ) ) . '</span>
                    <div>
                        <div class="tmnl-badge-stars">' . $this->render_stars_decimal( $avg ) . '</div>
                        <span class="tmnl-badge-count">' . esc_html( $count_text ) . '</span>
                    </div>
                </div>
                ' . ( $source_label ? '<div class="tmnl-badge-source">' . esc_html( $source_label ) . '</div>' : '' ) . '
            </div>
        </div>';
    }

    // =============================================
    // Floating Template
    // =============================================

    private function render_floating( $items, $color_class, $opts = array() ) {
        $show_photo = $opts['show_photo'] ?? true;
        $show_date  = $opts['show_date']  ?? true;

        // Build JSON data for JS (exclude embed-only items)
        $reviews_data = array();
        foreach ( $items as $index => $item ) {
            if ( ! empty( $item['embed_html'] ) ) continue;
            $avatar_url = ! empty( $item['author_icon'] ) ? $item['author_icon'] : $this->get_avatar_url( $item, $index );
            $reviews_data[] = array(
                'author' => $item['author_name'],
                'rating' => intval( $item['rating'] ),
                'text'   => mb_substr( $item['text'], 0, 120 ),
                'date'   => $item['date'] ?? '',
                'icon'   => $avatar_url,
            );
        }

        if ( empty( $reviews_data ) ) return '';

        $first = $reviews_data[0];
        $uid   = 'tmnl-float-' . wp_rand( 1000, 9999 );
        $json  = wp_json_encode( $reviews_data, JSON_UNESCAPED_UNICODE );

        $avatar_html = '';
        if ( $show_photo ) {
            $avatar_html = '<img src="' . esc_url( $first['icon'] ) . '" alt="" class="tmnl-floating-avatar">';
        }

        $date_html = '';
        if ( $show_date && ! empty( $first['date'] ) ) {
            $date_html = '<span class="tmnl-floating-date">' . esc_html( $first['date'] ) . '</span>';
        }

        return '
        <div class="tmnl-floating-widget ' . $color_class . '" id="' . esc_attr( $uid ) . '"
             data-reviews="' . esc_attr( $json ) . '"
             data-show-photo="' . ( $show_photo ? '1' : '0' ) . '"
             data-show-date="' . ( $show_date ? '1' : '0' ) . '">
            <button class="tmnl-floating-close" aria-label="' . esc_attr__( 'Close', 'elplan-kuchikomi-wall' ) . '">&times;</button>
            <div class="tmnl-floating-content">
                <div class="tmnl-floating-author">
                    ' . $avatar_html . '
                    <div class="tmnl-floating-meta">
                        <span class="tmnl-floating-name">' . esc_html( $first['author'] ) . '</span>
                        ' . $this->render_stars( $first['rating'] ) . '
                    </div>
                </div>
                <p class="tmnl-floating-text">' . esc_html( $first['text'] ) . '</p>
                ' . $date_html . '
            </div>
            <div class="tmnl-floating-nav">
                <span class="tmnl-floating-counter">1 / ' . count( $reviews_data ) . '</span>
                <div class="tmnl-floating-nav-btns">
                    <button class="tmnl-float-prev" aria-label="' . esc_attr__( 'Previous', 'elplan-kuchikomi-wall' ) . '">&#8249;</button>
                    <button class="tmnl-float-next" aria-label="' . esc_attr__( 'Next', 'elplan-kuchikomi-wall' ) . '">&#8250;</button>
                </div>
            </div>
        </div>';
    }

    // =============================================
    // Helpers
    // =============================================

    private function render_stars( $rating ) {
        if ( ! $rating ) return '';
        $html = '<span class="tmnl-stars">';
        for ( $i = 1; $i <= 5; $i++ ) {
            $html .= ( $i <= $rating ) ? '★' : '☆';
        }
        $html .= '</span>';
        return $html;
    }

    private function render_stars_decimal( $avg ) {
        $html = '<span class="tmnl-stars">';
        for ( $i = 1; $i <= 5; $i++ ) {
            if ( $avg >= $i ) {
                $html .= '★';
            } elseif ( $avg >= $i - 0.5 ) {
                $html .= '<span class="tmnl-star-half">★</span>';
            } else {
                $html .= '☆';
            }
        }
        $html .= '</span>';
        return $html;
    }

    private function render_text( $text, $index, $expand = false, $class = 'tmnl-text' ) {
        if ( $expand && mb_strlen( $text ) > 100 ) {
            $uid = 'tmnl-expand-' . $index . '-' . substr( md5( $text ), 0, 6 );
            return '<p class="' . esc_attr( $class ) . '">'
                . esc_html( mb_substr( $text, 0, 100 ) )
                . '<span class="tmnl-text-more" id="' . esc_attr( $uid ) . '" style="display:none;">'
                . esc_html( mb_substr( $text, 100 ) )
                . '</span>'
                . '<a href="#" class="tmnl-expand-toggle" data-target="' . esc_attr( $uid ) . '">…'
                . esc_html__( 'more', 'elplan-kuchikomi-wall' )
                . '</a></p>';
        }
        return '<p class="' . esc_attr( $class ) . '">' . esc_html( $text ) . '</p>';
    }

    public function expand_text_script() {
        // Output inline JS only if expand_text option is active anywhere
        if ( ! get_option( 'tmnl_expand_text', 0 ) ) return;
        ?>
        <script>
        (function(){
            document.addEventListener('click', function(e){
                var t = e.target;
                if ( t.classList && t.classList.contains('tmnl-expand-toggle') ) {
                    e.preventDefault();
                    var el = document.getElementById( t.dataset.target );
                    if ( el ) {
                        el.style.display = el.style.display === 'none' ? 'inline' : 'none';
                        t.style.display = 'none';
                    }
                }
            });
        })();
        </script>
        <?php
    }
}
