// /************************************************************************
// * @file         RecipeLockPanel.xaml.cs
// * @author   Su Liang
// * @date       2023/03/08
// *
// * @copyright &copy Sicentury Inc.
// *
// * @brief
// *
// * @details
// *
// *
// * *****************************************************************************/

using System;
using System.Diagnostics;
using System.Security.Cryptography;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Effects;
using Aitex.Core.Util;
using MECF.Framework.Common.DataCenter;
using MECF.Framework.Common.OperationCenter;
using Panel = System.Windows.Controls.Panel;

namespace MECF.Framework.UI.Client.Ctrlib.Controls
{
    public partial class PanelLocker
    {
        /// <summary>
        /// 锁定时背景模糊半径
        /// </summary>
        private const double BLUR_RADIUS = 30;

        /// <summary>
        /// 默认密码admin的SHA256
        /// </summary>
        private const string DEF_PASSWORD = "8C6976E5B5410415BDE908BD4DEE15DFB167A9C873FC4BB8A81F6F2AB448A918";

        // 阻止密码攻击定时器
        private readonly DeviceTimer _timPassAttackDetector;

        // 密码连续重试次数
        private int _retryTimes;

        // 自动锁定计时器
        private readonly Stopwatch _swAutoLock;

        private PeriodicJob _pjobAutoLock;

        private int _timeoutAutoLock = int.MaxValue;

        public PanelLocker()
        {
            InitializeComponent();

            _timPassAttackDetector = new DeviceTimer();
            _retryTimes = 0;

            _pjobAutoLock = new PeriodicJob(int.MaxValue, () =>
            {
                Dispatcher.Invoke(Lock);
                return true;
            }, "AutoLockRecipeEditor");

            // Lock面板加载后，或重新激活后，将焦点自动设置到PasswordBox
            Loaded += (sender, args) =>
            {
                txtPass.Focus();
            };
        }

        #region Dps

        public static readonly DependencyProperty LockTargetProperty = DependencyProperty.Register(
            nameof(LockTarget), typeof(Panel), typeof(PanelLocker), new PropertyMetadata(default(Panel), (sender, args) =>
            {
                // 初次拿到LockTarget对象时，锁定对象
                if (sender is PanelLocker pl && args.NewValue is Panel)
                {
                    pl.Lock();
                }
            }));

        /// <summary>
        /// 设置或返回待锁定的界面
        /// </summary>
        public Panel LockTarget
        {
            get => (Panel)GetValue(LockTargetProperty);
            set => SetValue(LockTargetProperty, value);
        }


        public static readonly DependencyProperty ScPathPasswordProperty = DependencyProperty.Register(
            nameof(ScPathPassword), typeof(string), typeof(PanelLocker), new PropertyMetadata("System.Recipe.EditorPassword"));

        /// <summary>
        /// 设置或返回SC中存放密码的节点。
        /// </summary>
        public string ScPathPassword
        {
            get => (string)GetValue(ScPathPasswordProperty);
            set => SetValue(ScPathPasswordProperty, value);
        }


        public static readonly DependencyProperty ScPathIsResetPasswordProperty = DependencyProperty.Register(
            nameof(ScPathIsResetPassword), typeof(string), typeof(PanelLocker), new PropertyMetadata("System.Recipe.ResetEditorPassword"));

        /// <summary>
        /// 设置或返回SC中复位密码的节点。
        /// </summary>
        public string ScPathIsResetPassword
        {
            get => (string)GetValue(ScPathIsResetPasswordProperty);
            set => SetValue(ScPathIsResetPasswordProperty, value);
        }

        public static readonly DependencyProperty OpPathSetNewPasswordProperty = DependencyProperty.Register(
            nameof(OpPathSetNewPassword), typeof(string), typeof(PanelLocker), new PropertyMetadata("System.SetNewRecipeEditorPassword"));

        /// <summary>
        /// 设置或返回RT中注册的用于设置新密码的OP。
        /// </summary>
        public string OpPathSetNewPassword
        {
            get => (string)GetValue(OpPathSetNewPasswordProperty);
            set => SetValue(OpPathSetNewPasswordProperty, value);
        }

        public static readonly DependencyProperty OpPathResetPasswordToDefaultProperty = DependencyProperty.Register(
            nameof(OpPathResetPasswordToDefault), typeof(string), typeof(PanelLocker), new PropertyMetadata("System.ResetRecipeEditorPassword"));

        public string OpPathResetPasswordToDefault
        {
            get => (string)GetValue(OpPathResetPasswordToDefaultProperty);
            set => SetValue(OpPathResetPasswordToDefaultProperty, value);
        }

        #endregion

        #region Methods


        protected override void OnRender(DrawingContext drawingContext)
        {
            base.OnRender(drawingContext);
            txtPass.Focus();
        }

        public void Lock()
        {
            txtPass.Password = "";
            txtInfo.Text = "";

            LockTarget.Effect = new BlurEffect();
            Visibility = Visibility.Visible;
            var aniBlurFadeOut = new DoubleAnimation(0, BLUR_RADIUS, new Duration(TimeSpan.FromMilliseconds(300)));
            LockTarget.Effect.BeginAnimation(BlurEffect.RadiusProperty, aniBlurFadeOut);

            // 停止自动锁定计时器
            //_swAutoLock.Stop();
        }

        /// <summary>
        /// 重置自动锁定超时计时器
        /// </summary>
        public void ResetAutoLockTimer()
        {
            _pjobAutoLock.Stop();
            _pjobAutoLock.Start();
        }

        /// <summary>
        /// 校验密码
        /// </summary>
        /// <returns></returns>
        private bool CheckPassword()
        {
            // 是否请求重置密码
            var reqResetPass = (bool)QueryDataClient.Instance.Service.GetConfig(ScPathIsResetPassword);
            if (reqResetPass)
            {
                // 密码重置为admin
                InvokeClient.Instance.Service.DoOperation(OpPathResetPasswordToDefault, DEF_PASSWORD);
            }

            // 读取系统配置中的Password，如果读取失败，使用默认密码admin
            var passInSc = QueryDataClient.Instance.Service.GetConfig(ScPathPassword).ToString();
            if (string.IsNullOrEmpty(passInSc))
                passInSc = DEF_PASSWORD;

            using (var sha = SHA256.Create())
            {
                var bytesHash = sha.ComputeHash(Encoding.UTF8.GetBytes(txtPass.Password));
                var passInput = BitConverter.ToString(bytesHash).Replace("-", "");
                if (passInput == passInSc)
                {
                    txtPass.Password = "";
                    return true;
                }
            }

            // 检测是否5s内重试密码5次以上。
            if (_timPassAttackDetector.IsIdle() || _timPassAttackDetector.IsTimeout())
            {
                _timPassAttackDetector.Start(5000);
                _retryTimes = 0;
            }
            else
            {
                _retryTimes++;
                if (_retryTimes > 5)
                {
                    btnUnlock.IsEnabled = false;
                    txtPass.IsEnabled = false;

                    // 如果5s内重试的次数大于5次，禁用解锁窗口5秒钟
                    Task.Run(() =>
                    {
                        var deniedSec = 5;
                        while (deniedSec-- > 0)
                        {
                            Dispatcher.Invoke(() =>
                            {
                                txtInfo.Text = $"You have retried too many times, try again in {deniedSec} seconds";
                            });

                            Thread.Sleep(1000);
                        }

                        Dispatcher.Invoke(() =>
                        {
                            txtInfo.Text = "";
                            btnUnlock.IsEnabled = true;
                            txtPass.IsEnabled = true;
                        });

                    });

                }
            }

            txtInfo.Text = "Incorrect Password";
            txtPass.Password = "";
            return false;
        }

        #endregion

        #region Events

        private void BtnUnlock_OnClick(object sender, RoutedEventArgs e)
        {
            if (!CheckPassword())
            {
                txtPass.Focus();
                return;
            }

            if (LockTarget.Effect is BlurEffect eff)
            {
                var aniBlurFadeOut = new DoubleAnimation(BLUR_RADIUS, 0, new Duration(TimeSpan.FromMilliseconds(300)));
                eff.BeginAnimation(BlurEffect.RadiusProperty, aniBlurFadeOut);
            }

            LockTarget.Effect = null;
            this.Visibility = Visibility.Collapsed;


            // 启动自动锁定计时器
            /*var autoLockTimeout = (int)QueryDataClient.Instance.Service.GetConfig("System.RecipeEditorAutoLockTimeout");
            if (autoLockTimeout <= 0)
                autoLockTimeout = 60;
            _swAutoLock.Interval = autoLockTimeout;
            _swAutoLock.Start();*/
        }

        private void TxtPass_OnPreviewKeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
                BtnUnlock_OnClick(this, new RoutedEventArgs());
        }

        #endregion



    }
}