using Aitex.Core.RT.DataCenter;
using Aitex.Core.RT.SCCore;
using MECF.Framework.RT.EquipmentLibrary.HardwareUnits.Temps.Filters;
using System;
using Aitex.Core.RT.Log;

namespace MECF.Framework.RT.EquipmentLibrary.HardwareUnits.Temps;

public sealed class TempDataFilter
{
    #region Variables

    private readonly string _scBase;
    private readonly MoveAverageFilter _mafFilter;
    private readonly KalmanFilter _kalmanFilter;

    private IFilter _activeFilter = null;
    private FilterTypes _filterType = FilterTypes.None;

    #endregion

    #region Ctor

    public TempDataFilter(string module, string sensorName, double pollIntervalMs, double minimalTemp = 600,
        string scBasePath = "TempSensors")
    {
        Module = module;
        SensorName = sensorName;
        _scBase = scBasePath;

        _mafFilter =
            new MoveAverageFilter(module, $"{module}.Temp.Filter.{sensorName}.MAF", $"{scBasePath}.Filters.MAF");
        _kalmanFilter = new KalmanFilter(module, $"{module}.Temp.Filter.{sensorName}.Kalman",
            $"{scBasePath}.Filters.Kalman", pollIntervalMs);
    }

    #endregion

    #region Properties

    public string Module { get; }

    public string SensorName { get; }

    public FilterTypes FilterType
    {
        get => _filterType;
        private set
        {
            switch (value)
            {
                case FilterTypes.None:
                    _activeFilter = null;
                    break;

                case FilterTypes.MAF:
                    _activeFilter = _mafFilter;
                    break;

                case FilterTypes.Kalman:
                    _activeFilter = _kalmanFilter;
                    break;
            }

            if (_filterType != value)
            {
                // 如果切换滤波器类型，重置当前滤波器，以防止滤波结果包含很久以前的数据导致滤波错误。
                _activeFilter?.Reset();
            }

            _filterType = value;
        }
    }

    /// <summary>
    /// 返回测温原始温度值。
    /// </summary>
    internal double Raw { get; private set; }

    /// <summary>
    /// 返回滤波后的温度。
    /// </summary>
    internal double Filtered { get; private set; }

    #endregion

    #region Methods

    public bool Initialize(out string reason)
    {
        reason = "";

        DATA.Subscribe($"{Module}.Temp.Filter.{SensorName}.FilterType", () => (int)FilterType);
        DATA.Subscribe($"{Module}.Temp.Filter.{SensorName}.RAW", () => Raw);
        DATA.Subscribe($"{Module}.Temp.Filter.{SensorName}.Filtered", () => Filtered);

        var scName = $"{_scBase}.FilterType";
        FilterType = ConvertToFilterType(SC.SafeGetStringValue(scName, "None"));
        SC.RegisterValueChangedCallback(scName, value =>
        {
            if (value is string filterType)
                FilterType = ConvertToFilterType(filterType);
            else
                LOG.Error($"{SensorName} Invalid value for Filter Type: {value}. Expected an string.");
        });

        var isFilterInitSucceeded = true;
        if (!_mafFilter.Initialize(out var reasonMaf))
        {
            LOG.Error($"{SensorName} Move Average Filter initialization failed: {reasonMaf}");
            isFilterInitSucceeded = false;
        }

        if (!_kalmanFilter.Initialize(out var reasonKalman))
        {
            LOG.Error($"{SensorName} Move Kalman Filter initialization failed: {reasonKalman}");
            isFilterInitSucceeded = false;
        }

        if (!isFilterInitSucceeded)
        {
            reason = $"{SensorName} Filter initialization failed, see log for details";
            return false;
        }

        return true;
    }

    /// <summary>
    /// 添加一个新温度值。
    /// </summary>
    /// <param name="temp"></param>
    public void Update(double temp)
    {
        Raw = temp;
        Filtered = _activeFilter?.Update(temp) ?? Raw;
    }

    #endregion

    private FilterTypes ConvertToFilterType(string type)
    {
        if (Enum.TryParse<FilterTypes>(type, true, out var ft))
            return ft;
        else
        {
            LOG.Error($"{this} Unable to convert {type} to filter type.");
            return FilterTypes.None;
        }
    }

}