<?php

namespace FleekDash\Core\Search;

use FleekDash\Utils\AvatarHelper;

/**
 * Search index rebuilding operations
 *
 * Handles bulk index rebuilding for all searchable object types.
 * Used for initial indexing and manual reindexing operations.
 *
 * @package FleekDash\Core\Search
 * @since 2.2.0
 */
class SearchIndexBuilder
{
    /**
     * Rebuild post index
     *
     * @return int Number of posts indexed
     */
    public static function rebuildPostIndex(): int
    {
        global $wpdb;
        $table_name = $wpdb->prefix . 'fleekdash_search_index';

        // Clear existing post entries
        $wpdb->delete($table_name, ['object_type' => 'post']);

        // Get all published posts
        $posts = \get_posts([
            'post_type' => 'any',
            'post_status' => 'publish',
            'numberposts' => -1,
            'fields' => 'ids',
            'no_found_rows' => true,
            'update_post_meta_cache' => false,
            'update_post_term_cache' => false,
        ]);

        $count = 0;
        foreach ($posts as $post_id) {
            if (self::indexSinglePost((int) $post_id)) {
                $count++;
            }
        }

        return $count;
    }

    /**
     * Rebuild user index
     *
     * @return int Number of users indexed
     */
    public static function rebuildUserIndex(): int
    {
        global $wpdb;
        $table_name = $wpdb->prefix . 'fleekdash_search_index';

        // Clear existing user entries
        $wpdb->delete($table_name, ['object_type' => 'user']);

        $users = get_users(['fields' => 'ids']);
        $count = 0;

        foreach ($users as $user_id) {
            if (self::indexSingleUser((int) $user_id)) {
                $count++;
            }
        }

        return $count;
    }

    /**
     * Rebuild menu index
     *
     * @return int Number of menu items indexed
     */
    public static function rebuildMenuIndex()
    {
        global $wpdb;
        $table_name = $wpdb->prefix . 'fleekdash_search_index';

        $wpdb->delete($table_name, ['object_type' => 'menu']);

        $items = self::fetchAdminMenuItems();
        $flattened = self::flattenMenuItems($items);

        $count = 0;
        foreach ($flattened as $entry) {
            $title = isset($entry['name']) ? wp_strip_all_tags((string) $entry['name']) : '';
            if ($title === '') {
                continue;
            }

            $row = self::buildMenuIndexRow($entry, $title);
            $wpdb->insert($table_name, $row);
            $count++;
        }

        return $count;
    }

    /**
     * Fetch admin menu items from AdminMenu service
     *
     * @return array
     */
    private static function fetchAdminMenuItems(): array
    {
        $admin_menu_service = \FleekDash\Admin\AdminMenu::getInstance();
        $admin_menu_service->bootstrap();
        if (!\did_action('admin_menu')) {
            \do_action('_wp_menu_output');
        }
        $admin_menu_service->captureAdminMenuComplete();
        $admin_menu_service->ensureMenuCaptured();

        return $admin_menu_service->getAdminMenuItems();
    }

    /**
     * Flatten menu items (top-level + submenu) into a single list
     *
     * @param array $items Menu items
     * @return array
     */
    private static function flattenMenuItems(array $items): array
    {
        $flattened = [];
        foreach ($items as $item) {
            $flattened[] = $item;
            if (!empty($item['submenu']) && is_array($item['submenu'])) {
                foreach ($item['submenu'] as $sub) {
                    $flattened[] = array_merge($sub, ['parent' => $item['name']]);
                }
            }
        }
        return $flattened;
    }

    /**
     * Build a single menu index row for insertion
     *
     * @param array $entry Menu entry
     * @param string $title Sanitized title
     * @return array<string, mixed> Row data for wpdb insert
     */
    private static function buildMenuIndexRow(array $entry, string $title): array
    {
        $url = $entry['url'] ?? '';
        $href = $entry['href'] ?? '';
        $route_type = $entry['route_type'] ?? '';
        $is_wp_native = isset($entry['is_wp_native']) ? (bool) $entry['is_wp_native'] : true;
        $parent = $entry['parent'] ?? '';

        $raw_id = $entry['unique_id'] ?? ($href ?: $url ?: $title);
        $object_id = (int) sprintf('%u', crc32((string) $raw_id));

        $content = trim(($parent ? ($parent . ' ') : '') . ($href ?: $url));
        $excerpt = $content !== '' ? wp_trim_words($content, 15) : '';
        $keywords = trim(($route_type ? ($route_type . ' ') : '') . ($is_wp_native ? 'wordpress_iframe' : 'react'));
        $search_vector = $title . ' ' . $content . ' ' . $keywords;

        $metadata = [
            'url' => $url,
            'href' => $href,
            'route_type' => $route_type,
            'is_wp_native' => $is_wp_native,
            'parent' => $parent,
            'popularity_score' => 5,
        ];

        return [
            'object_id' => $object_id,
            'object_type' => 'menu',
            'title' => $title,
            'content' => $content,
            'excerpt' => $excerpt,
            'keywords' => $keywords,
            'search_vector' => $search_vector,
            'metadata' => json_encode($metadata),
            'popularity_score' => $metadata['popularity_score'],
        ];
    }

    /**
     * Rebuild setting index
     *
     * @return int Number of settings indexed
     */
    public static function rebuildSettingIndex()
    {
        global $wpdb;
        $table_name = $wpdb->prefix . 'fleekdash_search_index';

        // Clear existing setting entries
        $wpdb->delete($table_name, ['object_type' => 'setting']);

        // Add common WordPress settings
        $settings = [
            ['id' => 1, 'title' => 'General Settings', 'content' => 'Site title, tagline, URL, email'],
            ['id' => 2, 'title' => 'Reading Settings', 'content' => 'Front page displays, posts per page'],
            ['id' => 3, 'title' => 'Discussion Settings', 'content' => 'Comments, avatars, moderation'],
            ['id' => 4, 'title' => 'Media Settings', 'content' => 'Image sizes, file uploads']
        ];

        $count = 0;
        foreach ($settings as $setting) {
            $wpdb->insert($table_name, [
                'object_id' => $setting['id'],
                'object_type' => 'setting',
                'title' => $setting['title'],
                'content' => $setting['content'],
                'excerpt' => substr($setting['content'], 0, 150),
                'search_vector' => $setting['title'] . ' ' . $setting['content'],
                'metadata' => json_encode(['section' => 'admin']),
                'popularity_score' => 10
            ]);
            $count++;
        }

        return $count;
    }

    /**
     * Index a single post
     *
     * @param int $post_id Post ID
     * @return bool|int False on skip/failure, rows affected on success
     */
    public static function indexSinglePost(int $post_id)
    {
        global $wpdb;
        $post = \get_post($post_id);
        if (!$post || $post->post_status !== 'publish') {
            return false;
        }

        $table_name = $wpdb->prefix . 'fleekdash_search_index';
        $content = \wp_strip_all_tags($post->post_content);
        $search_vector = $post->post_title . ' ' . $content;

        $metadata = [
            'post_type' => $post->post_type,
            'post_status' => $post->post_status,
            'author' => \get_the_author_meta('display_name', $post->post_author),
            'popularity_score' => 1
        ];

        // Delete existing entry if any
        $wpdb->delete($table_name, ['object_id' => $post_id, 'object_type' => 'post']);

        return $wpdb->insert($table_name, [
            'object_id' => $post_id,
            'object_type' => 'post',
            'title' => \get_the_title($post_id),
            'content' => $content,
            'excerpt' => \wp_trim_words($content, 30),
            'search_vector' => $search_vector,
            'metadata' => json_encode($metadata),
            'popularity_score' => 1
        ]);
    }

    /**
     * Remove post from index
     *
     * @param int $post_id Post ID
     * @return bool|int
     */
    public static function removePostFromIndex(int $post_id)
    {
        global $wpdb;
        $table_name = $wpdb->prefix . 'fleekdash_search_index';
        return $wpdb->delete($table_name, ['object_id' => $post_id, 'object_type' => 'post']);
    }

    /**
     * Index a single user
     *
     * @param int $user_id User ID
     * @return bool|int False on skip/failure, rows affected on success
     */
    public static function indexSingleUser(int $user_id)
    {
        global $wpdb;
        $user = \get_userdata($user_id);
        if (!$user) {
            return false;
        }

        $table_name = $wpdb->prefix . 'fleekdash_search_index';
        $content = $user->user_login . ' ' . $user->user_email . ' ' . $user->display_name;
        $search_vector = $user->display_name . ' ' . $user->user_login . ' ' . $user->user_email;

        $avatar_url = AvatarHelper::getUserAvatarUrl($user_id, ['size' => 128]);

        $metadata = [
            'username' => $user->user_login,
            'email' => $user->user_email,
            'roles' => $user->roles,
            'avatar' => $avatar_url,
            'avatar_url' => $avatar_url,
            'popularity_score' => 3
        ];

        // Delete existing entry if any
        $wpdb->delete($table_name, ['object_id' => $user_id, 'object_type' => 'user']);

        return $wpdb->insert($table_name, [
            'object_id' => $user_id,
            'object_type' => 'user',
            'title' => $user->display_name,
            'content' => $content,
            'excerpt' => $user->user_email,
            'search_vector' => $search_vector,
            'metadata' => json_encode($metadata),
            'popularity_score' => 3
        ]);
    }

    /**
     * Remove user from index
     *
     * @param int $user_id User ID
     * @return bool|int
     */
    public static function removeUserFromIndex(int $user_id)
    {
        global $wpdb;
        $table_name = $wpdb->prefix . 'fleekdash_search_index';
        return $wpdb->delete($table_name, ['object_id' => $user_id, 'object_type' => 'user']);
    }

    /**
     * Index a single menu (stub)
     */
    public static function indexSingleMenu()
    {
        // For menus, it's easier to rebuild the entire menu index
        return self::rebuildMenuIndex();
    }

    /**
     * Remove menu from index by object_id
     *
     * @param int|string $objectId The object_id stored in the index (computed from menu entry)
     */
    public static function removeMenuFromIndex($objectId)
    {
        global $wpdb;
        $table_name = $wpdb->prefix . 'fleekdash_search_index';
        return $wpdb->delete($table_name, ['object_id' => $objectId, 'object_type' => 'menu']);
    }
}
