using Hawkeye.VisionBuilder.Workflow.Datatypes;
using Hawkeye.VisionBuilder.Workflow.Operations.Attributes;
using OpenCvSharp;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using Hawkeye.VisionBuilder.Workflow.DataTransfer;


namespace Hawkeye.VisionBuilder.Workflow.Operations.AI;

[Category("AI")]
[IgnoreOperation]
public class Color128HalfOperation:BaseOperation
{
    public Color128HalfOperation()
    {
        _cSharpDataTransferMQRPC = PythonModelProxyRPC.GetInterface();
        _cSharpDataTransferMQRPC.TransferData<object>(new MethodCall("activate_model", "segment128half"));
        var sizeEncoded = _cSharpDataTransferMQRPC.TransferData<object[]>(new MethodCall("get_accept_size"));
        var size = sizeEncoded.Select(Convert.ToInt32).ToArray();
        _imageWidth = size[0];
        _imageHeight = size[1];
        CanHaveProcessingError = false;
    }

    public string FilterClasses { get; set; } = "0";
    public FilePath ModelFilePath { get; set; } = new FilePath() { Format = "Model file(*.h5)|*.h5" };


    private readonly CSharpDataTransferMQRPC _cSharpDataTransferMQRPC;
    private readonly int _imageWidth;
    private readonly int _imageHeight;

    private bool _initialized = false;

    protected override void InterpretInternal(Context context)
    {
        if(!CheckImageExists(context))return;
        if(!CheckColorful(context))return;

        _cSharpDataTransferMQRPC.TransferData<object>(new MethodCall("activate_model", "segment128half"));

        if (!_initialized)
        {
            if (!File.Exists(ModelFilePath.Path))
            {
                this.SetError("Model file not found");
                return;
            }
            _cSharpDataTransferMQRPC.TransferData<object>(new MethodCall("load_model", ModelFilePath.Path));
            _initialized = true;
        }

        var currentImage = context.ActiveImage;

        var rightColor = currentImage.ImageData.CvtColor(ColorConversionCodes.BGR2RGB);
        var resized = rightColor.Resize(new Size(_imageHeight, _imageWidth));
        int dataSize = resized.Rows * resized.Cols * resized.ElemSize();
        var byteArray = new byte[dataSize];
        Marshal.Copy(resized.Data, byteArray, 0, dataSize);

        var allowed = FilterClasses.Split(',',StringSplitOptions.RemoveEmptyEntries).Select(x => Convert.ToInt32(x)).ToArray();

        var allowedFlags = new byte[128];
        foreach (var i in allowed)
        {
            allowedFlags[i] = 1;
        }

        var resultEncoded = _cSharpDataTransferMQRPC.TransferData<object[]>(new MethodCall("predict", byteArray));

        var result = resultEncoded.Select(Convert.ToByte).ToArray();

        var resultColor = result.Select(x =>
                allowedFlags[x]==1
                    ? (byte)255
                    : (byte)0)
            .ToArray();

        // black and white mask
        var mask = new Mat(_imageHeight, _imageWidth, MatType.CV_8UC1);
        mask.SetArray(resultColor);

        var maskResized = mask.Resize(new Size(currentImage.ImageData.Width, currentImage.ImageData.Height));

        context.ActiveImage = new HawkeyeImage() {ImageData = maskResized};


        Result = true;
        

    }

    public override void SetParameters(Dictionary<string, object> parameters)
    {
        base.SetParameters(parameters);
        _initialized = false;
    }

    public override void Save(BinaryWriter bw)
    {
        base.Save(bw);
        bw.Write(FilterClasses);
        bw.Write(ModelFilePath.Path);

    }

    public override void Load(BinaryReader br)
    {
        base.Load(br);
        FilterClasses = br.ReadString();
        ModelFilePath.Path = br.ReadString();
    }

    public override void Save(Dictionary<string, object> dict)
    {
        base.Save(dict);
        dict[nameof(FilterClasses)] = FilterClasses;
        dict[nameof(ModelFilePath)] = ModelFilePath.Path;
    }

    public override void Load(Dictionary<string, object> dict)
    {
        base.Load(dict);
        if (dict.ContainsKey(nameof(FilterClasses)))
            FilterClasses = dict[nameof(FilterClasses)].ToString();
        if (dict.ContainsKey(nameof(ModelFilePath)))
            ModelFilePath.Path = dict[nameof(ModelFilePath)].ToString();
    }
}