using System;
using System.Collections.Generic;
using System.Linq;

namespace Ounibo.Catalog.Core
{
    /// <summary>
    /// 内存搜索引擎: 型号编码/系列名/参数名/关键词 (英文+拼音) 全文匹配,
    /// 支持数值参数的区间过滤。数据量 ≤ 10 万级内存扫描足够。
    /// </summary>
    public class SearchEngine
    {
        public class SearchItem
        {
            public Series Series;
            public Variant Variant;
            public string Note;   // 平替来源标注 (如 "SMC SQ32-50"), 显示在系列名后
            public string ModelCode { get { return Variant.modelCode; } }
            public string SeriesNameZh { get { return Note == null ? Series.nameZh : Series.nameZh + " ← 平替 " + Note; } }
            public string SeriesNameEn { get { return Note == null ? Series.nameEn : Series.nameEn + " (Alt: " + Note + ")"; } }
            public string Step { get { return Variant.step; } }
            public double Score;
            public List<string> AltCodes = new List<string>();   // 平替对照: 指向此变体的竞品型号 (品牌 型号)
        }

        List<SearchItem> _items = new List<SearchItem>();

        public SearchEngine(Catalog cat)
        {
            foreach (var s in cat.series ?? new List<Series>())
                foreach (var v in s.variants ?? new List<Variant>())
                    _items.Add(new SearchItem { Series = s, Variant = v });

            // 平替对照: 竞品型号挂到对应我方变体上 (搜竞品型号 = 命中我方型号)
            foreach (var cr in cat.crossRefs ?? new List<CrossRefRow>())
            {
                var it = _items.FirstOrDefault(x => string.Equals(x.ModelCode, cr.ourModel, StringComparison.OrdinalIgnoreCase));
                if (it != null) it.AltCodes.Add(cr.brand + " " + cr.foreignModel);
            }
        }

        public int Count { get { return _items.Count; } }

        string LangName(Series s, string lang)
        {
            return lang == "en" ? (s.nameEn ?? s.nameZh) : (s.nameZh ?? s.nameEn);
        }

        string LangParamName(ParameterDef p, string lang)
        {
            return lang == "en" ? (p.nameEn ?? p.nameZh) : (p.nameZh ?? p.nameEn);
        }

        /// <summary>构建变体的可搜索文本 (不含型号编码本身)。</summary>
        string BuildText(SearchItem it, string lang)
        {
            var parts = new List<string>();
            parts.Add(LangName(it.Series, lang));
            parts.Add(it.Series.code);
            parts.Add(it.Series.keywords ?? "");
            foreach (var kv in it.Variant.@params)
            {
                var p = it.Series.parameters.FirstOrDefault(x => x.code == kv.Key);
                if (p != null)
                {
                    parts.Add(LangParamName(p, lang));
                    parts.Add(p.keywords ?? "");
                    var disp = p.display != null && p.display.ContainsKey(Convert.ToString(kv.Value)) ? p.display[Convert.ToString(kv.Value)] : null;
                    if (disp != null) parts.Add(disp);
                }
                parts.Add(Convert.ToString(kv.Value, System.Globalization.CultureInfo.InvariantCulture));
            }
            foreach (var alt in it.AltCodes) parts.Add(alt);   // 平替对照: 竞品品牌+型号可搜
            return string.Join(" ", parts).ToLowerInvariant();
        }

        /// <summary>
        /// 全文查询: 空格分词, 全部词都命中才算; 按 精确编码 &gt; 编码前缀 &gt; 其他文本 排序。
        /// </summary>
        public List<SearchItem> Query(string q, string lang)
        {
            var tokens = (q ?? "").ToLowerInvariant()
                .Split(new[] { ' ', ',', '，', ';', '；' }, StringSplitOptions.RemoveEmptyEntries)
                .Select(t => t.Trim())
                .Where(t => t.Length > 0)
                .ToList();
            if (tokens.Count == 0) return new List<SearchItem>();

            foreach (var it in _items)
            {
                var code = it.ModelCode.ToLowerInvariant();
                var alts = it.AltCodes.Select(a => a.ToLowerInvariant()).ToList();
                var text = BuildText(it, lang);
                it.Score = 0;
                if (!tokens.All(t => code.Contains(t) || alts.Any(a => a.Contains(t)) || text.Contains(t)))
                    continue;
                if (tokens.Any(t => code == t)) it.Score = 1000;
                else if (tokens.Any(t => alts.Any(a => a == t))) it.Score = 900;      // 竞品型号精确命中
                else if (tokens.All(t => code.Contains(t))) it.Score = 800;
                else if (tokens.All(t => alts.Any(a => a.Contains(t)) || text.Contains(t))) it.Score = 500;
                else it.Score = 100;
            }
            return _items.Where(x => x.Score > 0).OrderByDescending(x => x.Score).ThenBy(x => x.ModelCode).ToList();
        }

        /// <summary>数值参数区间过滤 (range 的键为参数 code, 值为 min/max 数组, null 表示不限制)。</summary>
        public List<SearchItem> RangeFilter(List<SearchItem> items, Dictionary<string, double?[]> ranges)
        {
            if (ranges == null || ranges.Count == 0) return items;
            return items.Where(it =>
            {
                foreach (var r in ranges)
                {
                    var p = it.Series.parameters.FirstOrDefault(x => x.code == r.Key);
                    if (p == null || p.type != "number") continue;
                    object val;
                    if (!it.Variant.@params.TryGetValue(r.Key, out val)) continue;
                    double d;
                    if (!double.TryParse(Convert.ToString(val, System.Globalization.CultureInfo.InvariantCulture),
                        System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out d))
                        continue;
                    if (r.Value[0].HasValue && d < r.Value[0].Value) return false;
                    if (r.Value[1].HasValue && d > r.Value[1].Value) return false;
                }
                return true;
            }).ToList();
        }
    }
}
