using MainShell.Hardware;
using MainShell.Motion;
using MainShell.HeightMeasure.Model;
using MaxwellFramework.Core.Attributes;
using MXJM.Parameter.Maintance;
using System;

namespace MainShell.HeightMeasure.Service
{
    [Singleton]
    public class HeightMeasureMotionService
    {
        private readonly HardwareManager _hardware;
        private readonly SafeAxisMotion _safeAxisMotion;
        private readonly StagePlatformMotionService _stagePlatformMotionService;

        public HeightMeasureMotionService(HardwareManager hardware, SafeAxisMotion safeAxisMotion, StagePlatformMotionService stagePlatformMotionService)
        {
            _hardware = hardware ?? throw new ArgumentNullException(nameof(hardware));
            _safeAxisMotion = safeAxisMotion ?? throw new ArgumentNullException(nameof(safeAxisMotion));
            _stagePlatformMotionService = stagePlatformMotionService ?? throw new ArgumentNullException(nameof(stagePlatformMotionService));
        }

        public void MoveCalibrationAndStagePlatformHeights(double czCalibrationHeight, double stageDatumHeight)
        {
            _safeAxisMotion.MoveAbs(AxisName.Axis_SZ, czCalibrationHeight);
            _stagePlatformMotionService.MoveFlat(stageDatumHeight);
        }

        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_Y2, nameof(_hardware.Axis_Y2)), yPosition));
        }

        public void MovePhsAndNeedle(double xPosition, double yPosition, double zPosition)
        {
            _safeAxisMotion.SafeMove(
                MotionMoveRequest.ForAxis(GetRequiredAxis(_hardware.Axis_X1, nameof(_hardware.Axis_X1)), xPosition),
                MotionMoveRequest.ForAxis(GetRequiredAxis(_hardware.Axis_Y1, nameof(_hardware.Axis_Y1)), yPosition));
            _safeAxisMotion.MoveAbs(GetRequiredAxis(_hardware.Axis_Z1, nameof(_hardware.Axis_Z1)), zPosition);
        }

        public void MoveGlassMeasurePoint(TeachPoint point)
        {
            if (point == null)
            {
                throw new ArgumentNullException(nameof(point));
            }

            MovePhsAndNeedle(point.X, point.Y, point.Z);
        }

        public void MoveWaferMeasurePoint(TeachPoint point)
        {
            if (point == null)
            {
                throw new ArgumentNullException(nameof(point));
            }

            MoveWsAvoidance(point.X, point.Y);
            _safeAxisMotion.MoveAbs(GetRequiredAxis(_hardware.Axis_Z1, nameof(_hardware.Axis_Z1)), point.Z);
        }

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

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

            return axis;
        }
    }
}