using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text.RegularExpressions;
using System.Windows.Media;
using System.Windows.Media.Media3D;

namespace Ounibo.Catalog.Viewer3D
{
    public class Cyl
    {
        public double Z0, Z1, R;
        public double X;   // 圆心 X 偏移 (双轴活塞杆)
    }

    /// <summary>
    /// 解析本项目生成的极简 STEP (圆柱组合), 并离散为 WPF 网格。
    /// 注: 只支持自有生成器的格式; 真实 CAD 的通用 STEP 解析在 M2 由 Builder 侧处理。
    /// </summary>
    public static class StepMesh
    {
        public static List<Cyl> Parse(string step)
        {
            var rs = new List<double>();
            foreach (Match m in Regex.Matches(step, @"CYLINDRICAL_SURFACE\('',#\d+,([\d.]+)\);"))
                rs.Add(double.Parse(m.Groups[1].Value, CultureInfo.InvariantCulture));

            // 圆心点 = 仅有的 y=0 点: (X, 0, Z) 每圆柱一对 (底+顶)
            var xs = new List<double>();
            var zs = new List<double>();
            foreach (Match m in Regex.Matches(step, @"CARTESIAN_POINT\('',\((-?[\d.]+),0,(-?[\d.]+)\)\);"))
            {
                xs.Add(double.Parse(m.Groups[1].Value, CultureInfo.InvariantCulture));
                zs.Add(double.Parse(m.Groups[2].Value, CultureInfo.InvariantCulture));
            }

            var cy = new List<Cyl>();
            for (int i = 0; i < rs.Count && 2 * i + 1 < zs.Count; i++)
                cy.Add(new Cyl
                {
                    Z0 = Math.Min(zs[2 * i], zs[2 * i + 1]),
                    Z1 = Math.Max(zs[2 * i], zs[2 * i + 1]),
                    R = rs[i],
                    X = xs[2 * i]
                });
            return cy;
        }

        /// <summary>圆柱 → 三角网格 (侧面 + 顶盖 + 底盖, 带逐顶点法线)。</summary>
        public static MeshGeometry3D BuildMesh(Cyl c, int segments = 32)
        {
            var mesh = new MeshGeometry3D();
            var pts = new List<Point3D>();
            var nrm = new List<Vector3D>();

            // 下环 (z0) 与上环 (z1)
            for (int i = 0; i < segments; i++)
            {
                double a = 2 * Math.PI * i / segments;
                double x = Math.Cos(a) * c.R + c.X, y = Math.Sin(a) * c.R;
                pts.Add(new Point3D(x, y, c.Z0));
                var n0 = new Vector3D(x - c.X, y, 0); n0.Normalize(); nrm.Add(n0);
            }
            for (int i = 0; i < segments; i++)
            {
                double a = 2 * Math.PI * i / segments;
                double x = Math.Cos(a) * c.R + c.X, y = Math.Sin(a) * c.R;
                pts.Add(new Point3D(x, y, c.Z1));
                var n1 = new Vector3D(x - c.X, y, 0); n1.Normalize(); nrm.Add(n1);
            }

            // 侧面
            for (int i = 0; i < segments; i++)
            {
                int a0 = i, a1 = (i + 1) % segments;
                int b0 = segments + i, b1 = segments + ((i + 1) % segments);
                mesh.TriangleIndices.Add(a0); mesh.TriangleIndices.Add(b0); mesh.TriangleIndices.Add(a1);
                mesh.TriangleIndices.Add(a1); mesh.TriangleIndices.Add(b0); mesh.TriangleIndices.Add(b1);
            }

            // 顶盖与底盖 (中心点 + 扇形)
            pts.Add(new Point3D(c.X, 0, c.Z1)); nrm.Add(new Vector3D(0, 0, 1));
            int topC = pts.Count - 1;
            pts.Add(new Point3D(c.X, 0, c.Z0)); nrm.Add(new Vector3D(0, 0, -1));
            int botC = pts.Count - 1;
            for (int i = 0; i < segments; i++)
            {
                int b0 = segments + i, b1 = segments + ((i + 1) % segments);
                mesh.TriangleIndices.Add(topC); mesh.TriangleIndices.Add(b0); mesh.TriangleIndices.Add(b1);
                mesh.TriangleIndices.Add(botC); mesh.TriangleIndices.Add(i + 1 == segments ? 0 : i + 1); mesh.TriangleIndices.Add(i);
            }

            mesh.Positions = new Point3DCollection(pts);
            mesh.Normals = new Vector3DCollection(nrm);
            return mesh;
        }

        /// <summary>计算包围信息用于相机取景。</summary>
        public static void Bounds(List<Cyl> cyls, out double cx, out double cy, out double cz, out double r, out double h)
        {
            cx = 0; cy = 0;
            double zMin = double.MaxValue, zMax = double.MinValue, rMax = 0;
            foreach (var c in cyls)
            {
                zMin = Math.Min(zMin, c.Z0); zMax = Math.Max(zMax, c.Z1); rMax = Math.Max(rMax, c.R);
            }
            cz = (zMin + zMax) / 2; h = zMax - zMin; r = rMax;
        }
    }
}
