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

namespace Ounibo.Catalog.Core
{
    /// <summary>
    /// 选型引擎: 规则求值 + 允许值过滤 + 变体解析。
    /// 规则语义: 若某变体满足规则 If 条件, 则必须同时满足 Then 条件, 否则该变体无效。
    /// </summary>
    public class Configurator
    {
        public Series Series { get; private set; }
        private readonly List<Variant> _all;

        public Configurator(Series s)
        {
            Series = s;
            _all = s.variants ?? new List<Variant>();
        }

        /// <summary>参数化模式 (mode=parametric): 选型可超出 CSV 网格, 由 ParametricEngine 生成非标组合。</summary>
        public bool IsParametric { get { return ParametricEngine.IsParametric(Series); } }

        // 值比较统一走字符串 (枚举值如 16 / "16.0" / "S" 均可比)
        static string S(object o) { return o == null ? "" : Convert.ToString(o, CultureInfo.InvariantCulture); }
        static bool Eq(object a, object b) { return string.Equals(S(a), S(b), StringComparison.OrdinalIgnoreCase); }
        static double D(object o) { return Convert.ToDouble(o, CultureInfo.InvariantCulture); }

        public bool CondMatches(RuleCond c, Dictionary<string, object> p)
        {
            if (c == null) return true;
            object val;
            if (!p.TryGetValue(c.Param, out val)) return false;
            switch (c.Op)
            {
                case "eq": return Eq(val, c.Value);
                case "ne": return !Eq(val, c.Value);
                case "in":
                    var arr = c.Value as object[];
                    return arr != null && arr.Any(x => Eq(val, x));
                case "gt": return D(val) > D(c.Value);
                case "ge": return D(val) >= D(c.Value);
                case "lt": return D(val) < D(c.Value);
                case "le": return D(val) <= D(c.Value);
                case "between":
                    var r = c.Value as object[];
                    return r != null && r.Length == 2 && D(val) >= D(r[0]) && D(val) <= D(r[1]);
                default: return false;
            }
        }

        public bool RuleViolated(Variant v)
        {
            foreach (var rule in Series.rules ?? Enumerable.Empty<Rule>())
                if (CondMatches(rule.If, v.@params) && !CondMatches(rule.Then, v.@params))
                    return true;
            return false;
        }

        /// <summary>
        /// 部分选择下的规则违背判定 (参数化联动用): Then 参数未选时视为"尚可满足", 不判违背 —
        /// 否则选 mount=YB 会瞬间清空其他未选参数的选项 (参数化引擎一期, 与网页同语义)。
        /// </summary>
        public bool RuleViolatedPartial(Dictionary<string, object> p)
        {
            foreach (var rule in Series.rules ?? Enumerable.Empty<Rule>())
                if (CondMatches(rule.If, p) && p.ContainsKey(rule.Then.Param) && !CondMatches(rule.Then, p))
                    return true;
            return false;
        }

        public List<Variant> ValidVariants()
        {
            return _all.Where(v => !RuleViolated(v)).ToList();
        }

        public bool Matches(Variant v, Dictionary<string, object> sel)
        {
            foreach (var kv in sel)
            {
                object val;
                if (!v.@params.TryGetValue(kv.Key, out val) || !Eq(val, kv.Value))
                    return false;
            }
            return true;
        }

        /// <summary>
        /// 每个参数在"当前已选 + 规则"约束下的允许值 (保持参数定义顺序)。
        /// 已选参数按"除自身外的其他已选"计算可改值 (选完也能调整),
        /// 未选参数按全部已选计算; 均用于 UI 自动清除被置为非法的选择。
        /// </summary>
        public Dictionary<string, List<object>> AllowedOptions(Dictionary<string, object> sel)
        {
            var result = new Dictionary<string, List<object>>();
            foreach (var p in Series.parameters ?? new List<ParameterDef>())
            {
                // 候选值: 枚举/数值参数取定义值; range 参数取 gridValues 快捷值
                var cands = p.type == "range"
                    ? (p.gridValues ?? p.values ?? new List<object>())
                    : (p.values ?? new List<object>());
                var selForP = sel.Where(kv => kv.Key != p.code).ToDictionary(kv => kv.Key, kv => kv.Value);
                var allowed = new List<object>();
                // 联动按"域+规则"判合法 (参数化引擎一期): 自由 range 值没有对应网格行,
                // 若按网格行存在性过滤会把其他参数选项瞬间清空 — 与网页同语义
                foreach (var val in cands)
                {
                    var combo = new Dictionary<string, object>(selForP) { [p.code] = val };
                    if (ParametricEngine.ValidatePartial(Series, combo) == null)
                        allowed.Add(val);
                }
                // range 参数: 保留当前已选的自由输入值 (域内合法) — 防止联动刷新时清掉自定义值
                if (p.type == "range" && sel.ContainsKey(p.code) &&
                    !allowed.Any(x => Eq(x, sel[p.code])) && ParametricEngine.DomainValid(p, sel[p.code]))
                    allowed.Add(sel[p.code]);
                result[p.code] = allowed;
            }
            return result;
        }

        /// <summary>参数选满且合法时返回变体, 否则 null。</summary>
        public Variant Resolve(Dictionary<string, object> sel)
        {
            if (sel.Count < (Series.parameters?.Count ?? 0)) return null;
            return ValidVariants().FirstOrDefault(v => Matches(v, sel));
        }
    }
}
