using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using o0.Geometry2D;
using System;
using SixLabors.ImageSharp.PixelFormats;
using UnityEngine.UIElements;
using o0.Num;
using Unity.VisualScripting;
using System.Threading.Tasks;
using System.Linq;
using o0;
using o0.Project;

namespace ZIM.Image
{
    // 灰度图处理(float)
    public class ImgProcessGray
    {
        int width, height;
        float[] pixels;

        public float this[int index]
        {
            get
            {
                if (index >= 0 && index < pixels.Count())
                    return pixels[index];
                else
                    return 0f;
            }
        }
        public float this[int i, int j] => this[i + j * width];

        public ImgProcessGray(float[] pixels, int width, int height)
        {
            if (pixels.Length != width * height)
                throw new ArgumentException("Input array length must be equal to width * height");

            this.width = width;
            this.height = height;
            this.pixels = pixels;
        }

        public (float[] p, int w, int h) FindLines()
        //public List<o0.Geometry.Line<float>> FindLines()
        {
            int kernel_size = 3;
            int half_size = kernel_size / 2;
            int conv_width = width - kernel_size + 1;
            int conv_height = height - kernel_size + 1;
            var edgeArray = new ConvEdge[conv_width * conv_height];

            var result = new float[conv_width * conv_height];

            Parallel.For(0, conv_width, (i) =>
            //for (int i = 0; i < conv_width; i++)
            {
                for (int j = 0; j < conv_height; j++)
                {
                    var e = new ConvEdge(this, (i + half_size, j + half_size), kernel_size);
                    edgeArray[i + j * conv_width] = e;
                    result[i + j * conv_width] = e.Variance;
                }
            });
            //return default;
            LevelEqualization(result, 10240);

            return (result, conv_width, conv_height);
            
        }

        void SigmodAdjust(float[] p)
        {
            var mean = p.Mean();
            Parallel.For(0, p.Length, (i) =>
            {
                p[i] = 1 / (1 + (float)Math.Exp(-p[i]/mean));
            });
        }

        void LevelAdjust(float[] p)
        {
            var max = p.Max();
            var scale = 1 / (float)Math.Sqrt(max);
            Parallel.For(0, p.Length, (i) =>
            {
                p[i] = (float)Math.Sqrt(p[i]) * scale;
            });
            //var scale = 1 / max;
            //Parallel.For(0, p.Length, (i) =>
            //{
            //    p[i] = Math.Min(p[i] * scale, 1);
            //});
        }

        void LevelEqualization(float[] p, int bit = 256)
        {
            bit -= 1;
            var scale = 1 / p.Max();
            Parallel.For(0, p.Length, (i) => p[i] *= scale);        // 归一化
            int[] pint = new int[p.Length];
            Parallel.For(0, p.Length, i => pint[i] = (int)(p[i] * bit));        // 映射到256色彩

            int[] H = new int[bit+1];
            for (int i = 0; i < p.Length; i++)
                H[pint[i]]++;
            float[] HF = new float[bit+1];
            for (int i = 0; i <= bit; i++)
                HF[i] = H[i] / (float)p.Length;       // 概率

            float[] D = new float[bit + 1];
            float temp = 0;
            for (int i = 1; i <= bit; i++)      // 不取颜色为0的概率
            {
                temp += HF[i];
                D[i] = temp;        // 累计密度
            }
            Parallel.For(0, p.Length, i => p[i] = D[pint[i]] / D.Last());       // 去密度为颜色，并归一化

        }
    }

    public class ConvEdge
    {
        public Vector<float> EdgePoint;
        public Vector<float> EdgeDirection;
        public float Variance;
        public int noiseCount;

        // kernel_size应是奇数，偶数没测试
        public ConvEdge(ImgProcessGray imgGray, (int, int) pixel, int kernel_size, int scale = 1)
        {
            EdgePoint = new Vector<float>(pixel.Item1, pixel.Item2);
            noiseCount = 0;

            var convList = new List<(float, Vector<float>)>();
            var mean = 0f;
            for (int i = pixel.Item1 - kernel_size / 2 * scale; i <= pixel.Item1 + kernel_size / 2 * scale; i += scale)
            {
                for (int j = pixel.Item2 - kernel_size / 2 * scale; j <= pixel.Item2 + kernel_size / 2 * scale; j += scale)
                {
                    var value = imgGray[i, j];
                    convList.Add((value, new Vector<float>(i, j)));
                    mean += value;
                }
            }
            mean /= convList.Count;
            convList.Sort((a, b) => a.Item1.CompareTo(b.Item1));

            var vMean0 = Vector<float>.Zero;  // 暗区
            var vMean1 = Vector<float>.Zero;  // 明区
            for (int k = 0; k < convList.Count / 2; k++)
            {
                Variance += (float)Math.Pow((convList[k].Item1 - mean), 2) / convList.Count;
                vMean0 += convList[k].Item2;
                if (AreaOfPoint(convList[k].Item2) == 1)
                    noiseCount++;
            }
            vMean0 /= convList.Count / 2;
            for (int k = convList.Count / 2; k < convList.Count; k++)
            {
                Variance += (float)Math.Pow((convList[k].Item1 - mean), 2) / convList.Count;
                vMean1 += convList[k].Item2;
                if (AreaOfPoint(convList[k].Item2) == 0)
                    noiseCount++;
            }
            vMean1 /= convList.Count - convList.Count / 2;

            GetEdgeDirection(vMean0, vMean1);
        }

        // 返回 1 在明区，返回 0 在暗区, -1 在边界上
        public int AreaOfPoint(Vector<float> v)
        {
            var ev = v - EdgePoint;
            var dot = ev.x * EdgeDirection.y - ev.y * EdgeDirection.x;
            if (dot == 0)
                return -1;
            return dot < 0 ? 1 : 0;
        }

        void GetEdgeDirection(Vector<float> v0, Vector<float> v1)   // v0 是暗部平均点，v1 是亮部平均点
        {
            var dir = v1 - v0;
            EdgeDirection = new Vector<float>(dir.y, -dir.x);
        }



        //public void ConvEdge(int[] pixels, Vector2Int vec, int kernel_size, int scale)
        //{
        //    var sum = 0f;
        //    for (int i = vec.x - kernel_size / 2 * scale; i < vec.x + kernel_size / 2 * scale; i += scale)
        //    {
        //        for (int j = vec.y - kernel_size / 2 * scale; j < vec.y + kernel_size / 2 * scale; j += scale)
        //        {
        //            var index2 = webCamera.cameraInfo.Vector2ToIndex(i, j);
        //            if (index2 > 0 && index2 < pixels.Length)       // 超出边缘不计算
        //                sum += pixels[index2];
        //        }
        //    }
        //    return sum / kernel_size / kernel_size;
        //}
    }
}


