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

namespace Ounibo.Catalog.Core
{
    public class ValidationIssue
    {
        public string Severity;   // ERROR / WARNING
        public string Message;
        public string Target;     // 如 "SC / SC32x50S-LB"
    }

    /// <summary>
    /// 数据包校验器 (对标 qacheck 思想): 资源缺失/编码重复/规则冲突/附件缺失。
    /// 校验不通过不允许编译发布 (M3 硬门槛)。
    /// </summary>
    public static class PackageValidator
    {
        static string S(object o) { return o == null ? "" : Convert.ToString(o, System.Globalization.CultureInfo.InvariantCulture); }

        public static List<ValidationIssue> Validate(OpcPackage pkg)
        {
            var issues = new List<ValidationIssue>();
            var cat = pkg.Catalog;
            if (cat == null) { issues.Add(new ValidationIssue { Severity = "ERROR", Message = "catalog.json 缺失" }); return issues; }
            if (cat.series == null || cat.series.Count == 0)
            { issues.Add(new ValidationIssue { Severity = "ERROR", Message = "无系列数据" }); return issues; }

            foreach (var s in cat.series)
            {
                // 变体资源与编码
                foreach (var v in s.variants ?? new List<Variant>())
                {
                    if (!pkg.HasAsset(v.step))
                        issues.Add(new ValidationIssue { Severity = "ERROR", Message = "STEP 文件缺失", Target = s.code + " / " + v.modelCode + " -> " + v.step });
                    var missing = (s.parameters ?? new List<ParameterDef>()).Where(p => !v.@params.ContainsKey(p.code)).Select(p => p.code).ToList();
                    if (missing.Count > 0)
                        issues.Add(new ValidationIssue { Severity = "ERROR", Message = "变体缺少参数: " + string.Join(",", missing), Target = s.code + " / " + v.modelCode });
                }
                var dup = (s.variants ?? new List<Variant>()).GroupBy(v => v.modelCode).Where(g => g.Count() > 1).ToList();
                foreach (var d in dup)
                    issues.Add(new ValidationIssue { Severity = "ERROR", Message = "型号编码重复 x" + d.Count(), Target = s.code + " / " + d.Key });

                // 规则引用检查
                foreach (var r in s.rules ?? new List<Rule>())
                {
                    CheckCond(r.If, s, issues, s.code);
                    CheckCond(r.Then, s, issues, s.code);
                    if (r.If != null && r.Then != null)
                    {
                        // 冲突: If 与 Then 针对同一参数且条件矛盾
                        if (r.If.Param == r.Then.Param && CondAlwaysFalse(r.If, r.Then))
                            issues.Add(new ValidationIssue { Severity = "WARNING", Message = "规则条件自相矛盾 (If/Then 同一参数互斥)", Target = s.code + " / " + r.If.Param });
                    }
                }

                // 附件
                foreach (var a in s.attachments ?? new List<Attachment>())
                {
                    if (!pkg.HasAsset(a.path))
                        issues.Add(new ValidationIssue { Severity = "WARNING", Message = "附件缺失 (" + a.kind + " " + a.lang + ")", Target = a.path });
                }
            }
            return issues;
        }

        static void CheckCond(RuleCond c, Series s, List<ValidationIssue> issues, string seriesCode)
        {
            if (c == null) return;
            var p = (s.parameters ?? new List<ParameterDef>()).FirstOrDefault(x => x.code == c.Param);
            if (p == null)
            {
                issues.Add(new ValidationIssue { Severity = "ERROR", Message = "规则引用了不存在的参数: " + c.Param, Target = seriesCode });
                return;
            }
            // 约束值必须在参数取值范围内
            var vals = c.Value as object[];
            if (vals != null)
            {
                var allowed = (p.values ?? new List<object>()).Select(x => S(x)).ToList();
                foreach (var v in vals)
                    if (!allowed.Contains(S(v)))
                        issues.Add(new ValidationIssue { Severity = "WARNING", Message = "规则值不在参数取值内: " + S(v), Target = seriesCode + " / " + c.Param });
            }
        }

        static bool CondAlwaysFalse(RuleCond a, RuleCond b)
        {
            // 仅判断简单互斥: eq x vs ne x / in [..] vs eq y 且 y 不在列表
            if (a.Op == "eq" && b.Op == "ne" && S(a.Value) == S(b.Value)) return true;
            if (a.Op == "ne" && b.Op == "eq" && S(a.Value) == S(b.Value)) return true;
            if (a.Op == "eq" && b.Op == "in")
            {
                var arr = b.Value as object[];
                if (arr != null && arr.Length > 0 && !arr.Any(x => S(x) == S(a.Value))) return true;
            }
            return false;
        }
    }
}
