using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Web.Script.Serialization;

namespace Ounibo.Catalog.Core
{
    public class BuildAttachmentSpec
    {
        public string kind;      // dimDrawing / datasheet / note
        public string lang;      // zh / en
        public string source;    // 源文件绝对路径
        public string model;     // 可选, 绑定型号
    }

    public class BuildResult
    {
        public bool Ok;
        public List<string> Errors = new List<string>();
        public List<string> Warnings = new List<string>();
        public string OutputPath;
    }

    /// <summary>
    /// .opc 打包器 (M2 Builder 内核, 也供脚本/自测使用):
    /// CSV (model_code + 参数列 + step_file 列) + STEP 目录 → zip 数据包。
    /// </summary>
    public static class OpcBuilder
    {
        /// <summary>
        /// 从 CSV 自动识别参数定义 (与向导 Step2 共用):
        /// 数值列 → type=number (支持范围搜索), 其他 → enum (取值按出现顺序去重)。
        /// </summary>
        public static List<ParameterDef> AutoDetectParameters(string csvPath)
        {
            var result = new List<ParameterDef>();
            var lines = File.ReadAllLines(csvPath, Encoding.UTF8).Where(l => !string.IsNullOrWhiteSpace(l)).ToArray();
            if (lines.Length < 2) return result;
            var header = lines[0].Split(',').Select(x => x.Trim()).ToArray();
            var dataRows = lines.Skip(1).Select(l => l.Split(',')).Where(c => c.Length >= header.Length && !string.IsNullOrWhiteSpace(c[0])).ToList();

            for (int i = 1; i < header.Length; i++)
            {
                var code = header[i];
                if (code == "step_file") continue;
                // 枚举列保留空值 (如 磁石="" 表示无磁石, 是合法取值); 数值列过滤空值
                var rawVals = dataRows.Select(r => r[i].Trim()).Distinct().ToList();
                var nonEmpty = rawVals.Where(v => v.Length > 0).ToList();
                bool numeric = nonEmpty.Count > 0 && nonEmpty.All(v =>
                {
                    double d;
                    return double.TryParse(v, NumberStyles.Float, CultureInfo.InvariantCulture, out d);
                });
                var values = numeric
                    ? nonEmpty.Select(v => double.Parse(v, CultureInfo.InvariantCulture)).OrderBy(d => d).Cast<object>().ToList()
                    : rawVals.Cast<object>().ToList();
                result.Add(new ParameterDef
                {
                    code = code,
                    nameZh = code,
                    nameEn = code,
                    unit = numeric ? "mm" : "",
                    type = numeric ? "number" : "enum",
                    values = values
                });
            }
            return result;
        }
        public static BuildResult Build(
            string outPath,
            string catalogName, string catalogVersion,
            string catCode, string catNameZh, string catNameEn,
            Series series,
            string csvPath, string stepDir,
            List<BuildAttachmentSpec> attachments)
        {
            var r = new BuildResult { Ok = true };

            try
            {
                // 1) 读 CSV: 首列 = 型号编码, step_file 列 = STEP 文件名, 其余 = 参数
                if (!File.Exists(csvPath)) { r.Errors.Add("CSV 不存在: " + csvPath); r.Ok = false; return r; }
                if (!Directory.Exists(stepDir)) { r.Errors.Add("STEP 目录不存在: " + stepDir); r.Ok = false; return r; }

                var variants = ReadCsvVariants(series, csvPath, stepDir, r);
                if (r.Errors.Count > 0 || variants == null || variants.Count == 0)
                {
                    if (variants == null || variants.Count == 0) r.Errors.Add("无有效变体");
                    r.Ok = false; return r;
                }

                // 2) 目录与系列
                var cat = new Catalog
                {
                    schemaVersion = "1.0",
                    catalogName = catalogName,
                    catalogNameEn = catalogName,
                    catalogVersion = catalogVersion,
                    defaultLang = "zh",
                    langs = new List<string> { "zh", "en" },
                    categories = new List<Category>
                    {
                        new Category { code = catCode, nameZh = catNameZh, nameEn = catNameEn, series = new List<string> { series.code } }
                    },
                    series = new List<Series> { series }
                };
                series.variants = variants;

                // 3) 组装临时目录 → zip
                var tmp = Path.Combine(Path.GetTempPath(), "opcbuild_" + Guid.NewGuid().ToString("N"));
                Directory.CreateDirectory(tmp);
                try
                {
                    foreach (var v in variants)
                    {
                        var dest = Path.Combine(tmp, v.step.Replace('/', '\\'));
                        Directory.CreateDirectory(Path.GetDirectoryName(dest));
                        var srcName = ResolveStepFile(stepDir, Path.GetFileName(v.step.Replace('/', '\\')));
                        File.Copy(Path.Combine(stepDir, srcName), dest);
                    }
                    foreach (var a in attachments ?? new List<BuildAttachmentSpec>())
                    {
                        if (!File.Exists(a.source)) { r.Warnings.Add("附件源文件缺失, 跳过: " + a.source); continue; }
                        // 包内目录统一用 kebab-case (dimDrawing → dim-drawing), 与 sample-data 布局一致
                        var folder = a.kind == "dimDrawing" ? "dim-drawing" : a.kind;
                        var rel = "docs/" + folder + "/" + Path.GetFileName(a.source);
                        Directory.CreateDirectory(Path.Combine(tmp, "docs", folder));
                        File.Copy(a.source, Path.Combine(tmp, rel.Replace('/', '\\')), true);
                        series.attachments = series.attachments ?? new List<Attachment>();
                        series.attachments.Add(new Attachment { kind = a.kind, lang = a.lang, path = rel, model = a.model });
                    }

                    var ser = new JavaScriptSerializer();
                    var json = ser.Serialize(cat);
                    File.WriteAllText(Path.Combine(tmp, "catalog.json"), json, new UTF8Encoding(true));

                    Directory.CreateDirectory(Path.GetDirectoryName(outPath));
                    if (File.Exists(outPath)) File.Delete(outPath);
                    ZipFile.CreateFromDirectory(tmp, outPath, CompressionLevel.Optimal, false);
                    r.OutputPath = outPath;
                }
                finally
                {
                    Directory.Delete(tmp, true);
                }
            }
            catch (Exception ex)
            {
                r.Errors.Add("打包异常: " + ex.Message);
                r.Ok = false;
            }
            return r;
        }

        /// <summary>
        /// STEP 物理文件查找: 优先 CSV 写的 .step, 兼容同名 .stp (NX 导出常用后缀)。
        /// 返回物理文件名, 找不到返回 null。
        /// </summary>
        public static string ResolveStepFile(string stepDir, string stepName)
        {
            if (File.Exists(Path.Combine(stepDir, stepName))) return stepName;
            var alt = Path.ChangeExtension(stepName, ".stp");
            return File.Exists(Path.Combine(stepDir, alt)) ? alt : null;
        }

        /// <summary>
        /// CSV → 变体列表 (与 Build 共用内核; 错误写进 r.Errors, 返回值可能为 null)。
        /// 首列 = 型号编码, step_file 列 = STEP 文件名 (需存在于 stepDir, .stp/.step 兼容), 其余 = 参数列。
        /// </summary>
        public static List<Variant> ReadCsvVariants(Series series, string csvPath, string stepDir, BuildResult r)
        {
            var lines = File.ReadAllLines(csvPath, Encoding.UTF8).Where(l => !string.IsNullOrWhiteSpace(l)).ToArray();
            if (lines.Length < 2) { r.Errors.Add("CSV 无数据行: " + csvPath); return null; }
            var header = lines[0].Split(',').Select(x => x.Trim()).ToArray();
            if (!header.Contains("step_file")) { r.Errors.Add("CSV 缺少 step_file 列: " + csvPath); return null; }

            var variants = new List<Variant>();
            var seen = new HashSet<string>();
            foreach (var line in lines.Skip(1))
            {
                var c = line.Split(',');
                if (c.Length < header.Length) { r.Errors.Add("CSV 行字段不足: " + line); continue; }
                var model = c[0].Trim();
                if (string.IsNullOrEmpty(model)) { r.Errors.Add("CSV 行缺型号编码: " + line); continue; }
                if (!seen.Add(model)) { r.Errors.Add("型号编码重复: " + model); continue; }

                var p = new Dictionary<string, object>();
                for (int i = 1; i < header.Length; i++)
                {
                    var code = header[i];
                    if (code == "step_file") continue;
                    var def = (series.parameters ?? new List<ParameterDef>()).FirstOrDefault(x => x.code == code);
                    if (def == null) continue;   // 未定义的列跳过
                    var raw = (i < c.Length) ? c[i].Trim() : "";
                    if (def.type == "number" || def.type == "range")
                    {
                        double d;
                        if (double.TryParse(raw, NumberStyles.Float, CultureInfo.InvariantCulture, out d))
                            p[code] = d;
                        else { r.Errors.Add("参数值非数字: " + model + " / " + code + "=" + raw); continue; }
                    }
                    else p[code] = raw;
                }
                if (p.Count < (series.parameters ?? new List<ParameterDef>()).Count)
                { r.Errors.Add("参数不全: " + model); continue; }

                var stepCol = Array.IndexOf(header, "step_file");
                var stepName = (stepCol < c.Length) ? c[stepCol].Trim() : "";
                if (ResolveStepFile(stepDir, stepName) == null)
                { r.Errors.Add("STEP 文件缺失: " + stepName); continue; }
                variants.Add(new Variant { modelCode = model, @params = p, step = "step/" + stepName });
            }
            return variants.Count == 0 ? null : variants;
        }
    }
}
