using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Media.Animation;
using AR;
using arCtl;
using COMM;
using Project.StateMachine;

namespace Project
{
    /// <summary>
    /// 장치 연결 및 상태 전송을 담당하는 별도 태스크
    /// </summary>
    public partial class fMain
    {
        // 장치 관리 태스크 관련
        private Task deviceManagementTask;
        private CancellationTokenSource deviceManagementCts;
        private volatile bool isDeviceManagementRunning = false;

        /// <summary>
        /// 장치 관리 태스크 시작 (IDLE 상태 진입 시 호출)
        /// </summary>
        public void StartDeviceManagementTask()
        {
            if (isDeviceManagementRunning)
            {
                PUB.log.Add("DeviceManagement", "이미 실행 중입니다.");
                return;
            }

            isDeviceManagementRunning = true;
            deviceManagementCts = new CancellationTokenSource();

            deviceManagementTask = Task.Factory.StartNew(
                () => DeviceManagementWorker(deviceManagementCts.Token),
                deviceManagementCts.Token,
                TaskCreationOptions.LongRunning,
                TaskScheduler.Default
            );

            PUB.log.Add("DeviceManagement", "장치 관리 태스크 시작");
        }

        /// <summary>
        /// 장치 관리 태스크 종료
        /// File : /device/_DeviceManagement.cs
        /// </summary>
        public void StopDeviceManagementTask()
        {
            if (!isDeviceManagementRunning)
                return;

            isDeviceManagementRunning = false;

            try
            {
                deviceManagementCts?.Cancel();

                if (deviceManagementTask != null)
                {
                    if (!deviceManagementTask.Wait(3000)) // 3초 대기
                    {
                        PUB.log.AddE("DeviceManagement:태스크 종료 대기 시간 초과");
                    }
                }
            }
            catch (Exception ex)
            {
                PUB.log.AddE($"DeviceManagement 종료 중 오류: {ex.Message}");
            }
            finally
            {
                deviceManagementCts?.Dispose();
                deviceManagementCts = null;
                deviceManagementTask = null;
                PUB.log.Add("DeviceManagement", "장치 관리 태스크 종료");
            }
        }

        /// <summary>
        /// 장치 관리 워커 (별도 태스크에서 실행)
        /// - 장치 연결 관리 (AGV, XBee, BMS)
        /// - 자동 상태 전송 (XBee, BMS)
        /// </summary>
        private void DeviceManagementWorker(CancellationToken cancellationToken)
        {
            PUB.log.Add("DeviceManagementWorker", "시작");

            DateTime lastXbeStatusSendTime = DateTime.Now;
            DateTime lastBmsQueryTime = DateTime.Now;

            while (!cancellationToken.IsCancellationRequested && isDeviceManagementRunning)
            {
                try
                {
                    // 상태머신이 IDLE 이상이고 CLOSING 미만일 때만 동작
                    if (PUB.sm.Step >= eSMStep.IDLE && PUB.sm.Step < eSMStep.CLOSING)
                    {
                        // ========== 1. 장치 연결 관리 ==========
                        ManageDeviceConnections();

                        // ========== 2. XBee 상태 전송 ==========
                        if (PUB.XBE != null && PUB.XBE.IsOpen)
                        {
                            var tsXbe = DateTime.Now - lastXbeStatusSendTime;
                            if (tsXbe.TotalSeconds >= PUB.setting.interval_xbe)
                            {
                                lastXbeStatusSendTime = DateTime.Now;
                                ThreadPool.QueueUserWorkItem(_ =>
                                {
                                    try
                                    {
                                        PUB.XBE.SendStatus();
                                    }
                                    catch (Exception ex)
                                    {
                                        PUB.log.AddE($"XBee SendStatus 오류: {ex.Message}");
                                    }
                                });
                            }
                        }

                        // ========== 3. BMS 쿼리 및 배터리 경고 ==========
                        if (PUB.BMS != null && PUB.BMS.IsOpen)
                        {
                            var tsBms = DateTime.Now - lastBmsQueryTime;
                            if (tsBms.TotalSeconds >= PUB.setting.interval_bms)
                            {
                                lastBmsQueryTime = DateTime.Now;
                                ThreadPool.QueueUserWorkItem(_ =>
                                {
                                    try
                                    {
                                        PUB.BMS.SendQuery();
                                    }
                                    catch (Exception ex)
                                    {
                                        PUB.log.AddE($"BMS SendQuery 오류: {ex.Message}");
                                    }
                                });
                            }

                            // 배터리 경고음
                            try
                            {
                                Update_BatteryWarnSpeak();
                            }
                            catch (Exception ex)
                            {
                                PUB.log.AddE($"BatteryWarnSpeak 오류: {ex.Message}");
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    PUB.log.AddE($"DeviceManagementWorker 오류: {ex.Message}");
                }

                // 1초 대기 (또는 취소 요청 시 즉시 종료)
                try
                {
                    Task.Delay(1000, cancellationToken).Wait();
                }
                catch (OperationCanceledException)
                {
                    break;
                }
            }
            PUB.log.Add("DeviceManagementWorker", "종료");
        }

        /// <summary>
        /// 장치 연결 상태 관리
        /// </summary>
        private void ManageDeviceConnections()
        {
            try
            {
                // AGV 연결
                ConnectSerialPort(PUB.AGV, PUB.setting.Port_AGV, PUB.setting.Baud_AGV,
                     eVarTime.LastConn_AGV, eVarTime.LastConnTry_AGV, eVarTime.LastRecv_AGV);

                // XBee 연결
                ConnectSerialPort(PUB.XBE, PUB.setting.Port_XBE, PUB.setting.Baud_XBE,
                     eVarTime.LastConn_XBE, eVarTime.LastConnTry_XBE, eVarTime.LastRecv_XBE);

                // BMS 연결
                if (PUB.BMS.IsOpen == false)
                {
                    var ts = VAR.TIME.RUN(eVarTime.LastConn_BAT);
                    if (ts.TotalSeconds > 3)
                    {
                        PUB.log.Add($"BMS 연결 시도: {PUB.setting.Port_BAT}");
                        PUB.BMS.PortName = PUB.setting.Port_BAT;
                        if (PUB.BMS.Open())
                            PUB.log.AddI($"BMS 연결 완료({PUB.setting.Port_BAT})");

                        VAR.TIME.Update(eVarTime.LastConn_BAT);
                        VAR.TIME.Update(eVarTime.LastConnTry_BAT);
                    }
                }
                else if (PUB.BMS.IsValid == false)
                {
                    var ts = VAR.TIME.RUN(eVarTime.LastConnTry_BAT);
                    if (ts.TotalSeconds > (PUB.setting.interval_bms * 2.5))
                    {
                        PUB.log.Add("BMS 자동 연결 해제 (응답 없음)");
                        PUB.BMS.Close();
                        VAR.TIME.Set(eVarTime.LastConn_BAT, DateTime.Now.AddSeconds(5));
                    }
                }
            }
            catch (Exception ex)
            {
                PUB.log.AddE($"ManageDeviceConnections 오류: {ex.Message}");
            }
        }

        /// <summary>
        /// 시리얼 포트 연결 (arDev.arRS232)
        /// </summary>
        void ConnectSerialPort(arDev.arRS232 dev, string port, int baud, eVarTime conn, eVarTime conntry, eVarTime recvtime)
        {
            if (dev.IsOpen == false && port.isEmpty() == false)
            {
                var tsPLC = VAR.TIME.RUN(conntry);
                if (tsPLC.TotalSeconds > 5)
                {
                    VAR.TIME.Update(conntry);
                    try
                    {
                        VAR.TIME.Update(recvtime);
                        dev.PortName = port;
                        dev.BaudRate = baud;
                        if (dev.Open())
                        {
                            PUB.log.Add(port, $"[AGV:{port}:{baud}] 연결 완료");
                        }
                        else
                        {
                            var errmessage = dev.errorMessage;
                            PUB.log.AddE($"[AGV:{port}:{baud}] {errmessage}");
                        }
                        VAR.TIME.Update(conn);
                        VAR.TIME.Update(conntry);
                    }
                    catch (Exception ex)
                    {
                        PUB.log.AddE(ex.Message);
                    }
                }
            }
            else if (dev.PortName.Equals(port) == false)
            {
                PUB.log.Add(port, $"포트 변경({dev.PortName}->{port})으로 연결 종료");
                dev.Close();
                VAR.TIME.Update(conntry);
            }
        }

        /// <summary>
        /// 시리얼 포트 연결 (Device.Xbee)
        /// </summary>
        void ConnectSerialPort(Device.Xbee dev, string port, int baud, eVarTime conn, eVarTime conntry, eVarTime recvtime)
        {
            if (dev.IsOpen == false && port.isEmpty() == false)
            {
                var tsPLC = VAR.TIME.RUN(conntry);
                if (tsPLC.TotalSeconds > 5)
                {
                    VAR.TIME.Update(conntry);
                    try
                    {
                        VAR.TIME.Update(recvtime);
                        dev.PortName = port;
                        dev.BaudRate = baud;
                        if (dev.Open())
                        {
                            PUB.log.Add(port, $"[XBEE:{port}:{baud}] 연결 완료");
                        }
                        else
                        {
                            var errmessage = dev.errorMessage;
                            PUB.log.AddE($"[XBEE:{port}:{baud}] {errmessage}");
                        }
                        VAR.TIME.Update(conn);
                        VAR.TIME.Update(conntry);
                    }
                    catch (Exception ex)
                    {
                        PUB.log.AddE(ex.Message);
                    }
                }
            }
            else if (dev.PortName.Equals(port) == false)
            {
                PUB.log.Add(port, $"포트 변경({dev.PortName}->{port})으로 연결 종료");
                dev.Close();
                VAR.TIME[(int)conntry] = DateTime.Now;
            }
        }
    }
}
