using Hawkeye.VisionBuilder.Workflow.Datatypes.Elements.Poly;
using Hawkeye.VisionBuilder.Workflow.Operations.Attributes;

using OpenCvSharp;
using static Hawkeye.VisionBuilder.Workflow.Operations.FindManyBlobsOperation;
using Point = OpenCvSharp.Point;

namespace Hawkeye.VisionBuilder.Workflow.Operations.AI;

[Category("AI")]
public class YoloPickDetected:BaseOperation
{
    public string SlotName { get; set; } = "Image";
    public int TypeId { get; set; }

    public int MinArea { get; set; } = 0;
    public int MaxArea { get; set; } = 99999;
    public int MinWidth { get; set; } = 0;
    public int MaxWidth { get; set; } = 99999;
    public int MinHeight { get; set; } = 0;
    public int MaxHeight { get; set; } = 99999;
    

    protected override void InterpretInternal(Context context)
    {
        Status = "No blobs found";
        var image=context.Memory[SlotName];
        var threshold= image.ImageData.InRange(TypeId, TypeId);
        var contours = threshold
            .FindContoursAsArray(RetrievalModes.List, ContourApproximationModes.ApproxSimple);
        
        //case: no blobs found
        if (contours.Length == 0)
        {
            
            return;
        }

        var validContours = new List<Point[]>();

        foreach (var contour in contours)
        {
            var boundingRect = Cv2.BoundingRect(contour);
            var area = Cv2.ContourArea(contour);
            if (boundingRect.Width >= MinWidth && boundingRect.Width <= MaxWidth &&
                boundingRect.Height >= MinHeight && boundingRect.Height <= MaxHeight &&
                area >= MinArea && area <= MaxArea
                )
            {
                validContours.Add(contour);
            }
        }

        int badCount = 0;
        foreach (var contourMatch in validContours)
        {
            PolyElement poly = new PolyElement() { IsGood = false };

            poly.Points = contourMatch.Select(x => new Vector2(x.X, x.Y)).ToArray();

            context.GraphicsElements.Add(poly);
            badCount++;
        }

        

        if (badCount > 0)
        {
            // find smallest contour size
            var smallest = validContours.OrderBy(x => Cv2.ContourArea(x)).First();
            var smallestBoundingRect = Cv2.BoundingRect(smallest);
            var biggest = validContours.OrderBy(x => Cv2.ContourArea(x)).Last();
            var biggestBoundingRect = Cv2.BoundingRect(biggest);
            var smallestArea = Cv2.ContourArea(smallest);
            var biggestArea = Cv2.ContourArea(biggest);
            Status = $"Found: {badCount} Min area:{smallestArea} Max area:{biggestArea}";
            
            
            
            Result = false;
            return;
        }

        Result = true;



    }

    public override void Save(BinaryWriter bw)
    {
        base.Save(bw);
        bw.Write(SlotName);
        bw.Write(TypeId);
        bw.Write(MinWidth);
        bw.Write(MaxWidth);
        bw.Write(MinHeight);
        bw.Write(MaxHeight);
        bw.Write(MinArea);
        bw.Write(MaxArea);
    }

    public override void Load(BinaryReader br)
    {
        base.Load(br);
        SlotName = br.ReadString();
        TypeId = br.ReadInt32();
        MinWidth = br.ReadInt32();
        MaxWidth = br.ReadInt32();
        MinHeight = br.ReadInt32();
        MaxHeight = br.ReadInt32();
        MinArea = br.ReadInt32();
        MaxArea = br.ReadInt32();
    }

    public override void Save(Dictionary<string, object> dict)
    {
        base.Save(dict);
        dict[nameof(SlotName)] = SlotName;
        dict[nameof(TypeId)] = TypeId;
        dict[nameof(MinWidth)] = MinWidth;
        dict[nameof(MaxWidth)] = MaxWidth;
        dict[nameof(MinHeight)] = MinHeight;
        dict[nameof(MaxHeight)] = MaxHeight;
        dict[nameof(MinArea)] = MinArea;
        dict[nameof(MaxArea)] = MaxArea;
    }

    public override void Load(Dictionary<string, object> dict)
    {
        base.Load(dict);
        if (dict.ContainsKey(nameof(SlotName)))
            SlotName = dict[nameof(SlotName)].ToString();
        if (dict.ContainsKey(nameof(TypeId)))
            TypeId = Convert.ToInt32(dict[nameof(TypeId)]);
        if (dict.ContainsKey(nameof(MinWidth)))
            MinWidth = Convert.ToInt32(dict[nameof(MinWidth)]);
        if (dict.ContainsKey(nameof(MaxWidth)))
            MaxWidth = Convert.ToInt32(dict[nameof(MaxWidth)]);
        if (dict.ContainsKey(nameof(MinHeight)))
            MinHeight = Convert.ToInt32(dict[nameof(MinHeight)]);
        if (dict.ContainsKey(nameof(MaxHeight)))
            MaxHeight = Convert.ToInt32(dict[nameof(MaxHeight)]);
        if (dict.ContainsKey(nameof(MinArea)))
            MinArea = Convert.ToInt32(dict[nameof(MinArea)]);
        if (dict.ContainsKey(nameof(MaxArea)))
            MaxArea = Convert.ToInt32(dict[nameof(MaxArea)]);
    }
}