using MainShell.Vision;
using SemiconductorVisionAlgorithm.SemiParams;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;

namespace MainShell.Process
{
    public class WaferDieRecognizer : IWaferDieRecognizer
    {
        private readonly IFindDieService _findDieService;

        public WaferDieRecognizer(IFindDieService findDieService)
        {
            _findDieService = findDieService ?? throw new ArgumentNullException(nameof(findDieService));
        }

        public FindDieImageRequest BuildRequest(WaferCaptureFrame frame, WaferDiePositionContext context)
        {
            FindDieImageRequest request = new FindDieImageRequest();
            FindDieParameters parameters = new FindDieParameters();
            parameters.CurrentRuler = frame == null
                ? new Point(0.0d, 0.0d)
                : new Point(frame.TriggerPoint.X, frame.TriggerPoint.Y);
            parameters.OverlapX = context != null && context.ScanSettings != null ? context.ScanSettings.OverlapRateX : 0d;
            parameters.OverlapY = context != null && context.ScanSettings != null ? context.ScanSettings.OverlapRateY : 0d;
            parameters.DieWidth = context != null && context.WaferRecipe != null && context.WaferRecipe.WaferInfo != null
                ? context.WaferRecipe.WaferInfo.DieSizeX
                : 0d;
            parameters.DieHeight = context != null && context.WaferRecipe != null && context.WaferRecipe.WaferInfo != null
                ? context.WaferRecipe.WaferInfo.DieSizeY
                : 0d;
            parameters.ScoreThreshold = 0.8d;
            parameters.TemplatePath = string.Empty;
            parameters.SerialNumber = string.Empty;
            request.Parameters = parameters;
            request.TimeoutMilliseconds = 3000;
            return request;
        }

        public async Task<WaferRecognitionFrameResult> RecognizeAsync(WaferCaptureFrame frame, WaferDiePositionContext context, CancellationToken cancellationToken)
        {
            if (frame == null)
            {
                throw new ArgumentNullException(nameof(frame));
            }

            WaferRecognitionFrameResult frameResult = new WaferRecognitionFrameResult();
            frameResult.SequenceId = frame.SequenceId;

            if (frame.Image == null)
            {
                frameResult.IsSuccess = false;
                frameResult.ErrorMessage = "DiePosition: capture frame image is null.";
                return frameResult;
            }

            FindDieImageRequest request = BuildRequest(frame, context);
            VisionProcessResult<FindDiesResult> result = await _findDieService.ProcessMultipleImageAsync(frame.Image, request, cancellationToken).ConfigureAwait(false);
            if (result == null || !result.Succeeded || result.Data == null)
            {
                frameResult.IsSuccess = false;
                frameResult.ErrorMessage = result == null ? "DiePosition: recognition returned null result." : result.Message;
                return frameResult;
            }

            List<double> rowsReal = new List<double>();
            List<double> columnsReal = new List<double>();
            List<double> angles = new List<double>();
            List<double> overlapRows = new List<double>();
            List<double> overlapColumns = new List<double>();
            List<double> overlapAngles = new List<double>();

            foreach (FindDieResult item in result.Data.Items)
            {
                if (item.IsOverlap)
                {
                    overlapRows.Add(item.CenterY);
                    overlapColumns.Add(item.CenterX);
                    overlapAngles.Add(item.Angle);
                }
                else
                {
                    rowsReal.Add(item.CenterY);
                    columnsReal.Add(item.CenterX);
                    angles.Add(item.Angle);
                }
            }

            frameResult.IsSuccess = true;
            frameResult.ErrorMessage = null;
            frameResult.RowsReal = rowsReal.ToArray();
            frameResult.ColumnsReal = columnsReal.ToArray();
            frameResult.Angles = angles.ToArray();
            frameResult.OverlapRows = overlapRows.ToArray();
            frameResult.OverlapColumns = overlapColumns.ToArray();
            frameResult.OverlapAngles = overlapAngles.ToArray();
            frameResult.UniqueCount = frameResult.RowsReal.Length;
            frameResult.OverlapCount = frameResult.OverlapRows.Length;
            return frameResult;
        }
    }
}