using MainShell.Hardware;
using MainShell.Log;
using MainShell.Motion;
using MaxwellFramework.Core.Attributes;
using MwFramework.Device;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace MainShell.AlgorithmCalib.Service
{
    /// <summary>
    /// 旋转表标定运动服务
    /// 对标 OriginCalibrationMotionService
    /// </summary>
    [Singleton]
    public class RotateMatixFormCalibMotionService
    {
        private const int PositionSettleDelayMilliseconds = 200;

        private readonly HardwareManager _hardware;
        private readonly SafeAxisMotion _safeAxisMotion;

        public RotateMatixFormCalibMotionService(HardwareManager hardware, SafeAxisMotion safeAxisMotion)
        {
            _hardware = hardware ?? throw new ArgumentNullException(nameof(hardware));
            _safeAxisMotion = safeAxisMotion ?? throw new ArgumentNullException(nameof(safeAxisMotion));
        }

        #region 低级运动方法

        public void SafeMove(IAxis axis, double position)
        {
            _safeAxisMotion.SafeMove(
                MotionMoveRequest.ForAxis(GetRequiredAxis(axis, nameof(axis)), position));
        }

        public async Task SafeMoveAsync(IAxis axis, double position, CancellationToken cancellationToken = default)
        {
            var result = await _safeAxisMotion.SafeMoveAsync(
                cancellationToken,
                MotionMoveRequest.ForAxis(GetRequiredAxis(axis, nameof(axis)),position)).ConfigureAwait(false);
            result.EnsureSuccess();
        }

        public void MoveWsAvoidance(double xPosition, double yPosition)
        {
            _safeAxisMotion.SafeMove(
                MotionMoveRequest.ForAxis(GetRequiredAxis(_hardware.Axis_X2,nameof(_hardware.Axis_X2)), xPosition),
                MotionMoveRequest.ForAxis(GetRequiredAxis(_hardware.Axis_Y1,nameof(_hardware.Axis_Y1)), yPosition));
        }

        public async Task MoveWsAvoidanceAsync(double xPosition, double yPosition,CancellationToken cancellationToken = default)
        {
            var result = await _safeAxisMotion.SafeMoveAsync(
                cancellationToken,
                MotionMoveRequest.ForAxis(GetRequiredAxis(_hardware.Axis_X2,nameof(_hardware.Axis_X2)), xPosition),
                MotionMoveRequest.ForAxis(GetRequiredAxis(_hardware.Axis_Y1,nameof(_hardware.Axis_Y1)), yPosition)).ConfigureAwait(false);
            result.EnsureSuccess();
        }

        public void RotatePos(double rotatePosition)
        {
            _safeAxisMotion.SafeMove(
                MotionMoveRequest.ForAxis(GetRequiredAxis(_hardware.Axis_WS_R,nameof(_hardware.Axis_WS_R)), rotatePosition));
        }

        public async Task RotatePosAsync(double rotatePosition, CancellationToken cancellationToken = default)
        {
            var result = await _safeAxisMotion.SafeMoveAsync(
                cancellationToken,
                MotionMoveRequest.ForAxis(GetRequiredAxis(_hardware.Axis_WS_R,nameof(_hardware.Axis_WS_R)), rotatePosition)).ConfigureAwait(false);
            result.EnsureSuccess();
        }

        #endregion

        #region 批量运动方法（对标 OriginCalibrationMotionService）

        /// <summary>
        /// 批量移动避让轴
        /// </summary>
        public async Task MoveAvoidanceAxesAsync(CancellationToken cancellationToken = default)
        {
            // 移动 X1 到避让位
            if (_hardware.Axis_PHS_X1 != null)
            {
                string.Format("旋转表标定移动避让轴 X1 到位置。").LogInfo();
                await SafeMoveAsync(_hardware.Axis_PHS_X1, 0,cancellationToken).ConfigureAwait(false);
            }
        }

        /// <summary>
        /// 等待轴稳定后采集实际位置
        /// </summary>
        public async Task<Dictionary<string, double>> CollectActualPositionsAsync(
            IEnumerable<string> axisNames,
            CancellationToken cancellationToken = default)
        {
            string.Format("旋转表标定等待 {0} ms 以稳定轴反馈。",PositionSettleDelayMilliseconds).LogInfo();
            await Task.Delay(PositionSettleDelayMilliseconds,cancellationToken).ConfigureAwait(false);

            var positions = new Dictionary<string, double>(StringComparer.Ordinal);
            foreach (var axisName in axisNames)
            {
                if (string.IsNullOrWhiteSpace(axisName)) continue;

                var axis = _hardware.GetAxisByName(axisName);
                if (axis == null) continue;

                positions[axisName] = GetActualPosition(axis);
                string.Format("旋转表标定已采集轴'{0}'的实际位置：{1:F3}。", axisName,positions[axisName]).LogInfo();
            }

            return positions;
        }

        #endregion

        private static double GetActualPosition(IAxis axis)
        {
            return axis.State != null ? axis.State.ActualPos : axis.GetPositionImmediate();
        }

        private static IAxis GetRequiredAxis(IAxis axis, string axisPropertyName)
        {
            if (axis == null)
                throw new InvalidOperationException(string.Format("Axis '{0}' is not available.",axisPropertyName));
            return axis;
        }
    }
}