using System.Diagnostics;
using OpenCvSharp;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Threading.Tasks;
using Hawkeye.VisionBuilder.Workflow.Datatypes;

namespace Hawkeye.VisionBuilder.Workflow.ColorStudioClasses.Filters;

public class SpatialFilterItem : IFilter
{
    private Mat? _mask=null;

    public IFilterParent Parent { get; set; }
    
    public bool Subtract { get; set; }

    public string? FilePath { get; set; }

    public void ReloadMask()
    {
        if (!File.Exists(FilePath))
        {
           CreateMask();
        }else
        if (!string.IsNullOrEmpty(FilePath))
        {
            _mask = new Mat(FilePath,ImreadModes.Grayscale);
        }
    }

    public SpatialFilterItem()
    {
        
    }

    void CreateMask()
    {
        _mask = new Mat(13005 + 256, 256, MatType.CV_8UC1, (Scalar)0);
    }

    public SpatialFilterItem(CategoryItem parent) : this()
    {
        Parent = parent;
    }

    public Mat Mask
    {
        get
        {
            if (_mask == null)
            {
                if (FilePath != null)
                {
                    ReloadMask();
                }
                else
                {
                    CreateMask();
                }
            }
                
            return _mask;
        }
        set
        {
            _mask = value;
        }
    }

    struct PixelStruct
    {
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 65536*3)]
        public byte[] Pixels;
    }
    struct PixelStructMask
    {
        [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3394816)]
        public byte[] Pixels;
    }
    public static Mat lastInput;
    public unsafe void Transform(ref Mat image, ref Mat res)
    {
        
        //var pixelStruct = Marshal.PtrToStructure<PixelStruct>(new IntPtr(image.DataPointer));
        var candyBytes = GetPixels<byte>(image);
        var candidates = new Mat(image.Size(), MatType.CV_8UC1, (Scalar)0);
        Mat tmp=new Mat();
        image.CopyTo(tmp);
        lastInput = tmp;
        //var pixelStructMask = Marshal.PtrToStructure<PixelStructMask>(new IntPtr(Mask.DataPointer));

        var maskBytes = GetPixels<byte>(Mask);

        var len = candyBytes.Length;
        var w = image.Width;
        var mw = Mask.Width;
        
        var lenDiv3 = len / 3;
        
        for (var q = 0; q < lenDiv3; q++)
        {
            var i = q * 3;
            
            var p = i / 3;
            var y = p / w;
            var x = p % w;

            var yp = (int)candyBytes[i + 0];
            var xp = candyBytes[i + 1];
            var vp = ((byte) (candyBytes[i + 2] / 5f)) * 255;

            var hp = yp + vp;

            var maskColor = maskBytes[hp * mw + xp];
            if (maskColor > 0)
                candidates.Set<byte>(y, x, 255);
        }
        
        
        

        if (Subtract && !IsSelected)
        {
            res -= candidates;
        }
        else
        {
            res += candidates;

        }

        

    }

    string Hash(Span<byte> bytes) {
        using var sha = SHA256.Create();
        var hash = sha.ComputeHash(bytes.ToArray());
        return Convert.ToBase64String(hash);
    }
    unsafe Span<T> GetPixels<T>(Mat image) where T : unmanaged
    {

        return new Span<T>(image.DataPointer, image.Width * image.Height * image.Channels());

    }
    public void Save(BinaryWriter writer)
    {
        writer.Write(FilePath??"");
        writer.Write(Subtract);
    }

    public void Load(BinaryReader reader)
    {
        FilePath = reader.ReadString();
        Console.WriteLine("Loaded path:"+FilePath);
        if(FilePath.StartsWith("..\\../"))
            FilePath = FilePath.Replace("..\\../", "..\\");
        Subtract = reader.ReadBoolean();
    }

    public bool IsSelected { get; set; }


    public override string ToString()
    {
        var totalColors = 0;
        if (Mask != null)
        {
            totalColors = Mask.CountNonZero();
        }
        return $"{(Subtract ? "-" : "+")}Spatial Filter({totalColors} colors)";
    }
}