<?php
/**
 * LinkQuiver Theme Shortcodes
 *
 * Dynamic building blocks resolved at render time inside the HTML pushed to
 * the Theme Engine. Shortcodes are replaced server-side before output, so the
 * tag names never reach the public HTML. Output carries conventional class
 * hooks only (no branded prefix, no inline styling) — the pushed CSS fully
 * owns the visual presentation.
 *
 * Shortcodes (all also registered without the lq_ prefix when free):
 * - [lq_recent_posts limit="6" category="slug" columns="3" show_excerpt="1" show_date="1" show_category="1"]
 *   → .posts-grid, .post-card(-link/media/category/body/title/date/excerpt)
 * - [lq_categories limit="8" show_count="1" show_description="0"]
 *   → .category-list, .category-list-item(/name/count/desc)
 * - [lq_menu location="primary" class="nav-menu"]
 * - [lq_site_logo class="site-logo" width="" height=""]
 * - [lq_site_title]  → .site-title
 * - [lq_site_tagline]  → .site-description
 *
 * @package Linkquiver
 */

if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

class Linkquiver_Theme_Shortcodes {

    public function init() {
        $map = array(
            'recent_posts' => 'recent_posts_handler',
            'categories'   => 'categories_handler',
            'menu'         => 'menu_handler',
            'site_logo'    => 'site_logo_handler',
            'site_title'   => 'site_title_handler',
            'site_tagline' => 'site_tagline_handler',
        );

        foreach ( $map as $tag => $handler ) {
            add_shortcode( 'lq_' . $tag, array( $this, $handler ) );
            // Friendly unprefixed alias when no other plugin claimed it.
            if ( ! shortcode_exists( $tag ) ) {
                add_shortcode( $tag, array( $this, $handler ) );
            }
        }
    }

    /**
     * Recent posts grid — category filter, columns, thumbnail, badge,
     * excerpt, date. Reuses the same .post-card hooks as the archive grid.
     */
    public function recent_posts_handler( $atts ) {
        $atts = shortcode_atts( array(
            'limit'         => 6,
            'category'      => '',  // slug or comma-separated slugs
            'columns'       => 3,   // 1..6
            'offset'        => 0,
            'show_excerpt'  => 1,
            'show_date'     => 1,
            'show_category' => 1,
            'class'         => 'posts-grid',
        ), $atts, 'lq_recent_posts' );

        $limit   = max( 1, min( 24, (int) $atts['limit'] ) );
        $columns = max( 1, min( 6, (int) $atts['columns'] ) );

        $query_args = array(
            'post_type'      => 'post',
            'post_status'    => 'publish',
            'posts_per_page' => $limit,
            'offset'         => max( 0, (int) $atts['offset'] ),
            'orderby'        => 'date',
            'order'          => 'DESC',
        );

        if ( ! empty( $atts['category'] ) ) {
            $slugs = array_filter( array_map( 'trim', explode( ',', $atts['category'] ) ) );
            if ( ! empty( $slugs ) ) {
                $query_args['category_name'] = implode( ',', $slugs );
            }
        }

        $posts = get_posts( $query_args );
        if ( empty( $posts ) ) {
            return '';
        }

        $wrapper_class = esc_attr( $atts['class'] ) . ' ' . esc_attr( $atts['class'] ) . '--cols-' . $columns;
        $html = '<div class="' . $wrapper_class . '" data-columns="' . esc_attr( $columns ) . '">';

        foreach ( $posts as $p ) {
            $thumb       = get_the_post_thumbnail_url( $p, 'large' ) ?: '';
            $cats        = get_the_category( $p->ID );
            $primary_cat = ! empty( $cats ) ? $cats[0] : null;

            $html .= '<article class="post-card">';
            $html .= '<a class="post-card-link" href="' . esc_url( get_permalink( $p ) ) . '">';

            if ( $thumb ) {
                $html .= '<div class="post-card-media">';
                $html .= '<img src="' . esc_url( $thumb ) . '" alt="' . esc_attr( get_the_title( $p ) ) . '" loading="lazy" />';
                if ( (int) $atts['show_category'] && $primary_cat ) {
                    $html .= '<span class="post-card-category">' . esc_html( $primary_cat->name ) . '</span>';
                }
                $html .= '</div>';
            }

            $html .= '<div class="post-card-body">';
            $html .= '<h3 class="post-card-title">' . esc_html( get_the_title( $p ) ) . '</h3>';

            if ( (int) $atts['show_date'] ) {
                $html .= '<time class="post-card-date" datetime="' . esc_attr( get_the_date( 'c', $p ) ) . '">' . esc_html( get_the_date( '', $p ) ) . '</time>';
            }

            if ( (int) $atts['show_excerpt'] ) {
                $excerpt = wp_strip_all_tags( get_the_excerpt( $p ) );
                if ( $excerpt ) {
                    $html .= '<p class="post-card-excerpt">' . esc_html( wp_trim_words( $excerpt, 22, '…' ) ) . '</p>';
                }
            }

            $html .= '</div>';
            $html .= '</a>';
            $html .= '</article>';
        }

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

    /**
     * Categories grid — real WordPress categories, no custom tables.
     */
    public function categories_handler( $atts ) {
        $atts = shortcode_atts( array(
            'limit'            => 8,
            'show_count'       => 1,
            'show_description' => 0,
            'class'            => 'category-list',
        ), $atts, 'lq_categories' );

        $cats = get_categories( array(
            'hide_empty' => true,
            'number'     => max( 1, min( 24, (int) $atts['limit'] ) ),
            'orderby'    => 'count',
            'order'      => 'DESC',
        ) );

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

        $html = '<div class="' . esc_attr( $atts['class'] ) . '">';
        foreach ( $cats as $cat ) {
            $html .= '<a class="category-list-item" href="' . esc_url( get_category_link( $cat ) ) . '">';
            $html .= '<span class="category-list-name">' . esc_html( $cat->name ) . '</span>';
            if ( (int) $atts['show_count'] ) {
                $html .= '<span class="category-list-count">' . (int) $cat->count . '</span>';
            }
            if ( (int) $atts['show_description'] && $cat->description ) {
                $html .= '<span class="category-list-desc">' . esc_html( $cat->description ) . '</span>';
            }
            $html .= '</a>';
        }
        $html .= '</div>';
        return $html;
    }

    /**
     * Navigation menu by theme location (falls back to the page list so a
     * fresh site without menus still renders a usable nav).
     */
    public function menu_handler( $atts ) {
        $atts = shortcode_atts( array(
            'location' => 'primary',
            'menu'     => '',
            'class'    => 'nav-menu',
        ), $atts, 'lq_menu' );

        $args = array(
            'container'      => 'nav',
            'container_class'=> esc_attr( $atts['class'] ),
            'menu_class'     => esc_attr( $atts['class'] ) . '-list',
            'echo'           => false,
            'fallback_cb'    => false,
            'depth'          => 2,
        );

        if ( ! empty( $atts['menu'] ) ) {
            $args['menu'] = $atts['menu'];
        } elseif ( has_nav_menu( $atts['location'] ) ) {
            $args['theme_location'] = $atts['location'];
        } else {
            // Use the first menu that exists, whatever its location.
            $menus = wp_get_nav_menus();
            if ( ! empty( $menus ) ) {
                $args['menu'] = $menus[0]->term_id;
            }
        }

        $out = wp_nav_menu( $args );
        if ( $out ) return $out;

        // Last-resort fallback: pages list.
        $pages = wp_list_pages( array( 'echo' => false, 'title_li' => '' ) );
        if ( ! $pages ) return '';
        return '<nav class="' . esc_attr( $atts['class'] ) . '"><ul class="' . esc_attr( $atts['class'] ) . '-list">' . $pages . '</ul></nav>';
    }

    /**
     * Customizer logo as <img>, or linked site title fallback.
     */
    public function site_logo_handler( $atts ) {
        $atts = shortcode_atts( array(
            'class'  => 'site-logo',
            'width'  => '',
            'height' => '',
        ), $atts, 'lq_site_logo' );

        $logo_id = get_theme_mod( 'custom_logo' );
        if ( $logo_id ) {
            $url = wp_get_attachment_image_url( $logo_id, 'full' );
            if ( $url ) {
                $dims = '';
                if ( $atts['width'] )  $dims .= ' width="' . esc_attr( $atts['width'] ) . '"';
                if ( $atts['height'] ) $dims .= ' height="' . esc_attr( $atts['height'] ) . '"';
                return '<a href="' . esc_url( home_url( '/' ) ) . '" class="' . esc_attr( $atts['class'] ) . '-link" aria-label="' . esc_attr( get_bloginfo( 'name' ) ) . '">'
                    . '<img src="' . esc_url( $url ) . '" alt="' . esc_attr( get_bloginfo( 'name' ) ) . '" class="' . esc_attr( $atts['class'] ) . '"' . $dims . ' />'
                    . '</a>';
            }
        }
        return '<a href="' . esc_url( home_url( '/' ) ) . '" class="' . esc_attr( $atts['class'] ) . '-text">' . esc_html( get_bloginfo( 'name' ) ) . '</a>';
    }

    public function site_title_handler( $atts ) {
        $atts = shortcode_atts( array( 'class' => 'site-title' ), $atts, 'lq_site_title' );
        return '<span class="' . esc_attr( $atts['class'] ) . '">' . esc_html( get_bloginfo( 'name' ) ) . '</span>';
    }

    public function site_tagline_handler( $atts ) {
        $atts = shortcode_atts( array( 'class' => 'site-description' ), $atts, 'lq_site_tagline' );
        $tagline = get_bloginfo( 'description' );
        if ( ! $tagline ) return '';
        return '<span class="' . esc_attr( $atts['class'] ) . '">' . esc_html( $tagline ) . '</span>';
    }
}
