<?php
/**
 * Name: Table of Contents
 * Description: Auto-generate table of contents from post headings with anchor links for easier navigation in long articles allowing readers to jump to sections
 * Category: Content
 * Icon: -
 * UseCases: [
 *   {
 *     "title": "Long-Form Guide Navigation",
 *     "description": "Add clickable table of contents to 3000+ word tutorials so readers can jump to specific sections they need."
 *   },
 *   {
 *     "title": "Documentation Pages",
 *     "description": "Create anchor-linked TOC on product documentation pages for easy navigation to specific features or troubleshooting steps."
 *   },
 *   {
 *     "title": "SEO Jump Links",
 *     "description": "Generate structured table of contents for better Google search results with jump-to-section links in SERPs."
 *   }
 * ]
 * Added: 2025-08-22
 * Tags: toc, table-of-contents, headings, navigation, ux
 * WhereToFind: {
 *   "location": "Configure in module settings",
 *   "url": "",
 *   "instructions": "Use [toc] shortcode or enable auto-insert",
 *   "newTab": false
 * }
 */

// Prevent direct access
if (!defined('ABSPATH')) exit;

class SwitchboardTableOfContents {
    
    public function __construct() {
        add_filter('the_content', [$this, 'add_table_of_contents']);
        add_shortcode('toc', [$this, 'toc_shortcode']);
        
        // Register with data registry
        $this->register_with_data_registry();
    }
    
    /**
     * Register data locations with the data registry
     */
    private function register_with_data_registry() {
        if (class_exists('Switchboard_Data_Registry')) {
            $registry = Switchboard_Data_Registry::get_instance();
            $registry->auto_register($this, __FILE__);
        }
    }
    
    /**
     * Register data locations for cleanup
     * 
     * @return array Data locations used by this module
     */
    public function register_data_locations() {
        return [
            'options' => [
                'switchboard_table-of-contents_settings'
            ],
            'option_patterns' => [],
            'tables' => [],
            'post_meta' => [],
            'user_meta' => [],
            'transients' => []
        ];
    }
    
    /**
     * Render settings panel
     * 
     * @param array $settings Current settings
     * @return void Outputs HTML
     */
    public function render_settings($settings = []) {
        $auto_insert = isset($settings['auto_insert']) ? $settings['auto_insert'] : 'yes';
        $position = isset($settings['position']) ? $settings['position'] : 'after_first_paragraph';
        $min_headings = isset($settings['min_headings']) ? intval($settings['min_headings']) : 3;
        $heading_levels = isset($settings['heading_levels']) ? $settings['heading_levels'] : '2,3';
        $title = isset($settings['title']) ? $settings['title'] : 'Table of Contents';
        $numbered = isset($settings['numbered']) ? $settings['numbered'] : 'no';
        ?>
        <input type="hidden" name="module" value="table-of-contents">

        <div class="sb-module-option-item sb-module-toggle-item">
            <div class="sb-module-option-content">
                <div class="sb-module-toggle-header">
                    <strong class="sb-module-option-title"><?php esc_html_e('Auto Insert', 'wpswitchboard'); ?></strong>
                    <label class="sb-module-toggle">
                        <input type="checkbox" name="setting_auto_insert" value="yes" <?php checked($auto_insert, 'yes'); ?>>
                        <span class="sb-module-toggle-slider"></span>
                    </label>
                </div>
                <p class="sb-module-option-text"><?php esc_html_e('Automatically add TOC to posts. When disabled, use shortcode [toc] to display TOC manually.', 'wpswitchboard'); ?></p>
            </div>
        </div>

        <div class="sb-sp-group sb-sp-field-horizontal">
            <div class="sb-sp-field-horizontal-left">
                <label for="setting_position" class="sb-sp-label"><?php esc_html_e('Position', 'wpswitchboard'); ?></label>
                <p class="sb-sp-description"><?php esc_html_e('Where to display the table of contents', 'wpswitchboard'); ?></p>
            </div>
            <select name="setting_position" id="setting_position" class="sb-sp-select">
                <option value="after_first_paragraph" <?php selected($position, 'after_first_paragraph'); ?>><?php esc_html_e('After First Paragraph (Recommended)', 'wpswitchboard'); ?></option>
                <option value="before_content" <?php selected($position, 'before_content'); ?>><?php esc_html_e('Before Content', 'wpswitchboard'); ?></option>
            </select>
        </div>

        <div class="sb-sp-group sb-sp-field-horizontal">
            <div class="sb-sp-field-horizontal-left">
                <label for="setting_min_headings" class="sb-sp-label"><?php esc_html_e('Minimum Headings', 'wpswitchboard'); ?></label>
                <p class="sb-sp-description"><?php esc_html_e('Only show TOC if post has at least this many headings. Default: 3', 'wpswitchboard'); ?></p>
            </div>
            <input type="number" name="setting_min_headings" id="setting_min_headings" value="<?php echo esc_attr($min_headings); ?>" min="1" max="10" class="sb-sp-select" style="width: 150px;">
        </div>

        <div class="sb-sp-group sb-sp-field-horizontal">
            <div class="sb-sp-field-horizontal-left">
                <label for="setting_heading_levels" class="sb-sp-label"><?php esc_html_e('Heading Levels', 'wpswitchboard'); ?></label>
                <p class="sb-sp-description"><?php esc_html_e('Comma-separated heading levels to include (e.g., "2,3,4" for H2, H3, H4). Default: "2,3"', 'wpswitchboard'); ?></p>
            </div>
            <input type="text" name="setting_heading_levels" id="setting_heading_levels" value="<?php echo esc_attr($heading_levels); ?>" class="sb-sp-select">
        </div>

        <div class="sb-sp-group sb-sp-field-horizontal">
            <div class="sb-sp-field-horizontal-left">
                <label for="setting_title" class="sb-sp-label"><?php esc_html_e('TOC Title', 'wpswitchboard'); ?></label>
                <p class="sb-sp-description"><?php esc_html_e('Title displayed at the top of the table of contents', 'wpswitchboard'); ?></p>
            </div>
            <input type="text" name="setting_title" id="setting_title" value="<?php echo esc_attr($title); ?>" class="sb-sp-select">
        </div>

        <div class="sb-module-option-item sb-module-toggle-item">
            <div class="sb-module-option-content">
                <div class="sb-module-toggle-header">
                    <strong class="sb-module-option-title"><?php esc_html_e('Numbered List', 'wpswitchboard'); ?></strong>
                    <label class="sb-module-toggle">
                        <input type="checkbox" name="setting_numbered" value="yes" <?php checked($numbered, 'yes'); ?>>
                        <span class="sb-module-toggle-slider"></span>
                    </label>
                </div>
                <p class="sb-module-option-text"><?php esc_html_e('Use numbered list (1, 2, 3...). When disabled, uses bullet points.', 'wpswitchboard'); ?></p>
            </div>
        </div>

        <div class="sb-sp-info-box sb-sp-info-box-info">
            <h4 class="sb-sp-heading-sm"><?php esc_html_e('How to Use', 'wpswitchboard'); ?></h4>
            <ul class="sb-sp-list">
                <li class="sb-sp-list-item"><strong><?php esc_html_e('Automatic:', 'wpswitchboard'); ?></strong> <?php esc_html_e('Enable "Auto Insert" and TOC will appear automatically in posts with enough headings.', 'wpswitchboard'); ?></li>
                <li class="sb-sp-list-item"><strong><?php esc_html_e('Manual:', 'wpswitchboard'); ?></strong> <?php esc_html_e('Disable "Auto Insert" and use shortcode', 'wpswitchboard'); ?> <code>[toc]</code> <?php esc_html_e('anywhere in your content.', 'wpswitchboard'); ?></li>
                <li class="sb-sp-list-item"><strong><?php esc_html_e('Tip:', 'wpswitchboard'); ?></strong> <?php esc_html_e('TOC creates clickable links that smoothly scroll to each heading.', 'wpswitchboard'); ?></li>
            </ul>
        </div>
        <?php
    }
    
    private function get_settings() {
        return get_option('switchboard_table-of-contents_settings', []);
    }
    
    public function add_table_of_contents($content) {
        $settings = $this->get_settings();
        $auto_insert = isset($settings['auto_insert']) ? $settings['auto_insert'] : 'yes';
        
        if ($auto_insert !== 'yes') {
            return $content;
        }
        
        if (!is_single() || !in_array(get_post_type(), ['post', 'page'])) {
            return $content;
        }
        
        $min_headings = isset($settings['min_headings']) ? intval($settings['min_headings']) : 3;
        $heading_levels = isset($settings['heading_levels']) ? $settings['heading_levels'] : '2,3';
        $levels_array = array_map('trim', explode(',', $heading_levels));
        $levels_pattern = '[' . implode('', $levels_array) . ']';
        
        // Check if content has headings
        if (!preg_match_all('/<h(' . $levels_pattern . ')([^>]*)>(.*?)<\/h\1>/i', $content, $matches, PREG_SET_ORDER)) {
            return $content;
        }
        
        // Only add TOC if there are enough headings
        if (count($matches) < $min_headings) {
            return $content;
        }
        
        $toc = $this->generate_toc($matches, $content);
        
        $position = isset($settings['position']) ? $settings['position'] : 'after_first_paragraph';
        
        if ($position === 'before_content') {
            return $toc . $content;
        } else {
            // Insert TOC after first paragraph
            $content = preg_replace('/(<\/p>)/', '$1' . $toc, $content, 1);
            return $content;
        }
    }
    
    public function toc_shortcode($atts) {
        global $post;
        
        if (!$post) {
            return '';
        }
        
        preg_match_all('/<h([2-3])([^>]*)>(.*?)<\/h\1>/i', $post->post_content, $matches, PREG_SET_ORDER);
        
        if (count($matches) < 1) {
            return '';
        }
        
        return $this->generate_toc($matches, $post->post_content);
    }
    
    private function generate_toc($matches, &$content) {
        $settings = $this->get_settings();
        $title = isset($settings['title']) ? $settings['title'] : 'Table of Contents';
        $numbered = isset($settings['numbered']) ? $settings['numbered'] : 'no';
        
        $list_style = $numbered === 'yes' ? 'decimal' : 'none';
        $list_padding = $numbered === 'yes' ? '0 0 0 20px' : '0';

        $toc_html = '<div class="switchboard-toc" style="background: #f9fafb; padding: 20px; border-radius: 8px; border: 1px solid #e5e7eb; margin: 32px 0;">';
        $toc_html .= '<h3 style="font-size: 18px; font-weight: 600; color: #111827; margin: 0 0 12px 0;">' . esc_html($title) . '</h3>';
        $toc_html .= '<ul style="margin: 0; list-style: ' . $list_style . '; padding-left: ' . $list_padding . ';">';

        foreach ($matches as $index => $match) {
            $level = $match[1];
            $heading_text = wp_strip_all_tags($match[3]);
            $slug = sanitize_title($heading_text) . '-' . $index;

            // Add ID to heading in content
            $old_heading = $match[0];
            $heading_content_safe = wp_kses_post($match[3]); // Allow safe HTML only
            $new_heading = '<h' . $level . ' id="' . esc_attr($slug) . '">' . $heading_content_safe . '</h' . $level . '>';
            $content = str_replace($old_heading, $new_heading, $content);

            // Add to TOC
            $indent_style = $level == 3 ? 'margin-bottom: 8px; margin-left: 20px;' : 'margin-bottom: 8px;';
            $toc_html .= '<li style="' . $indent_style . '">';
            $toc_html .= '<a href="#' . $slug . '" style="text-decoration: none; color: var(--primary-500);">' . esc_html($heading_text) . '</a>';
            $toc_html .= '</li>';
        }

        $toc_html .= '</ul></div>';
        
        // Add smooth scroll CSS
        $toc_html .= '<style>html { scroll-behavior: smooth; }</style>';
        
        return $toc_html;
    }
}

// Initialize and register with data system
$switchboard_instance = new SwitchboardTableOfContents();
Switchboard_Data_Registry::get_instance()->auto_register($switchboard_instance, __FILE__);
