<?php

declare(strict_types=1);

namespace Numinix\SeekmodoWordPress\LocalIndex;

/**
 * Local index operator settings (weights, operators, throttle, etc.).
 */
final class IndexSettings
{
    public const OPT_WEIGHTS           = 'seekmodo_local_index_weights';
    public const OPT_DEFAULT_OPERATOR  = 'seekmodo_local_index_default_operator';
    public const OPT_OR_FALLBACK       = 'seekmodo_local_index_or_fallback';
    public const OPT_PARTIAL_MATCH     = 'seekmodo_local_index_partial_match';
    public const OPT_THROTTLE          = 'seekmodo_local_index_throttle';
    public const OPT_MIN_WORD_LENGTH   = 'seekmodo_local_index_min_word_length';
    public const OPT_INDEX_COMMENTS    = 'seekmodo_local_index_comments';
    public const OPT_CUSTOM_FIELDS     = 'seekmodo_local_index_custom_fields';
    public const OPT_EXCLUDED_IDS      = 'seekmodo_local_index_excluded_ids';
    public const OPT_LOG_QUERIES       = 'seekmodo_local_index_log_queries';
    public const DIRTY_META            = '_seekmodo_local_dirty';

    /** @var array<string,int> */
    private const DEFAULT_WEIGHTS = [
        'title'       => 5,
        'content'     => 1,
        'comment'     => 1,
        'tag'         => 1,
        'category'    => 1,
        'excerpt'     => 3,
        'taxonomy'    => 1,
        'customfield' => 2,
        'author'      => 1,
    ];

    public static function registerDefaults(): void
    {
        if (!function_exists('add_option')) {
            return;
        }
        add_option(self::OPT_WEIGHTS, self::DEFAULT_WEIGHTS);
        add_option(self::OPT_DEFAULT_OPERATOR, 'and');
        add_option(self::OPT_OR_FALLBACK, '1');
        add_option(self::OPT_PARTIAL_MATCH, '1');
        add_option(self::OPT_THROTTLE, '500');
        add_option(self::OPT_MIN_WORD_LENGTH, '3');
        add_option(self::OPT_INDEX_COMMENTS, '0');
        add_option(self::OPT_CUSTOM_FIELDS, 'visible');
        add_option(self::OPT_EXCLUDED_IDS, '');
        add_option(self::OPT_LOG_QUERIES, '1');
    }

    /**
     * @return array<string,int>
     */
    public static function weights(): array
    {
        $stored = get_option(self::OPT_WEIGHTS, self::DEFAULT_WEIGHTS);
        if (!is_array($stored)) {
            $stored = self::DEFAULT_WEIGHTS;
        }
        $weights = array_merge(self::DEFAULT_WEIGHTS, $stored);
        if (function_exists('apply_filters')) {
            /** @var array<string,int> $weights */
            $weights = apply_filters('seekmodo_local_index_weights', $weights);
        }

        return $weights;
    }

    public static function defaultOperator(): string
    {
        $op = strtolower((string) get_option(self::OPT_DEFAULT_OPERATOR, 'and'));

        return $op === 'or' ? 'or' : 'and';
    }

    public static function orFallbackEnabled(): bool
    {
        return self::truthy(get_option(self::OPT_OR_FALLBACK, '1'));
    }

    public static function partialMatchEnabled(): bool
    {
        return self::truthy(get_option(self::OPT_PARTIAL_MATCH, '1'));
    }

    public static function throttleLimit(): int
    {
        $v = (int) get_option(self::OPT_THROTTLE, 500);

        return max(50, min(5000, $v));
    }

    public static function minWordLength(): int
    {
        $v = (int) get_option(self::OPT_MIN_WORD_LENGTH, 3);

        return max(1, min(20, $v));
    }

    public static function indexComments(): bool
    {
        return self::truthy(get_option(self::OPT_INDEX_COMMENTS, '0'));
    }

    public static function customFieldsMode(): string
    {
        $mode = strtolower((string) get_option(self::OPT_CUSTOM_FIELDS, 'visible'));
        if (!in_array($mode, ['none', 'visible', 'all', 'list'], true)) {
            return 'visible';
        }

        return $mode;
    }

    /**
     * @return list<int>
     */
    public static function excludedPostIds(): array
    {
        $raw = (string) get_option(self::OPT_EXCLUDED_IDS, '');
        if ($raw === '') {
            return [];
        }
        $ids = preg_split('/\s*,\s*/', $raw) ?: [];

        return array_values(array_filter(array_map('intval', $ids)));
    }

    public static function logQueries(): bool
    {
        return self::truthy(get_option(self::OPT_LOG_QUERIES, '1'));
    }

    /**
     * @return list<string>
     */
    public static function defaultMetaKeys(): array
    {
        $keys = ['page_lead'];
        if (function_exists('apply_filters')) {
            /** @var list<string> $keys */
            $keys = apply_filters('seekmodo_local_index_meta_keys', $keys);
        }

        return $keys;
    }

    /**
     * @return list<string> SQL LIKE patterns for postmeta keys.
     */
    public static function defaultMetaPatterns(): array
    {
        $patterns = ['page\_sections\_%\_html', '%\_html'];
        if (function_exists('apply_filters')) {
            /** @var list<string> $patterns */
            $patterns = apply_filters('seekmodo_local_index_meta_patterns', $patterns);
        }

        return $patterns;
    }

    /**
     * @param mixed $v
     */
    private static function truthy($v): bool
    {
        if (is_bool($v)) {
            return $v;
        }

        return in_array(strtolower((string) $v), ['1', 'true', 'yes', 'on'], true);
    }
}
