using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Threading;
using System.Windows.Forms;

using DevExpress.XtraCharts;
using DevExpress.XtraLayout;
using LFP_Manager.DataStructure;

namespace LFP_Manager.Controls
{
    public delegate void CommandEvent(int sId, int cmd, int index, int flag, 
        ref CsDeviceData.DeviceModuleData.DeviceParamData aParam, 
        ref CsDeviceData.DeviceModuleData.DeviceCalibration aCalib);

    public partial class ucMainStatus : DevExpress.XtraEditors.XtraUserControl
    {
        #region CONSTANTS / ENUMS

        private const int HeaderHeight = 30;
        private const int RowHeight = 60;
        private const int BorderPadding = 2;

        private static class Colors
        {
            public static readonly Color Normal = Color.Green;
            public static readonly Color Warning = Color.Orange;
            public static readonly Color Fault = Color.Red;
            public static readonly Color Offline = Color.Red;
            public static readonly Color Charging = Color.Blue;
            public static readonly Color Discharging = Color.Magenta;
            public static readonly Color Default = Color.Black;
        }

        private enum OperatingStatus
        {
            Standby = 0,
            Charging = 1,
            Discharging = 2,
            Floating = 3
        }

        private enum BatteryStatus
        {
            Normal = 0,
            Warning = 1,
            Fault = 2,
            WarmingUp = 3,
            FaultAntiTheftComm = 4,
            FaultAntiTheftGyro = 5
        }

        #endregion

        #region FIELDS

        private CommConfig _config;
        private CsDeviceData _deviceData;

        private static CsDeviceData.DeviceModuleData dummy;

        private ucModuleMainHeader _moduleMainHeader;
        private ucModuleMainB[] _moduleMainRows;

        private LayoutControlItem[] _lcitemModuleMain;
        private EmptySpaceItem[] _emptySpaceItems;

        private int _moduleQty;

        private double _totalVoltage;
        private double _totalCurrent;
        private double _totalTemperature;
        private double _totalSoc;
        private double _totalSoh;

        private bool _active;

        public event CommandEvent OnCommand;

        #endregion

        #region CONSTRUCTORS

        public ucMainStatus()
        {
            InitializeComponent();

            _moduleQty = csConstData.SystemInfo.MAX_MODULE_SIZE;

            // 크기 변경 시 레이아웃 재배치
            this.Resize += (_, __) =>
            {
                if (_moduleMainRows != null && _moduleMainRows.Length > 0)
                    RepositionLayout();
            };

            // 🔧 리소스/이벤트 정리: Dispose 이벤트로 대체
            this.Disposed += UcMainStatus_Disposed;
        }

        #endregion

        #region PUBLIC API
        public void UpdateMainConfig(CommConfig config, CsDeviceData devData)
        {
            if (config == null || devData == null)
                return;

            _config = config;
            _deviceData = devData;

            _moduleQty = Math.Max(0, Math.Min(_config.ModuleQty, csConstData.SystemInfo.MAX_MODULE_SIZE));

            LoadModuleMain(_moduleQty);
            lcgbModuleMain.Invalidate();
        }

        public void Start(CommConfig config, CsDeviceData devData)
        {
            if (config == null || devData == null)
                return;

            _config = config;
            _deviceData = devData;
            _moduleQty = Math.Max(0, Math.Min(_config.ModuleQty, csConstData.SystemInfo.MAX_MODULE_SIZE));

            _active = true;
            tmrDisplay.Enabled = true;
        }
        public void Stop()
        {
            _active = false;
            tmrDisplay.Enabled = false;
        }

        public void UpdateData(CsDeviceData devData)
        {
            if (!_active || devData == null)
                return;

            _deviceData = devData;

            // 합계 값 계산 (0으로 나눔 방지, 스케일 고정)
            _totalVoltage = _deviceData.TotalData?.ValueData != null ? _deviceData.TotalData.ValueData.TotalVoltage / 10.0 : 0.0;
            _totalCurrent = _deviceData.TotalData?.ValueData != null ? _deviceData.TotalData.ValueData.TotalCurrent / 10.0 : 0.0;
            _totalSoc = _deviceData.TotalData?.ValueData != null ? _deviceData.TotalData.ValueData.TotalSOC / 10.0 : 0.0;
            _totalSoh = _deviceData.TotalData?.ValueData != null ? _deviceData.TotalData.ValueData.TotalSOH / 10.0 : 0.0;
            _totalTemperature = _deviceData.TotalData?.ValueData != null ? _deviceData.TotalData.ValueData.TotalTemp / 10.0 : 0.0;

            // 모듈 행 갱신 (범위/Null 안전)
            if (_moduleMainRows != null && _deviceData.ModuleData != null)
            {
                var count = Math.Min(Math.Min(_moduleMainRows.Length, _deviceData.ModuleData.Length), _moduleQty);
                for (var i = 0; i < count; i++)
                {
                    _moduleMainRows[i]?.UpdateData(ref _deviceData.ModuleData[i]);
                }
            }
        }

        private void UcMainStatus_Disposed(object sender, EventArgs e)
        {
            try
            {
                // 타이머 정지
                if (tmrDisplay != null)
                    tmrDisplay.Enabled = false;

                // 이벤트 구독 해제
                if (_moduleMainRows != null)
                {
                    foreach (var row in _moduleMainRows)
                    {
                        if (row != null)
                            row.OnCommand -= SetCmdEvent;
                    }
                }
            }
            catch { /* swallow on dispose */ }
        }

        #endregion

        #region INTERNAL LAYOUT

        private void LoadModuleMain(int mQty)
        {
            if (lcModuleMain == null || lcgbModuleMain == null)
                return;

            // 기존 컨트롤/아이템 제거 (성능 최적화)
            lcModuleMain.SuspendLayout();
            lcgbModuleMain.BeginUpdate();
            try
            {
                lcModuleMain.Controls.Clear();
                lcgbModuleMain.Items.Clear();

                _moduleMainHeader = new ucModuleMainHeader();
                _moduleMainRows = new ucModuleMainB[mQty];

                _lcitemModuleMain = new LayoutControlItem[mQty + 1];

                var emptySize = csConstData.SystemInfo.MAX_MODULE_SIZE - mQty;
                _emptySpaceItems = emptySize > 0 ? new EmptySpaceItem[emptySize] : Array.Empty<EmptySpaceItem>();

                // 헤더
                _lcitemModuleMain[0] = new LayoutControlItem
                {
                    Control = _moduleMainHeader,
                    Name = "lcitemModuleMainHeader",
                    Size = new Size(Math.Max(0, lcgbModuleMain.Width - 2 * BorderPadding), HeaderHeight),
                    Location = new Point(BorderPadding, BorderPadding),
                    TextVisible = false,
                    Padding = new DevExpress.XtraLayout.Utils.Padding(0)
                };

                // 본문 행
                var tWidth = Math.Max(0, lcgbModuleMain.Width - 2 * BorderPadding);
                var y = BorderPadding + HeaderHeight;

                var emptyIdx = 0;
                for (var i = 0; i < csConstData.SystemInfo.MAX_MODULE_SIZE; i++)
                {
                    if (i < mQty)
                    {
                        // 기존 구독 제거(안전)
                        if (_moduleMainRows[i] != null)
                            _moduleMainRows[i].OnCommand -= SetCmdEvent;

                        var moduleDataRef = _deviceData != null && _deviceData.ModuleData != null && _deviceData.ModuleData.Length > i
                            ? ref _deviceData.ModuleData[i]
                            : ref GetDummyModuleRef();

                        _moduleMainRows[i] = new ucModuleMainB(_config, i + 1, ref moduleDataRef);
                        _moduleMainRows[i].OnCommand += SetCmdEvent;

                        _lcitemModuleMain[i + 1] = new LayoutControlItem
                        {
                            Control = _moduleMainRows[i],
                            Name = $"lcitemModuleMain_{i + 1}",
                            Size = new Size(tWidth, RowHeight),
                            Location = new Point(BorderPadding, y),
                            TextVisible = false,
                            Padding = new DevExpress.XtraLayout.Utils.Padding(0)
                        };

                        y += RowHeight;
                    }
                    else if (_emptySpaceItems.Length > 0 && emptyIdx < _emptySpaceItems.Length)
                    {
                        _emptySpaceItems[emptyIdx] = new EmptySpaceItem
                        {
                            Size = new Size(tWidth, RowHeight),
                            Location = new Point(BorderPadding, y)
                        };
                        y += RowHeight;
                        emptyIdx++;
                    }
                }

                // 컨트롤 추가
                lcModuleMain.Controls.Add(_moduleMainHeader);
                for (var i = 0; i < mQty; i++)
                {
                    if (_moduleMainRows[i] != null)
                        lcModuleMain.Controls.Add(_moduleMainRows[i]);
                }

                // 레이아웃 아이템 구성
                var items = new List<BaseLayoutItem>(csConstData.SystemInfo.MAX_MODULE_SIZE + 1);
                items.Add(_lcitemModuleMain[0]);
                for (var i = 1; i < _lcitemModuleMain.Length; i++)
                {
                    if (_lcitemModuleMain[i] != null)
                        items.Add(_lcitemModuleMain[i]);
                }
                if (_emptySpaceItems.Length > 0)
                    items.AddRange(_emptySpaceItems);

                lcgbModuleMain.Items.AddRange(items.ToArray());
            }
            finally
            {
                lcgbModuleMain.EndUpdate();
                lcModuleMain.ResumeLayout();
                lcgbModuleMain.Invalidate();
            }
        }

        // 크기 변경 시 아이템 사이즈/좌표만 갱신 (재생성 X)
        private void RepositionLayout()
        {
            if (_lcitemModuleMain == null || _lcitemModuleMain.Length == 0 || lcgbModuleMain == null)
                return;

            lcgbModuleMain.BeginUpdate();
            try
            {
                var tWidth = Math.Max(0, lcgbModuleMain.Width - 2 * BorderPadding);

                // 헤더
                if (_lcitemModuleMain[0] != null)
                {
                    _lcitemModuleMain[0].Size = new Size(tWidth, HeaderHeight);
                    _lcitemModuleMain[0].Location = new Point(BorderPadding, BorderPadding);
                }

                // 행
                var y = BorderPadding + HeaderHeight;
                for (var i = 1; i < _lcitemModuleMain.Length; i++)
                {
                    var item = _lcitemModuleMain[i];
                    if (item == null) continue;

                    item.Size = new Size(tWidth, RowHeight);
                    item.Location = new Point(BorderPadding, y);
                    y += RowHeight;
                }

                // 빈공간
                if (_emptySpaceItems != null && _emptySpaceItems.Length > 0)
                {
                    foreach (var emp in _emptySpaceItems)
                    {
                        if (emp == null) continue;
                        emp.Size = new Size(tWidth, RowHeight);
                        emp.Location = new Point(BorderPadding, y);
                        y += RowHeight;
                    }
                }
            }
            finally
            {
                lcgbModuleMain.EndUpdate();
                lcgbModuleMain.Invalidate();
            }
        }

        // 모듈 데이터가 아직 없을 때 참조를 위한 더미(구조 동일)
        private ref CsDeviceData.DeviceModuleData GetDummyModuleRef()
        {
            // static 필드로 유지해도 무방
            return ref dummy;
        }
        #endregion

        #region EVENT BRIDGE

        private void SetCmdEvent(
            int sId, int cmd, int index, int flag,
            ref CsDeviceData.DeviceModuleData.DeviceParamData aParam,
            ref CsDeviceData.DeviceModuleData.DeviceCalibration aCalib)
        {
            var handler = OnCommand; // 레이스 방지
            handler?.Invoke(sId, cmd, index, flag, ref aParam, ref aCalib);
        }

        #endregion

        #region TIMER EVENT
        private void tmrDisplay_Tick(object sender, EventArgs e)
        {
            DisplayTotalValue();
            DisplayStatusAndAlarm();
        }

        #endregion

        #region DISPLAY FUNCTION
        private void DisplayTotalValue()
        {
            if (!_active || _deviceData?.TotalData == null)
                return;

            var fw = _deviceData.TotalData.IdentData?.FwVerStr ?? "N/A";
            var modules = _config != null ? _config.ModuleQty : _moduleQty;

            rtGraph.Text = $"Real Time Graph - V{fw} - {modules} Modules";

            dgTotalVoltage.Text = $"{_totalVoltage:0.0}";
            dgTotalCurrent.Text = $"{_totalCurrent:0.0}";
            dgTotalTemp.Text = $"{_totalTemperature:0.0}";
            dgTotalSOC.Text = $"{_totalSoc:0.0}";
            dgTotalSOH.Text = $"{_totalSoh:0.0}";

            chartVI?.Invalidate();
        }

        private void DisplayStatusAndAlarm()
        {
            if (_deviceData?.TotalData == null)
                return;

            if (_deviceData.TotalData.CommFail)
            {
                lbStatus.Text = "OFF-LINE";
                lbStatus.ForeColor = Colors.Offline;
                lbAlarm.Text = "OFF-LINE";
                lbAlarm.ForeColor = Colors.Offline;
                return;
            }

            // Operating Status
            var st = (OperatingStatus)(_deviceData.TotalData.StatusData?.status ?? -1);
            switch (st)
            {
                case OperatingStatus.Standby:
                    lbStatus.Text = "STANDBY";
                    lbStatus.ForeColor = Colors.Default;
                    break;
                case OperatingStatus.Charging:
                    lbStatus.Text = "CHARGING";
                    lbStatus.ForeColor = Colors.Charging;
                    break;
                case OperatingStatus.Discharging:
                    lbStatus.Text = "DISCHARGING";
                    lbStatus.ForeColor = Colors.Discharging;
                    break;
                case OperatingStatus.Floating:
                    lbStatus.Text = "FLOATING";
                    lbStatus.ForeColor = Colors.Default;
                    break;
                default:
                    lbStatus.Text = "UNKNOWN";
                    lbStatus.ForeColor = Colors.Default;
                    break;
            }

            // Battery Status
            var bs = (BatteryStatus)(_deviceData.TotalData.StatusData?.batteryStatus ?? -1);
            switch (bs)
            {
                case BatteryStatus.Normal:
                    lbAlarm.Text = "NORMAL";
                    lbAlarm.ForeColor = Colors.Normal;
                    break;
                case BatteryStatus.Warning:
                    lbAlarm.Text = "WARNING";
                    lbAlarm.ForeColor = Colors.Warning;
                    break;
                case BatteryStatus.Fault:
                    lbAlarm.Text = "FAULT";
                    lbAlarm.ForeColor = Colors.Fault;
                    break;
                case BatteryStatus.WarmingUp:
                    lbAlarm.Text = "WARMING UP";
                    lbAlarm.ForeColor = Colors.Warning;
                    break;
                case BatteryStatus.FaultAntiTheftComm:
                    lbAlarm.Text = "FAULT (Anti-Theft Comm.)";
                    lbAlarm.ForeColor = Colors.Fault;
                    break;
                case BatteryStatus.FaultAntiTheftGyro:
                    lbAlarm.Text = "FAULT (Anti-Theft Gyro)";
                    lbAlarm.ForeColor = Colors.Fault;
                    break;
                default:
                    lbAlarm.Text = $"UNKNOWN ({_deviceData.TotalData.StatusData?.batteryStatus})";
                    lbAlarm.ForeColor = Colors.Fault;
                    break;
            }
        }

        #endregion
    }
}
