
using Microsoft.Win32;
using Model;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Channels;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Threading;
using TSMasterCAN;
using UIShare.GlobalVariable;
using UIShare.UIViewModel;

namespace CANModule.ViewModels
{
    public class CANViewModel : BindableBase, IDialogAware
    {

        #region 属性
        private string _Title = "同星CAN";

        public string Title
        {
            get { return _Title; }
            set { SetProperty(ref _Title, value); }
        }
        private ObservableCollection<CanMessageShowVM> _CanMessageList = new();

        public ObservableCollection<CanMessageShowVM> CanMessageList
        {
            get { return _CanMessageList; }
            set { SetProperty(ref _CanMessageList, value); }
        }
        private string _DBCChannel = "0";

        public string DBCChannel
        {
            get { return _DBCChannel; }
            set { SetProperty(ref _DBCChannel, value); }
        }
        private bool _IsDirectlySend = false;

        public bool IsDirectlySend
        {
            get { return _IsDirectlySend; }
            set { SetProperty(ref _IsDirectlySend, value); }
        }
        private ObservableCollection<string> _Message;
        public ObservableCollection<string> Message
        {
            get { return _Message; }
            set { SetProperty(ref _Message, value); }
        }
        private ObservableCollection<string> _Signal;
        public ObservableCollection<string> Signal
        {
            get { return _Signal; }
            set { SetProperty(ref _Signal, value); }
        }
        byte channel;
        private string _selectedMessage;
        public string SelectedMessage
        {
            get { return _selectedMessage; }
            set
            {
                if (_selectedMessage != value)
                {
                    Signal = new(DBCParse.MsgDatabase[channel].Where(x => $"[0x{x.msg_id:X}]{x.msg_name}" == value).First().signal_Name);
                    _selectedMessage = value;
                    RaisePropertyChanged();
                }
            }
        }

        private string _selectedSignal;
        public string SelectedSignal
        {
            get { return _selectedSignal; }
            set { SetProperty(ref _selectedSignal, value); }
        }

        private string _signalValue;
        public string SignalValue
        {
            get { return _signalValue; }
            set { SetProperty(ref _signalValue, value); }
        }

        private string _cycleSendInterval;
        public string CycleSendInterval
        {
            get { return _cycleSendInterval; }
            set { SetProperty(ref _cycleSendInterval, value); }
        }

        private string _messageSendChannel = "0";
        public string MessageSendChannel
        {
            get { return _messageSendChannel; }
            set { SetProperty(ref _messageSendChannel, value); }
        }
        public string BLFPath
        {
            get => _systemConfig?.DefaultBLFFilePath ?? "";
            set
            {
                if (_systemConfig != null && _systemConfig.DefaultBLFFilePath != value)
                {
                    _systemConfig.DefaultBLFFilePath = value;
                    RaisePropertyChanged();
                }
            }
        }

        public string DBCPath
        {
            get => _systemConfig?.DefaultDBCFilePath ?? "";
            set
            {
                if (_systemConfig != null && _systemConfig.DefaultDBCFilePath != value)
                {
                    _systemConfig.DefaultDBCFilePath = value;
                    RaisePropertyChanged();
                }
            }
        }
        private bool _IsSaved;
        public bool IsSaved
        {
            get { return _IsSaved; }
            set { SetProperty(ref _IsSaved, value); }
        }
        public ObservableCollection<AutoDBCLoadItem> DBCAutoLoadList
        {
            get => _systemConfig?.DBCAutoLoadList ?? new ObservableCollection<AutoDBCLoadItem>();
        }

        private AutoDBCLoadItem _SelectedDcAutoLoad;
        public AutoDBCLoadItem SelectedDcAutoLoad
        {
            get { return _SelectedDcAutoLoad; }
            set { SetProperty(ref _SelectedDcAutoLoad, value); }
        }
        private TSMaster.APP_CHANNEL[] _appChannelNames = new[] { TSMaster.APP_CHANNEL.CHN1, TSMaster.APP_CHANNEL.CHN2, TSMaster.APP_CHANNEL.CHN3, TSMaster.APP_CHANNEL.CHN4 };
        public TSMaster.APP_CHANNEL[] APP_CHANNEL
        {
            get { return _appChannelNames; }
            set { SetProperty(ref _appChannelNames, value); }
        }

        private TSMaster.APP_CHANNEL _aIdxChn;
        public TSMaster.APP_CHANNEL AIdxChn
        {
            get { return _aIdxChn; }
            set { SetProperty(ref _aIdxChn, value); }
        }

        private int _aID;
        public int AID
        {
            get { return _aID; }
            set { SetProperty(ref _aID, value); }
        }

        private bool _aIsTx;
        public bool AIsTx
        {
            get { return _aIsTx; }
            set { SetProperty(ref _aIsTx, value); }
        }

        private bool _aIsExt;
        public bool AIsExt
        {
            get { return _aIsExt; }
            set { SetProperty(ref _aIsExt, value); }
        }

        private bool _aIsRemote;
        public bool AIsRemote
        {
            get { return _aIsRemote; }
            set { SetProperty(ref _aIsRemote, value); }
        }

        private byte _aDlc;
        public byte ADLC
        {
            get { return _aDlc; }
            set { SetProperty(ref _aDlc, value); }
        }

        private byte[] _aDataArray;
        public byte[] ADataArray
        {
            get { return _aDataArray; }
            set { SetProperty(ref _aDataArray, value); }
        }

        private bool _aIsFD = true;
        public bool AIsFD
        {
            get { return _aIsFD; }
            set { SetProperty(ref _aIsFD, value); }
        }

        private bool _aIsBRS = false;
        public bool AIsBRS
        {
            get { return _aIsBRS; }
            set { SetProperty(ref _aIsBRS, value); }
        }

        private bool _AutoSetting = true;
        public bool AutoSetting
        {
            get { return _AutoSetting; }
            set { SetProperty(ref _AutoSetting, value); }
        }

        private string _CustomMessage = "[00,11,22,33,AA,BB,CC,DD]";
        public string CustomMessage
        {
            get { return _CustomMessage; }
            set { SetProperty(ref _CustomMessage, value); }
        }

        private float _CustomSendCycleInterval = 0.0f;
        public float CustomSendCycleInterval
        {
            get { return _CustomSendCycleInterval; }
            set { SetProperty(ref _CustomSendCycleInterval, value); }
        }
        private bool _UpdateToDB;
        public bool UpdateToDB
        {
            get { return _UpdateToDB; }
            set { SetProperty(ref _UpdateToDB, value); }
        }
        #endregion
        #region 命令
        public ICommand SelectBLFPathCommand { get; set; }
        public ICommand SaveBLFPathCommand { get; set; }
        public ICommand StartTranscirbeCommand { get; set; }
        public ICommand EndTranscirbeCommand { get; set; }
        public ICommand CloseCommand { get; set; }
        public ICommand ConnectCanCommand { get; set; }
        public ICommand CloseCanCommand { get; set; }
        public ICommand ClearCycleCommand { get; set; }
        public ICommand UpLoadDBCCommand { get; set; }
        public ICommand ChangeDBCCommand { get; set; }
        public ICommand LoadDBCCommand { get; set; }
        public ICommand CheckDBCCommand { get; set; }
        public ICommand InitTSMasterCommand { get; set; }
        public ICommand ReleaseTSMasterCommand { get; set; }
        public ICommand LoadMessageCommand { get; set; }
        public ICommand SetAndSendMessageCommand { get; set; }
        public ICommand DeleteDcAutoLoadCommand { get; set; }
        public ICommand SendCustomMessageCommand { get; set; }

        #endregion
        private IEventAggregator _eventAggregator { get; set; }
        private CAN? _canfd;
        private SystemConfig? _systemConfig;
        private readonly DeviceManager _deviceManager;
        private IDialogService _dialogService { get; set; }
        CancellationTokenSource cts = new CancellationTokenSource();
        public CANViewModel(IContainerProvider containerProvider)
        {
            _eventAggregator = containerProvider.Resolve<IEventAggregator>();
            _systemConfig = containerProvider.Resolve<SystemConfig>();
            _deviceManager = containerProvider.Resolve<DeviceManager>();
            _canfd = _deviceManager.CANFD;
            _dialogService = containerProvider.Resolve<IDialogService>();
            SelectBLFPathCommand = new DelegateCommand(SelectBLFPath);
            SaveBLFPathCommand = new DelegateCommand(SaveBLFPath);
            StartTranscirbeCommand = new DelegateCommand(StartTranscirbe);
            EndTranscirbeCommand = new DelegateCommand(EndTranscirbe);
            CloseCommand = new DelegateCommand(Close);
            ConnectCanCommand = new DelegateCommand(ConnectCan);
            CloseCanCommand = new DelegateCommand(CloseCan);
            ClearCycleCommand = new DelegateCommand(ClearCycle);
            UpLoadDBCCommand = new DelegateCommand(UpLoadDBC);
            ChangeDBCCommand = new DelegateCommand(ChangeDBC);
            LoadDBCCommand = new DelegateCommand(LoadDBC);
            CheckDBCCommand = new DelegateCommand(CheckDBC);
            InitTSMasterCommand = new DelegateCommand(InitTSMaster);
            ReleaseTSMasterCommand = new DelegateCommand(ReleaseTSMaster);
            SetAndSendMessageCommand = new DelegateCommand(SetAndSendMessage);
            LoadMessageCommand = new DelegateCommand(LoadMessage);
            DeleteDcAutoLoadCommand = new DelegateCommand(DeleteDcAutoLoad);
            SendCustomMessageCommand = new DelegateCommand(SendCustomMessage);
        }

        #region 命令
        private void SendCustomMessage()
        {
            try
            {
                ADataArray = 报文转换(CustomMessage);
                if (ADataArray.Length > byte.MaxValue) throw new Exception("报文数量超过上限!");
                if (AutoSetting)
                {
                    ADLC = (byte)ADataArray.Length;
                }
            }
            catch (Exception ex)
            {
                _dialogService.ShowDialog("MessageDialog", new DialogParameters
                {
                    { "message", $"报文转换失败：{ex.Message}" }
                });
                return;
            }
            var re = CAN.SendMsg(AIdxChn, AID, AIsTx, AIsExt,
         AIsRemote, ADLC, ADataArray, AIsFD, AIsBRS, UpdateToDB, CustomSendCycleInterval);
        }
        private void DeleteDcAutoLoad()
        {
            DBCAutoLoadList.Remove(SelectedDcAutoLoad);
            ConfigService.Save(_systemConfig);
        }
        private void LoadMessage()
        {
            if (int.TryParse(MessageSendChannel, out int channel))
            {
                Message = new(DBCParse.MsgDatabase[channel].Select(s => $"[0x{s.msg_id:X}]{s.msg_name}"));
            }
            else
            {

            }
        }

        private void SetAndSendMessage()
        {
            if (int.TryParse(CycleSendInterval, out int sendPeriod) && double.TryParse(SignalValue, out double SValue) && byte.TryParse(MessageSendChannel, out byte c))
            {
                channel = c;
                var message = SelectedMessage.Split(']')[1];
                var re = CAN.SetSignalValue(channel, message, SelectedSignal, SValue, IsDirectlySend, sendPeriod);
            }
            else
            {

            }
        }

        private void ReleaseTSMaster()
        {
            CAN.Release();
        }

        private void InitTSMaster()
        {
            var re = CAN.Init("ACP");
        }
        private void UpLoadDBC()
        {
            var re = CAN.UnLoadDBC();
        }

        private void ChangeDBC()
        {
            var dialog = new OpenFileDialog
            {
                Title = "更换DBC文件",
                Filter = "DBC 文件 (*.dbc)|*.dbc|所有文件 (*.*)|*.*",
                DefaultExt = ".dbc",
            };
            if (dialog.ShowDialog() == true)
            {
                DBCPath = Path.GetFullPath(dialog.FileName);
                ConfigService.Save(_systemConfig);
            }
        }

        private void LoadDBC()
        {
            if (int.TryParse(DBCChannel, out var channel))
            {
                var re = CAN.LoadDBC(DBCPath, [channel], out _);
                if (re == 0 && IsSaved)
                {
                    var item = DBCAutoLoadList.Where(s => s.DBCChannel == channel).FirstOrDefault();
                    if (item == null)
                    {
                        DBCAutoLoadList.Add(new AutoDBCLoadItem
                        {
                            DBCFilePath = DBCPath,
                            DBCChannel = channel
                        });
                    }
                    else
                    {
                        DBCAutoLoadList.Remove(item);
                        DBCAutoLoadList.Add(new AutoDBCLoadItem
                        {
                            DBCFilePath = DBCPath,
                            DBCChannel = channel
                        });
                    }
                    ConfigService.Save(_systemConfig);
                }
            }
            else
            {

            }
        }

        private void CheckDBC()
        {
            if (int.TryParse(DBCChannel, out var channel))
            {
                _dialogService.ShowDialog("DBCInfo", new DialogParameters
                {
                    { "can_Network", DBCParse.can_Network },
                    { "MsgDatabase", DBCParse.MsgDatabase[channel] }
                });
            }

        }
        private void ClearCycle()
        {
            var re = CAN.DeleteCyclicMsgs();
        }

        private void CloseCan()
        {
            var re = CAN.DisConnect();
        }

        private void ConnectCan()
        {
            var re = CAN.Connect();
        }
        private void EndTranscirbe()
        {
            var re = CAN.StopLogging();
        }

        private void StartTranscirbe()
        {
            var re = CAN.StartLogging(BLFPath);
        }

        private void SaveBLFPath()
        {
            _systemConfig.DefaultBLFFilePath = BLFPath;
            ConfigService.Save(_systemConfig);
        }

        private void SelectBLFPath()
        {
            var dialog = new SaveFileDialog
            {
                Title = "保存 CAN报文回放 BLF 文件",
                Filter = "BLF 文件 (*.blf)|*.blf|所有文件 (*.*)|*.*",
                DefaultExt = ".blf",
                FileName = "log.blf",
                OverwritePrompt = true
            };
            if (dialog.ShowDialog() == true)
            {
                BLFPath = Path.GetFullPath(dialog.FileName);
            }
        }
        private void Close()
        {
            RequestClose.Invoke();
        }
        #endregion
        public byte[] 报文转换(string s)
        {
            s = s.Replace("[", string.Empty).Replace("]", string.Empty);
            var strs = s.Split(',', StringSplitOptions.RemoveEmptyEntries);
            byte[] bytes = new byte[strs.Length];
            for (int i = 0; i < strs.Length; i++)
            {
                bytes[i] = Convert.ToByte(strs[i], 16);
            }
            return bytes;
        }

        private async Task Refresh(CancellationToken ct = default)
        {
            while (ct.IsCancellationRequested == false)
            {
                var temp = CAN.RealTimeMessages.Select(s => s.Value).ToArray();
                foreach (var item in temp)
                {
                    var find = CanMessageList.FirstOrDefault(s => s.报文ID == item.FIdentifier);
                    if (find != null)
                    {
                        if (find.通道 != item.FIdxChn) find.通道 = item.FIdxChn;
                        if (find.报文ID != item.FIdentifier) find.报文ID = item.FIdentifier;
                        if (find.时间戳 != item.FTimeUS) find.时间戳 = item.FTimeUS;
                        if (find.FD != item.FIsFD) find.FD = item.FIsFD;
                        if (find.IsTx != item.FIsTx) find.IsTx = item.FIsTx;

                        var 长度改变 = find.长度 == item.FDLC;
                        var 数据改变 = find.Bytes.SequenceEqual(item.FData);
                        if (长度改变 || 数据改变)
                        {
                            find.长度 = item.FDLC;
                            Array.Copy(item.FData, 0, find.Bytes, 0, 64);
                            find.报文 = 十六进制字符串转换(item.FData.AsSpan(0, find.长度));
                        }
                    }
                    else
                    {
                        var 报文temp = new CanMessageShowVM()
                        {
                            通道 = item.FIdxChn,
                            报文ID = item.FIdentifier,
                            时间戳 = item.FTimeUS,
                            FD = item.FIsFD,
                            IsTx = item.FIsTx,
                            长度 = item.FDLC,
                            报文 = 十六进制字符串转换(item.FData.AsSpan(0, item.FDLC)),
                        };
                        Array.Copy(item.FData, 0, 报文temp.Bytes, 0, 64);
                        Application.Current.Dispatcher.Invoke(() =>
                        {
                            CanMessageList.Add(报文temp);
                        });
                    }

                }
                await Task.Delay(50, ct);
            }
        }
        string 十六进制字符串转换(Span<byte> s)
        {
            if (s == null || s.Length == 0)
                return "[]";

            var sb = new StringBuilder();
            sb.Append('[');
            for (int i = 0; i < s.Length; i++)
            {
                sb.Append("0x");
                sb.Append(s[i].ToString("X2"));
                if (i < s.Length - 1)
                    sb.Append(", ");
            }
            sb.Append(']');
            return sb.ToString();
        }
        #region dialog规范
        public DialogCloseListener RequestClose { get; set; }

        public bool CanCloseDialog()
        {
            return true;
        }

        public void OnDialogClosed()
        {
            cts.Cancel();
        }

        public void OnDialogOpened(IDialogParameters parameters)
        {
            Task.Run(() => Refresh(cts.Token), cts.Token);
        }


        #endregion
    }
}
