using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace XPrint.Image.Tools
{
    public class VectorizationTool
    {
        private const byte ALPHA_OPAQUE_THRESHOLD = 250;    // 不透明Alpha阈值
        private readonly float _prescale;
        private readonly bool _verbose;

        public VectorizationTool(float prescale = 1.0f, bool verbose = false)
        {
            _prescale = prescale;
            _verbose = verbose;
        }

        public static bool HasValidContent(Bitmap mask)
        {
            if (mask == null) return false;

            Rectangle rect = new Rectangle(0, 0, mask.Width, mask.Height);
            BitmapData data = mask.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
            try
            {
                IntPtr ptr = data.Scan0;
                int bytes = Math.Abs(data.Stride) * mask.Height;
                byte[] argb = new byte[bytes];
                Marshal.Copy(ptr, argb, 0, bytes);

                // 检查是否有不透明像素（仅看Alpha通道）
                for (int i = 0; i < argb.Length; i += 4)
                {
                    if (argb[i + 3] >= ALPHA_OPAQUE_THRESHOLD)
                        return true;
                }
                return false;
            }
            finally
            {
                mask.UnlockBits(data);
            }
        }

        #region 矢量化与SVG生成（确保透明背景）

        /// <summary>
        /// 矢量化（纯C#实现，不依赖外部exe）
        /// </summary>
        public string? VectorizeMask(Bitmap mask, Color color)
        {
            if (!HasValidContent(mask)) return null;

            // 步骤1: 二值化图像（基于Alpha通道）
            //using var binaryImage = BinarizeImage(mask);

            // 步骤2: 提取轮廓
            var contours = ExtractContours(mask);

            // 步骤3: 简化轮廓
            var simplifiedContours = SimplifyContours(contours);

            // 步骤4: 转换为SVG
            string svgOutput = ConvertContoursToSvg(simplifiedContours, color);

            if(string.IsNullOrEmpty(svgOutput)) return null;

            return ExtractSvgPath(svgOutput, color.A);
        }

        /// <summary>
        /// 将图像二值化（不透明区域为黑，透明区域为白）
        /// </summary>
        private Bitmap BinarizeImage(Bitmap source)
        {
            int width = source.Width;
            int height = source.Height;
            var result = new Bitmap(width, height, PixelFormat.Format32bppArgb);

            Rectangle rect = new Rectangle(0, 0, width, height);
            BitmapData sourceData = source.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
            BitmapData resultData = result.LockBits(rect, ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb);

            try
            {
                IntPtr sourcePtr = sourceData.Scan0;
                IntPtr resultPtr = resultData.Scan0;
                int stride = sourceData.Stride;
                int pixelSize = 4;

                // 分配托管数组
                byte[] sourceArgb = new byte[Math.Abs(stride) * height];
                Marshal.Copy(sourcePtr, sourceArgb, 0, sourceArgb.Length);

                // 处理每个像素
                for (int y = 0; y < height; y++)
                {
                    for (int x = 0; x < width; x++)
                    {
                        int index = y * Math.Abs(stride) + x * pixelSize;
                        byte alpha = sourceArgb[index + 3];

                        // 计算结果图像中的索引
                        int resultIndex = y * Math.Abs(stride) + x * pixelSize;

                        if (alpha >= ALPHA_OPAQUE_THRESHOLD)
                        {
                            // 不透明区域 - 黑色
                            sourceArgb[resultIndex] = 0;     // B
                            sourceArgb[resultIndex + 1] = 0; // G
                            sourceArgb[resultIndex + 2] = 0; // R
                            sourceArgb[resultIndex + 3] = 255;// A
                        }
                        else
                        {
                            // 透明区域 - 白色
                            sourceArgb[resultIndex] = 255;   // B
                            sourceArgb[resultIndex + 1] = 255; // G
                            sourceArgb[resultIndex + 2] = 255; // R
                            sourceArgb[resultIndex + 3] = 255; // A
                        }
                    }
                }

                // 将处理后的数据复制回结果图像
                Marshal.Copy(sourceArgb, 0, resultPtr, sourceArgb.Length);
            }
            finally
            {
                source.UnlockBits(sourceData);
                result.UnlockBits(resultData);
            }

            return result;
        }

        /// <summary>
        /// 提取图像轮廓
        /// </summary>
        private List<List<Point>> ExtractContours(Bitmap binaryImage)
        {
            int width = binaryImage.Width;
            int height = binaryImage.Height;
            bool[,] visited = new bool[width, height];
            var contours = new List<List<Point>>();

            // 8个方向的搜索（上、下、左、右和四个对角线）
            int[] dx = { -1, -1, -1, 0, 0, 1, 1, 1 };
            int[] dy = { -1, 0, 1, -1, 1, -1, 0, 1 };

            Rectangle rect = new Rectangle(0, 0, width, height);
            BitmapData data = binaryImage.LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
            IntPtr scan0 = data.Scan0;
            int stride = data.Stride;
            int pixelSize = 4;

            try
            {
                // 遍历每个像素寻找轮廓
                for (int y = 0; y < height; y++)
                {
                    for (int x = 0; x < width; x++)
                    {
                        if (!visited[x, y] && IsBlackPixel(scan0, stride, x, y, pixelSize))
                        {
                            // 检查是否为轮廓点（有白色邻居）
                            if (HasWhiteNeighbor(scan0, stride, x, y, width, height, dx, dy, pixelSize))
                            {
                                // 跟踪完整轮廓
                                List<Point> contour = TraceContour(scan0, stride, x, y, width, height, visited, dx, dy, pixelSize);
                                if (contour.Count > 3) // 过滤过小的轮廓
                                {
                                    contours.Add(contour);
                                }
                            }
                            else
                            {
                                // 标记内部点为已访问
                                visited[x, y] = true;
                            }
                        }
                    }
                }
            }
            finally
            {
                binaryImage.UnlockBits(data);
            }

            return contours;
        }

        /// <summary>
        /// 检查是否为黑色像素（前景）
        /// </summary>
        private bool IsBlackPixel(IntPtr scan0, int stride, int x, int y, int pixelSize)
        {
            IntPtr address = scan0 + y * stride + x * pixelSize;
            return Marshal.ReadByte(address) == 0 &&       // B
                   Marshal.ReadByte(address + 1) == 0 &&   // G
                   Marshal.ReadByte(address + 2) == 0;     // R
        }

        /// <summary>
        /// 检查是否有白色邻居（背景）
        /// </summary>
        private bool HasWhiteNeighbor(IntPtr scan0, int stride, int x, int y, int width, int height, int[] dx, int[] dy, int pixelSize)
        {
            for (int i = 0; i < 8; i++)
            {
                int nx = x + dx[i];
                int ny = y + dy[i];

                if (nx >= 0 && nx < width && ny >= 0 && ny < height)
                {
                    IntPtr address = scan0 + ny * stride + nx * pixelSize;
                    if (Marshal.ReadByte(address) == 255 &&       // B
                        Marshal.ReadByte(address + 1) == 255 &&   // G
                        Marshal.ReadByte(address + 2) == 255)     // R
                    {
                        return true;
                    }
                }
            }
            return false;
        }

        /// <summary>
        /// 跟踪完整轮廓
        /// </summary>
        private List<Point> TraceContour(IntPtr scan0, int stride, int startX, int startY, int width, int height, bool[,] visited, int[] dx, int[] dy, int pixelSize)
        {
            var contour = new List<Point>();
            int currentX = startX;
            int currentY = startY;
            int currentDir = 0; // 初始方向

            do
            {
                contour.Add(new Point(currentX, currentY));
                visited[currentX, currentY] = true;

                bool found = false;
                // 搜索下一个轮廓点
                for (int i = 0; i < 8; i++)
                {
                    int dir = (currentDir + i + 6) % 8; // 从当前方向的左侧开始搜索
                    int nx = currentX + dx[dir];
                    int ny = currentY + dy[dir];

                    if (nx >= 0 && nx < width && ny >= 0 && ny < height &&
                        !visited[nx, ny] &&
                        IsBlackPixel(scan0, stride, nx, ny, pixelSize) &&
                        HasWhiteNeighbor(scan0, stride, nx, ny, width, height, dx, dy, pixelSize))
                    {
                        currentX = nx;
                        currentY = ny;
                        currentDir = dir;
                        found = true;
                        break;
                    }
                }

                if (!found)
                    break;

                // 防止无限循环
            } while (!(currentX == startX && currentY == startY) && contour.Count < 10000);

            return contour;
        }

        /// <summary>
        /// 简化轮廓（使用Douglas-Peucker算法）
        /// </summary>
        private List<List<Point>> SimplifyContours(List<List<Point>> contours, float epsilon = 1.0f)
        {
            var result = new List<List<Point>>();
            foreach (var contour in contours)
            {
                var simplified = SimplifyContour(contour, epsilon);
                if (simplified.Count > 3)
                {
                    result.Add(simplified);
                }
            }
            return result;
        }

        /// <summary>
        /// 简化单个轮廓
        /// </summary>
        private List<Point> SimplifyContour(List<Point> points, float epsilon)
        {
            if (points.Count <= 2)
                return new List<Point>(points);

            // 找到距离最大的点
            float maxDist = 0;
            int index = 0;
            Point first = points[0];
            Point last = points[points.Count - 1];

            for (int i = 1; i < points.Count - 1; i++)
            {
                float dist = PerpendicularDistance(points[i], first, last);
                if (dist > maxDist)
                {
                    maxDist = dist;
                    index = i;
                }
            }

            // 如果最大距离大于阈值，则递归简化
            if (maxDist > epsilon)
            {
                var left = SimplifyContour(points.GetRange(0, index + 1), epsilon);
                var right = SimplifyContour(points.GetRange(index, points.Count - index), epsilon);

                // 合并结果，移除重复点
                left.RemoveAt(left.Count - 1);
                left.AddRange(right);
                return left;
            }
            else
            {
                // 否则保留起点和终点
                return new List<Point> { first, last };
            }
        }

        /// <summary>
        /// 计算点到线段的垂直距离
        /// </summary>
        private float PerpendicularDistance(Point p, Point a, Point b)
        {
            float dx = b.X - a.X;
            float dy = b.Y - a.Y;

            if (dx == 0 && dy == 0)
                return (float)Math.Sqrt(Math.Pow(p.X - a.X, 2) + Math.Pow(p.Y - a.Y, 2));

            float t = Math.Clamp(((p.X - a.X) * dx + (p.Y - a.Y) * dy) / (dx * dx + dy * dy), 0f, 1f);
            float projX = a.X + t * dx;
            float projY = a.Y + t * dy;

            return (float)Math.Sqrt(Math.Pow(p.X - projX, 2) + Math.Pow(p.Y - projY, 2));
        }

        /// <summary>
        /// 生成与示例格式一致的SVG片段（贝塞尔曲线+统一样式+正确坐标）
        /// </summary>
        /// <param name="contours">轮廓集合</param>
        /// <param name="color">填充颜色</param>
        /// <param name="coordScale">坐标缩放系数（匹配示例量级，如10）</param>
        /// <returns>SVG的&lt;g&gt;片段</returns>
        private string ConvertContoursToSvg(List<List<Point>> contours, Color color, float coordScale = 1f)
        {
            if (contours.Count == 0)
                return string.Empty;

            var svgBuilder = new StringBuilder();
            string colorHex = $"#{color.R:X2}{color.G:X2}{color.B:X2}";
            string opacity = color.A < 255 ? $"opacity=\"{color.A / 255.0:0.00}\"" : "";

            // 1. 构建正确格式的<g>标签：统一样式+无stroke
            svgBuilder.AppendLine($"<g {opacity} fill=\"{colorHex}\" stroke=\"none\">");

            // 2. 遍历轮廓生成贝塞尔曲线路径（匹配示例的c命令）
            foreach (var contour in contours)
            {
                if (contour.Count < 4)
                    continue;

                // 确保轮廓闭合（起点=终点）
                var closedContour = new List<Point>(contour);
                if (!closedContour[0].Equals(closedContour.Last()))
                {
                    closedContour.Add(closedContour[0]);
                }

                // 3. 生成路径数据（无"f"后缀+贝塞尔曲线c命令）
                svgBuilder.Append("  <path d=\"");
                // 起点：M命令（坐标缩放至示例量级，空格分隔）
                Point start = closedContour[0];
                svgBuilder.Append($"M{(int)(start.X * coordScale)} {(int)(start.Y * coordScale)}");

                // 4. 用贝塞尔曲线c命令替代直线L命令（平滑路径，匹配示例）
                for (int i = 1; i < closedContour.Count - 1; i++)
                {
                    Point curr = closedContour[i];
                    Point next = closedContour[i + 1];
                    Point prev = closedContour[Math.Max(0, i - 1)];

                    // 计算贝塞尔控制点（简化拟合，确保平滑）
                    int c1X = (int)((prev.X + curr.X) * coordScale / 2);
                    int c1Y = (int)((prev.Y + curr.Y) * coordScale / 2);
                    int c2X = (int)((curr.X + next.X) * coordScale / 2);
                    int c2Y = (int)((curr.Y + next.Y) * coordScale / 2);
                    int endX = (int)(next.X * coordScale);
                    int endY = (int)(next.Y * coordScale);

                    // 贝塞尔曲线命令：c 控制点1X,控制点1Y 控制点2X,控制点2Y 终点X,终点Y
                    svgBuilder.Append($" c{c1X},{c1Y} {c2X},{c2Y} {endX},{endY}");

                    // 可选：每5个点换行（匹配示例的换行格式，提升可读性）
                    if (i % 5 == 0)
                    {
                        svgBuilder.AppendLine();
                        svgBuilder.Append("    "); // 缩进对齐
                    }
                }

                // 闭合路径：Z命令
                svgBuilder.AppendLine(" Z\" />");
            }

            // 闭合<g>标签
            svgBuilder.AppendLine("</g>");
            return svgBuilder.ToString();
        }

        public static string ExtractSvgPath(string rawSvg, byte alpha)
        {
            if (string.IsNullOrWhiteSpace(rawSvg)) return string.Empty;

            // 匹配<g>标签属性
            var gTagRegex = new Regex(@"<g\s+([^>]*?)>", RegexOptions.IgnoreCase);
            var gTagMatch = gTagRegex.Match(rawSvg);
            string originalGAttributes = gTagMatch.Success ? gTagMatch.Groups[1].Value : "";

            // 提取所有<path>
            var pathRegex = new Regex(@"<path\s+[^>]*?/>", RegexOptions.IgnoreCase);
            var matches = pathRegex.Matches(rawSvg);
            if (matches.Count == 0) return string.Empty;

            // 处理透明度属性
            string opacityAttribute = alpha < 255 ? $"opacity=\"{alpha / 255.0:0.00}\"" : "";

            // 合并属性（去重）
            var attributes = new List<string>();
            if (!string.IsNullOrWhiteSpace(originalGAttributes))
            {
                attributes.AddRange(originalGAttributes.Split(
                    new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries));
            }
            if (!string.IsNullOrWhiteSpace(opacityAttribute))
            {
                attributes.RemoveAll(a => a.StartsWith("opacity=", StringComparison.OrdinalIgnoreCase));
                attributes.Add(opacityAttribute);
            }

            // 构建最终<g>标签
            var result = new StringBuilder();
            result.Append($"<g {string.Join(" ", attributes)}>");
            foreach (Match match in matches)
                result.AppendLine(match.Value);
            result.Append("</g>");

            return result.ToString();
        }
        #endregion
    }
}
