using MainShell.Common;
using MainShell.Hardware;
using MaxwellFramework.Core.Attributes;
using MwFramework.Device;
using System;

namespace MainShell.Models
{
    [Singleton]
    public class VisionParController
    {
        private readonly HardwareManager _hardwareManager;

        public VisionParController(HardwareManager hardwareManager)
        {
            _hardwareManager = hardwareManager ?? throw new ArgumentNullException(nameof(hardwareManager));
        }

        public void SetTopPositionVisionPars(CameraConfig cameraConfig, UpCamLightConfig upCamLightConfig)
        {
            SetTopPositionCameraPars(cameraConfig);
            SetUpCamLightPars(upCamLightConfig);
        }

        public void SetBottomPositionVisionPars(CameraConfig cameraConfig, DownCamLightConfig downCamLightConfig)
        {
            SetBottomPositionCameraPars(cameraConfig);
            SetDownCamLightPars(downCamLightConfig);
        }

        public void SetMapVisionPars(CameraConfig cameraConfig, MapCamLightConfig mapCamLightConfig)
        {
            SetMapCameraPars(cameraConfig);
            SetMapCamLightPars(mapCamLightConfig);
        }

        public void SetTopPositionCameraPars(CameraConfig config)
        {
            MwCamera camera = GetCamera(CameraType.TopPositionCamera);
            SetCameraPars(camera, config);
        }

        public void SetBottomPositionCameraPars(CameraConfig config)
        {
            MwCamera camera = GetCamera(CameraType.MapCamera);
            SetCameraPars(camera, config);
        }

        public void SetMapCameraPars(CameraConfig config)
        {
            MwCamera camera = GetCamera(CameraType.MapCamera);
            SetCameraPars(camera, config);
        }

        public void ConfigureCameraForStream(CameraType cameraType)
        {
            MwCamera camera = GetCamera(cameraType);
            EnsureCameraAvailable(camera, cameraType);

            RetryMechanism.RetryIfNeeded(
                () => camera.SetTriggerMode(CameraTriggerMode.Off) == DriverLibResult.DriverLibNoError,
                string.Format("{0} 设置连续流触发模式失败", camera.ConnectId.CategoryName));
        }

        public void ConfigureCameraForSoftTrigger(CameraType cameraType, double? triggerDelay = null)
        {
            MwCamera camera = GetCamera(cameraType);
            EnsureCameraAvailable(camera, cameraType);

            RetryMechanism.RetryIfNeeded(
                () => camera.SetTriggerMode(CameraTriggerMode.On) == DriverLibResult.DriverLibNoError,
                string.Format("{0} 设置软触发模式失败", camera.ConnectId.CategoryName));

            RetryMechanism.RetryIfNeeded(
                () => camera.SetTriggerSource(CameraTriggerSource.Software) == DriverLibResult.DriverLibNoError,
                string.Format("{0} 设置软触发源失败", camera.ConnectId.CategoryName));

            if (triggerDelay.HasValue)
            {
                RetryMechanism.RetryIfNeeded(
                    () => camera.SetTriggerDelay(triggerDelay.Value) == DriverLibResult.DriverLibNoError,
                    string.Format("{0} 设置触发延时失败", camera.ConnectId.CategoryName));
            }
        }

        public void StartCameraGrabbing(CameraType cameraType)
        {
            MwCamera camera = GetCamera(cameraType);
            EnsureCameraAvailable(camera, cameraType);

            RetryMechanism.RetryIfNeeded(
                () =>
                {
                    DriverLibResult result = camera.StartGrabbing();
                    return result == DriverLibResult.DriverLibNoError || result == DriverLibResult.DriverLibDeviceAlreadyGrabbing;
                },
                string.Format("{0} 启动抓流失败", camera.ConnectId.CategoryName));
        }

        public void StopCameraGrabbing(CameraType cameraType)
        {
            MwCamera camera = GetCamera(cameraType);
            EnsureCameraAvailable(camera, cameraType);

            RetryMechanism.RetryIfNeeded(
                () =>
                {
                    DriverLibResult result = camera.StopGrabbing();
                    return result == DriverLibResult.DriverLibNoError || result == DriverLibResult.DriverLibDeviceNotGrabbing;
                },
                string.Format("{0} 停止抓流失败", camera.ConnectId.CategoryName));
        }

        public void EnsureCameraGrabbing(CameraType cameraType)
        {
            MwCamera camera = GetCamera(cameraType);
            EnsureCameraAvailable(camera, cameraType);

            if (!camera.IsGrabbing)
            {
                throw new InvalidOperationException(string.Format("相机 '{0}' 当前未处于抓流状态。", cameraType));
            }
        }

        public void SetCameraPars(MwCamera camera, CameraConfig config)
        {
            if (camera == null)
            {
                throw new ArgumentNullException(nameof(camera));
            }

            if (config == null)
            {
                throw new ArgumentNullException(nameof(config));
            }

            RetryMechanism.RetryIfNeeded(
                () => camera.SetExposureTime(config.ExposureTime) == DriverLibResult.DriverLibNoError,
                string.Format("{0} 设置曝光失败", camera.ConnectId.CategoryName));

            RetryMechanism.RetryIfNeeded(
                () => camera.SetGain(config.Gain) == DriverLibResult.DriverLibNoError,
                string.Format("{0} 设置增益失败", camera.ConnectId.CategoryName));
        }

        public void SetDownCamLightPars(DownCamLightConfig config)
        {
            if (config == null)
            {
                throw new ArgumentNullException(nameof(config));
            }

            _hardwareManager.SetDownPointBlueLightIntensity(config.PointBlueLight);
            _hardwareManager.SetDownRingBlueLightIntensity(config.RingBlueLight);
            _hardwareManager.SetDownPointRedLightIntensity(config.PointRedLight);
            _hardwareManager.SetDownRingRedLightIntensity(config.RingRedLight);
        }

        public void SetUpCamLightPars(UpCamLightConfig config)
        {
            if (config == null)
            {
                throw new ArgumentNullException(nameof(config));
            }

            _hardwareManager.SetUpPointBlueLightIntensity(config.PointBlueLight);
            _hardwareManager.SetUpRingBlueLightIntensity(config.RingBlueLight);
            _hardwareManager.SetUpPointRedLightIntensity(config.PointRedLight);
            _hardwareManager.SetUpRingRedLightIntensity(config.RingRedLight);
            _hardwareManager.SetUpRedBackLightIntensity(config.RedBackLight);
        }

        public void SetMapCamLightPars(MapCamLightConfig config)
        {
            if (config == null)
            {
                throw new ArgumentNullException(nameof(config));
            }

            _hardwareManager.SetMapBlueLightIntensity(config.BlueLight);
            _hardwareManager.SetMapRedLightIntensity(config.RedLight);
        }

        private MwCamera GetCamera(CameraType cameraType)
        {
            return _hardwareManager.GetCamera(cameraType).Camera;
        }

        private static void EnsureCameraAvailable(MwCamera camera, CameraType cameraType)
        {
            if (camera == null)
            {
                throw new InvalidOperationException(string.Format("相机 '{0}' 不存在。", cameraType));
            }

            if (!camera.IsOpen)
            {
                throw new InvalidOperationException(string.Format("相机 '{0}' 未打开。", cameraType));
            }
        }
    }
}
