<?php

namespace FleekDash\Core\Search;

// Load debug helpers
if (!function_exists('fleekdash_log_debug')) {
    require_once FLEEKDASH_PLUGIN_DIR . 'includes/Core/debug-helpers.php';
}

use FleekDash\Utils\AvatarHelper;

/**
 * Search utility methods
 *
 * Handles URL generation, preview data, synonyms, and type boosts.
 *
 * @package FleekDash\Core\Search
 * @since 2.2.0
 */
class SearchHelpers
{
    /** @var string[] */
    private const THUMBNAIL_SIZE_CANDIDATES = [
        'fleekdash-thumbnail',
        'thumbnail',
        'medium',
        'medium_large',
        'large',
        'fleekdash-preview',
    ];

    /**
     * Get type boost values from settings
     *
     * @return array Type => boost value mapping
     */
    public static function getTypeBoosts()
    {
        $option_name = 'fleekdash_search_settings';
        $saved = \get_option($option_name, []);

        $defaults = [
            'post' => 6.0,
            'user' => 5.0,
            'menu' => 2.0,
            'setting' => 1.0,
        ];

        $settings = is_array($saved) ? array_merge($defaults, $saved) : $defaults;
        $type_boosts = isset($settings['type_boosts']) && is_array($settings['type_boosts'])
            ? $settings['type_boosts']
            : $defaults;

        return array_merge($defaults, $type_boosts);
    }

    /**
     * Get object URL based on type
     *
     * @param string $type Object type (post, user, menu, setting)
     * @param int    $id   Object ID
     * @return string URL
     */
    public static function getObjectUrl($type, $id)
    {
        $url = '';

        switch ($type) {
            case 'post':
                $url = get_permalink($id);
                break;
            case 'user':
                $url = get_author_posts_url($id);
                break;
            case 'menu':
                $url = \admin_url('nav-menus.php?action=edit&menu=' . $id);
                break;
            case 'setting':
                $url = \admin_url('options-general.php');
                break;
            default:
                $url = '';
                break;
        }

        return $url ?: '';
    }

    /**
     * Get basic preview data for search results
     *
     * Preview fields are resolved from WordPress at request time (avatars via
     * AvatarHelper, thumbnails via attachment APIs). Indexed `$metadata` from
     * search results is not used here — callers merge index metadata separately.
     *
     * @param string $type Object type
     * @param int    $id   Object ID
     * @return array<string, mixed> Preview data (thumbnail, author, date, etc.)
     */
    public static function getPreviewData(string $type, int $id): array
    {
        $preview = [];

        if ($type === 'user') {
            $preview = self::buildUserPreviewData((int) $id);
        } elseif ($type !== 'menu' && $type !== 'setting') {
            $preview = self::buildPostPreviewData((int) $id);
        }

        return $preview;
    }

    /**
     * Expand search term with synonyms
     *
     * @param string $search_term Original search term
     * @return array Array of terms including synonyms
     */
    public static function expandWithSynonyms($search_term)
    {
        $terms = [$search_term];
        $synonyms = self::getSynonymsMap();
        $normalized_term = strtolower(trim($search_term));

        if (isset($synonyms[$normalized_term])) {
            $terms = array_merge($terms, $synonyms[$normalized_term]);
        }

        $terms = array_filter(array_unique($terms));

        if (strpos($normalized_term, 'image') !== false || strpos($normalized_term, 'test') !== false) {
            fleekdash_log_debug("🔍 Backend SearchIndexManager expanding '{$search_term}' to: " . implode(', ', $terms));
        }

        return $terms;
    }

    /**
     * Get synonyms map from settings
     *
     * @return array Bidirectional synonym mapping
     */
    public static function getSynonymsMap()
    {
        static $cached_synonyms = null;

        if ($cached_synonyms !== null) {
            return $cached_synonyms;
        }

        $settings = \get_option('fleekdash_search_settings', []);
        $synonyms_raw = $settings['synonyms'] ?? [];
        $synonyms_map = [];

        foreach ($synonyms_raw as $key => $values) {
            $key_norm = strtolower(trim($key));
            $values_norm = array_map(static function ($value) {
                return strtolower(trim((string) $value));
            }, (array) $values);

            if (!isset($synonyms_map[$key_norm])) {
                $synonyms_map[$key_norm] = [];
            }
            $synonyms_map[$key_norm] = array_merge($synonyms_map[$key_norm], $values_norm);

            foreach ($values_norm as $value) {
                if (!isset($synonyms_map[$value])) {
                    $synonyms_map[$value] = [];
                }
                if (!in_array($key_norm, $synonyms_map[$value], true)) {
                    $synonyms_map[$value][] = $key_norm;
                }
            }
        }

        return $cached_synonyms = $synonyms_map;
    }

    /**
     * @return array<string, mixed>
     */
    private static function buildUserPreviewData(int $id): array
    {
        $user_roles = '';
        $user_data = \get_userdata($id);
        if ($user_data && !is_wp_error($user_data) && !empty($user_data->roles)) {
            $user_roles = implode(', ', $user_data->roles);
        }

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

        return [
            'avatar' => $avatar_url,
            'avatar_url' => $avatar_url,
            'role' => $user_roles,
            'description' => \get_user_meta($id, 'description', true) ?: '',
        ];
    }

    /**
     * @return array<string, mixed>
     */
    private static function buildPostPreviewData(int $id): array
    {
        if (!is_callable('get_post_type') || !\call_user_func('get_post_type', $id)) {
            return [];
        }

        $tags = get_the_tags($id) ?: [];

        return [
            'image' => self::resolvePostThumbnailUrl($id),
            'author' => get_the_author_meta('display_name', get_post_field('post_author', $id)),
            'date' => get_the_date('Y-m-d', $id),
            'tags' => array_map(static function ($tag) {
                return $tag->name;
            }, $tags),
        ];
    }

    private static function resolvePostThumbnailUrl(int $post_id): string
    {
        $image_url = '';

        $logo_id = \get_post_meta($post_id, 'logo', true);
        if ($logo_id) {
            $image_url = self::pickBestThumbnailUrl((int) $logo_id);
        }

        if ($image_url === '' && is_callable('has_post_thumbnail') && \call_user_func('has_post_thumbnail', $post_id)) {
            $thumb_id = is_callable('get_post_thumbnail_id') ? (int) \call_user_func('get_post_thumbnail_id', $post_id) : 0;
            if ($thumb_id > 0) {
                $image_url = self::pickBestThumbnailUrl($thumb_id);
            }
        }

        if ($image_url === '') {
            $attached = is_callable('get_attached_media') ? \call_user_func('get_attached_media', 'image', $post_id) : [];
            if (!empty($attached)) {
                $first = reset($attached);
                if (!empty($first->ID)) {
                    $image_url = self::pickBestThumbnailUrl((int) $first->ID);
                }
            }
        }

        return $image_url;
    }

    private static function pickBestThumbnailUrl(int $attachment_id): string
    {
        $image_url = '';

        if ($attachment_id <= 0) {
            return $image_url;
        }

        foreach (self::THUMBNAIL_SIZE_CANDIDATES as $size) {
            $candidate = self::getAttachmentImageUrl($attachment_id, $size);
            if ($candidate !== '') {
                $image_url = $candidate;
                break;
            }
        }

        if ($image_url === '' && is_callable('wp_get_attachment_url')) {
            $fallback = \call_user_func('wp_get_attachment_url', $attachment_id);
            $image_url = $fallback ?: '';
        }

        return $image_url;
    }

    private static function getAttachmentImageUrl(int $attachment_id, string $size): string
    {
        if (!is_callable('wp_get_attachment_image_url')) {
            return '';
        }

        $url = \call_user_func('wp_get_attachment_image_url', $attachment_id, $size);

        return $url ?: '';
    }
}
