using LFP_Manager.DataStructure;
using LFP_Manager.Utils;
using System;
using System.Windows.Forms;

namespace LFP_Manager.Controls
{
    public partial class ucCalibration : DevExpress.XtraEditors.XtraUserControl
    {
        #region DELEGATE

        public delegate void setCalibUpdate(object sender);
        public delegate void setCalibCommand(int mode, int index, int flag, 
            ref CsDeviceData.DeviceModuleData.DeviceParamData aParm, 
            ref CsDeviceData.DeviceModuleData.DeviceCalibration aCalib);
        public delegate Int32 getBattData(int item, int cno);

        #endregion

        #region ENUMS

        private enum ControlLevel
        {
            User = 0,
            Technician = 1,
            Engineer = 2,
            Master = 3
        }

        private enum CommandMode
        {
            SetCapacity = 15,
            SetChargeMode = 16,
            SetDateTime = 17,
            SetAntiTheft = 18,
            ClearAntiTheft = 19,
            SetRS485Timeout = 20,
            SetBalanceVoltage = 21,
            SetBalanceDiff = 22
        }

        #endregion

        #region VARIABLES

        const int CALC_INDEX = 6;

        CommConfig Config;

        CsDeviceData.DeviceModuleData ModuleData;
        CsDeviceData.DeviceModuleData.DeviceCalibration rCalib;
        CsDeviceData.DeviceModuleData.DeviceCalibration wCalib;

        CsDeviceData.DeviceModuleData.DeviceParamData rParam;

        public event setCalibCommand OnCommand = null;

        int wFlag = 0;

        int dFlag;

        int PasswordResult;

        #endregion

        #region CONSTRUCTORS

        // Battery No:
        //     0: No 1,3,5,7,9,11,13,15 ODD
        //     1: No 2,4,6,8,10,12,14 Even
        public ucCalibration()
        {
            InitializeComponent();

            ComponentLoad();

            Config = new CommConfig();

            dFlag = 0;
        }

        private void ComponentLoad()
        {
            CbNewChaMode.Clear();
            for (int i = 0; i < csConstData.SystemInfo.CHG_MODE.Length; i++)
            {
                CbNewChaMode.Properties.Items.Add(csConstData.SystemInfo.CHG_MODE[i]);
            }

            teNewCapacity.KeyPress += TextBox_KeyPress;
            teNewSoc.KeyPress += TextBox_KeyPress;
            TeCommTimeoutNew.KeyPress += TextBox_KeyPress;
            TeChgModeValueNew.KeyPress += TextBox_KeyPress2;
        }
        #endregion

        #region EXT EVENT FUNCTION

        private void OnCommnadEvent(int mode, int index, int flag, 
            ref CsDeviceData.DeviceModuleData.DeviceParamData aParam, 
            ref CsDeviceData.DeviceModuleData.DeviceCalibration aCalib)
        {
            OnCommand?.Invoke(mode, index, flag, ref aParam, ref aCalib);
        }

        #endregion

        #region PUBLIC FUCTIONS

        public void UpdateConfig(CommConfig aConfig)
        {
            Config = aConfig;
        }
        public void UpdateData(CsDeviceData.DeviceModuleData mData, CsDeviceData.DeviceModuleData.DeviceCalibration aCalib)
        {
            ModuleData = mData;
            rCalib = aCalib;
            DisplayCalib();
            UpdateNewCalib();
        }

        private void UpdateNewCalib()
        {
            if (ModuleData != null)
            {
                if (wFlag == 0)
                {
                    teNewCapacity.Text = teCurrCapacity.Text;
                    teNewSoc.Text = teCurrSoc.Text;

                    wFlag = 1;
                }
            }
        }
        #endregion

        #region DISPLAY DATA

        private void DisplayCalib()
        {
            if (ModuleData != null)
            {
                teCurrCapacity.Text = string.Format("{0}", ModuleData.ValueData.designedCapacity / 10);
                teCurrSoc.Text = string.Format("{0}", ModuleData.ValueData.SOC / 10);

                switch (ModuleData.CalibrationData.ChaMode.Mode)
                {
                    case 0:
                        TeChaMode.Text = csConstData.SystemInfo.CHG_MODE[0];
                        break;
                    case 1:
                        TeChaMode.Text = csConstData.SystemInfo.CHG_MODE[1];
                        break;
                    case 2:
                        TeChaMode.Text = csConstData.SystemInfo.CHG_MODE[2];
                        break;
                    case 4:
                        TeChaMode.Text = csConstData.SystemInfo.CHG_MODE[3];
                        break;
                    case 8:
                        TeChaMode.Text = csConstData.SystemInfo.CHG_MODE[4];
                        break;
                    default:
                        TeChaMode.Text = string.Format("UNKNOWN({0})", ModuleData.CalibrationData.ChaMode.Mode);
                        break;
                }
                TeChgModeValueCurr.Text = string.Format("{0:0.00}", Convert.ToDouble(ModuleData.CalibrationData.ChaMode.Value) / 100);

                TeCurrDateTime.Text = ModuleData.BmsDateTime.DateTimeStr;

                // Anti-Theft Data Display
                if (ModuleData.CalibrationData.AntiTheft.GyroScope == 0)
                {
                    TeAntiTheftGyroCurr.Text = "DISABLE";
                }
                else
                {
                    TeAntiTheftGyroCurr.Text = "ENABLE";
                }
                TeSensitive.Text = string.Format("{0}", ModuleData.CalibrationData.AntiTheft.GyroScope);

                // Anti-Theft - RS-485 Comm. Timeout
                TeCommTimeout.Text = string.Format("{0}", ModuleData.CalibrationData.AntiTheft.Comm);

                if (dFlag == 0)
                {
                    CbNewChaMode.SelectedIndex = 1;
                    switch (ModuleData.CalibrationData.ChaMode.Mode)
                    {
                        case 0:
                            CbNewChaMode.SelectedIndex = 0;
                            break;
                        case 1:
                            CbNewChaMode.SelectedIndex = 1;
                            break;
                        case 2:
                            CbNewChaMode.SelectedIndex = 2;
                            break;
                        case 4:
                            CbNewChaMode.SelectedIndex = 3;
                            break;
                        case 8:
                            CbNewChaMode.SelectedIndex = 4;
                            break;
                        default:
                            CbNewChaMode.Text = string.Format("UNKNOWN({0})", ModuleData.CalibrationData.ChaMode.Mode);
                            break;
                    }

                    TeChgModeValueNew.Text = TeChgModeValueCurr.Text;

                    dFlag = 1;
                }
            }
        }

        #endregion

        #region BUTTON EVENT

        private void TextBox_KeyPress(object sender, KeyPressEventArgs e)
        {
            csUtils.TypingOnlyNumber(sender, e, false, false);
        }
        private void TextBox_KeyPress2(object sender, KeyPressEventArgs e)
        {
            csUtils.TypingOnlyNumber(sender, e, true, false);
        }

        private void btnCapacitySet_Click(object sender, EventArgs e)
        {
            try
            {
                if (!ValidateNumericInput(teNewCapacity.Text, "Capacity") ||
                    !ValidateNumericInput(teNewSoc.Text, "SOC"))
                {
                    return;
                }

                wCalib = rCalib.DeepCopy();
                wCalib.CapCalib.DesignCapacity = Convert.ToInt32(teNewCapacity.Text) * 10;
                wCalib.CapCalib.SocValue = Convert.ToInt32(teNewSoc.Text);

                OnCommnadEvent((int)CommandMode.SetCapacity, CALC_INDEX, 1, ref rParam, ref wCalib);
            }
            catch (Exception ex)
            {
                ShowError($"Failed to set capacity: {ex.Message}");
            }
        }

        private void BtnChaModeSet_Click(object sender, EventArgs e)
        {
            try
            {
                if (string.IsNullOrEmpty(CbNewChaMode.Text))
                {
                    ShowError("Please select a charge mode");
                    return;
                }

                if (CbNewChaMode.SelectedIndex > 1 &&
                    !ValidateNumericInput(TeChgModeValueNew.Text, "Charge Mode Value"))
                {
                    return;
                }

                wCalib = rCalib.DeepCopy();
                wCalib.ChaMode.Mode = CbNewChaMode.SelectedIndex;
                wCalib.ChaMode.Value = (int)(Convert.ToDouble(TeChgModeValueNew.Text) * 100);

                OnCommnadEvent((int)CommandMode.SetChargeMode, CALC_INDEX, 1, ref rParam, ref wCalib);
            }
            catch (Exception ex)
            {
                ShowError($"Failed to set charge mode: {ex.Message}");
            }
        }
        private void BtnBmsDateTimeSet_Click(object sender, EventArgs e)
        {
            try
            {
                if (string.IsNullOrEmpty(TeNewDateTime.Text))
                {
                    ShowError("Please enter a date/time value");
                    return;
                }

                DateTime dateTime = Convert.ToDateTime(TeNewDateTime.Text);
                int iDateTime = CalculateDateTimeValue(dateTime);

                wCalib = rCalib.DeepCopy();
                wCalib.BmsDateTime.sValue[0] = (short)(iDateTime >> 16);
                wCalib.BmsDateTime.sValue[1] = (short)(iDateTime >> 0);

                OnCommnadEvent((int)CommandMode.SetDateTime, CALC_INDEX, 1, ref rParam, ref wCalib);
            }
            catch (Exception ex)
            {
                ShowError($"Failed to set date/time: {ex.Message}");
            }
        }
        private int CalculateDateTimeValue(DateTime dateTime)
        {
            return ((dateTime.Year - 2000) << 26)
                | (dateTime.Month << 22)
                | (dateTime.Day << 17)
                | (dateTime.Hour << 12)
                | (dateTime.Minute << 6)
                | (dateTime.Second << 0);
        }

        private void BtnGetCurrTime_Click(object sender, EventArgs e)
        {
            TeNewDateTime.Text = string.Format("{0:yyyy-MM-dd HH:mm:ss}", DateTime.Now);
        }

        private void BtnClearAntiTheftProtect_Click(object sender, EventArgs e)
        {
            wCalib = rCalib.DeepCopy();
            wCalib.AntiTheft.GyroScope = Config.GyroSensitive;

            OnCommnadEvent(19, CALC_INDEX, 1, ref rParam, ref wCalib);
        }

        private void PassWordResultProc(int result)
        {
            PasswordResult = result;
        }

        private void BtnAntiTheftEnable_Click(object sender, EventArgs e)
        {
            wCalib = rCalib.DeepCopy();
            wCalib.AntiTheft.GyroScope = Config.GyroSensitive;

            OnCommnadEvent(18, CALC_INDEX, 1, ref rParam, ref wCalib);
        }

        private void BtnAntiTheftDisable_Click(object sender, EventArgs e)
        {
            wCalib = rCalib.DeepCopy();
            wCalib.AntiTheft.GyroScope = 0;

            OnCommnadEvent(18, CALC_INDEX, 1, ref rParam, ref wCalib);
        }

        private void BtnRS485TimeoutSet_Click(object sender, EventArgs e)
        {
            string stTimeout = TeCommTimeoutNew.Text;
            int Timeout = 0;

            try
            {
                Timeout = Convert.ToInt32(stTimeout);
            }
            catch (Exception)
            {
                MessageBox.Show("Timeout data Format Error", "Exception", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            wCalib = rCalib.DeepCopy();
            wCalib.AntiTheft.Comm = Timeout;

            OnCommnadEvent(20, CALC_INDEX, 1, ref rParam, ref wCalib);
        }
        #endregion

        #region COMPONENT EVENT
        private void CbNewChaMode_SelectedIndexChanged(object sender, EventArgs e)
        {
            switch (CbNewChaMode.SelectedIndex)
            {
                case 0:
                    TeChgModeValueNew.Enabled = false;
                    break;
                case 1:
                    TeChgModeValueNew.Enabled = false;
                    break;
                case 2:
                    TeChgModeValueNew.Enabled = true;
                    break;
                case 3:
                    TeChgModeValueNew.Enabled = true;
                    break;
                case 4:
                    TeChgModeValueNew.Enabled = true;
                    break;
                default:
                    TeChgModeValueNew.Enabled = false;
                    break;
            }
        }
        #endregion

        #region FORM EVENT
        private void ucCalibration_Load(object sender, EventArgs e)
        {
            CalibConfig_ReLoad();
        }

        private void CalibConfig_ReLoad()
        {
            var level = (ControlLevel)Config.ControlLevel;

            btnCapacitySet.Enabled = level == ControlLevel.Master;
            BtnChaModeSet.Enabled = level >= ControlLevel.Engineer;
            BtnBmsDateTimeSet.Enabled = level >= ControlLevel.Engineer;
            BtnClearAntiTheftProtect.Enabled = level >= ControlLevel.Technician;
            BtnAntiTheftEnable.Enabled = level >= ControlLevel.Engineer;
            BtnAntiTheftDisable.Enabled = level >= ControlLevel.Engineer;
            BtnRS485TimeoutSet.Enabled = level >= ControlLevel.Technician;
        }

        #endregion

        #region VALIDATION METHODS

        private bool ValidateNumericInput(string input, string fieldName)
        {
            if (string.IsNullOrEmpty(input))
            {
                ShowError($"Please enter a value for {fieldName}");
                return false;
            }

            if (!int.TryParse(input, out _))
            {
                ShowError($"Invalid numeric value for {fieldName}");
                return false;
            }

            return true;
        }

        private void ShowError(string message)
        {
            MessageBox.Show(message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }

        #endregion
    }
}
