using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using arCtl;
using Project.StateMachine;
using COMM;
using AR;
using AGVNavigationCore.Models;
using AGVNavigationCore.Controls;

namespace Project
{

    public partial class fMain
    {
        public int GetBufferIndex(MapNode node)
        {
            if (node == null) return 0;
            string name = node.AliasName;
            if (string.IsNullOrEmpty(name)) name = node.Id;

            if (name.Contains("Buffer") || name.ToUpper().StartsWith("B"))
            {
                var match = System.Text.RegularExpressions.Regex.Match(name, @"\d+");
                if (match.Success)
                {
                    int.TryParse(match.Value, out int idx);
                    if (idx >= 1 && idx <= 6) return idx;
                }
            }
            return 0;
        }

        public void SaveBufferStep(MapNode node, int step, ENIGProtocol.AGVCommandHE cmd)
        {
            int bufIdx = GetBufferIndex(node);
            if (bufIdx > 0)
            {
                try
                {
                    var stepVar = (eVarInt32)Enum.Parse(typeof(eVarInt32), $"Buffer{bufIdx}Step");
                    var cmdVar = (eVarString)Enum.Parse(typeof(eVarString), $"Buffer{bufIdx}LastCmd");
                    VAR.I32[stepVar] = step;
                    VAR.STR[cmdVar] = cmd.ToString();
                }
                catch { }
            }
        }

        public void ClearBufferStep(MapNode node)
        {
            int bufIdx = GetBufferIndex(node);
            if (bufIdx > 0)
            {
                try
                {
                    var stepVar = (eVarInt32)Enum.Parse(typeof(eVarInt32), $"Buffer{bufIdx}Step");
                    var cmdVar = (eVarString)Enum.Parse(typeof(eVarString), $"Buffer{bufIdx}LastCmd");
                    VAR.I32[stepVar] = 0;
                    VAR.STR[cmdVar] = "";
                }
                catch { }
            }
        }

        private void AGV_TurnComplete(object sender, arDev.Narumi.TurnEventArgs e)
        {
            //턴작업이완료되었을때 발생된다.
            PUB.log.Add($"AGV Turn Complete:{e.Direction}");

            //일반노드에서 턴작업이 진행되었다면, 이전경로와 현재경로의 모터 방향을 바꿔준다(일반노드에서만 사용)
            if (PUB._virtualAGV.CurrentNode != null && PUB._virtualAGV.CurrentNode.StationType == Station.Normal)
            {
                var prevnodeid = PUB._virtualAGV.PrevNode;//.Id;
                var currnodeid = PUB._virtualAGV.CurrentNode;//.Id;

                //현재 방향과 반대로 모터방향을 셋팅한다. 기존에 Fwd로 왔다면 BWD로 온것으로 처리
                var motdir = PUB._virtualAGV.PrevDirection == AgvDirection.Forward ? AgvDirection.Backward : AgvDirection.Forward;

                PUB.log.Add($"일반노드에서 TURN 완료({e.Direction}) 이전노드:{prevnodeid.ID2},현재노드:{currnodeid.ID2},이전방향:{PUB._virtualAGV.PrevDirection},변경방향:{motdir}");
                
                //이전노드이동한것으로처리
                PUB._mapCanvas.SetAGVPosition(PUB.setting.MCID, prevnodeid, motdir);
                PUB._virtualAGV.SetPosition(prevnodeid, motdir);

                //현재노드이동한것으로처리
                PUB._mapCanvas.SetAGVPosition(PUB.setting.MCID, currnodeid, motdir);
                PUB._virtualAGV.SetPosition(currnodeid, motdir);
            }

        }


        private void AGV_Message(object sender, arDev.Narumi.MessageEventArgs e)
        {
            if (e.MsgType == arDev.NarumiSerialComm.MessageType.Normal)
                PUB.logagv.AddE(e.Message);
            else if (e.MsgType == arDev.NarumiSerialComm.MessageType.Normal)
                PUB.logagv.Add(e.Message);
            else if (e.MsgType == arDev.NarumiSerialComm.MessageType.Recv)
            {
                if (e.Message.Substring(1).StartsWith("STS") == false)
                    PUB.logagv.Add("AGV-RX", e.Message);
            }
            else if (e.MsgType == arDev.NarumiSerialComm.MessageType.Send)
                PUB.logagv.Add("AGV-TX", e.Message);
            else if(e.MsgType == arDev.NarumiSerialComm.MessageType.TagIgnore)
            {
                PUB._mapCanvas.SetTagIgnore(e.Message);
                PUB.logagv.Add(e.MsgType.ToString(), e.Message);
            }
            else
            {
                PUB.logagv.Add(e.MsgType.ToString(), e.Message);
            }
        }


        bool _charging = false;
        private void AGV_DataReceive(object sender, arDev.Narumi.DataEventArgs e)
        {
            try
            {
                VAR.TIME.Set(eVarTime.LastRecv_AGV, DateTime.Now);
                //데이터 파싱
                switch (e.DataType)
                {
                    case arDev.Narumi.DataType.STS:
                        {
                            //마크센서 확인
                            var agv_err = PUB.AGV.error.Value;
                            var agv_emg = PUB.AGV.error.Emergency;
                            var agv_chg = PUB.AGV.system1.Battery_charging;
                            var agv_stp = PUB.AGV.system1.agv_stop;
                            var agv_run = PUB.AGV.system1.agv_run;
                            var agv_mrk = PUB.AGV.signal1.mark_sensor;


                            //if (chg_run && PUB.AGV.system1.agv_run) PUB.Speak("이동을 시작 합니다");
                            VAR.BOOL[eVarBool.AGVDIR_BACK] = PUB.AGV.data.Direction == 'B';
                            var syncDir = PUB.AGV.data.Direction == 'B' ? AgvDirection.Backward : AgvDirection.Forward;

                            // [Sync] Update VirtualAGV Direction
                            if (PUB._virtualAGV != null && PUB._virtualAGV.CurrentDirection != syncDir)
                                PUB.UpdateAGVDirection(syncDir);

                            // [Sync] Update VirtualAGV State
                            AGVState syncState = AGVState.Idle;
                            if (PUB.AGV.error.Value > 0) syncState = AGVState.Error;
                            else if (PUB.AGV.system1.Battery_charging) syncState = AGVState.Charging;
                            else if (PUB.AGV.system1.agv_run) syncState = AGVState.Moving;

                            if (PUB._virtualAGV != null && PUB._virtualAGV.GetCurrentState() != syncState)
                                PUB.UpdateAGVState(syncState);

                            if (VAR.BOOL[eVarBool.AGV_ERROR] != (agv_err > 0))
                            {
                                VAR.BOOL[eVarBool.AGV_ERROR] = (agv_err > 0);
                                PUB.logagv.Add($"[_AGV] new AGV_ERROR ({PUB.AGV.error.Value})");
                            }
                            if (VAR.BOOL[eVarBool.EMERGENCY] != agv_emg)
                            {
                                VAR.BOOL[eVarBool.EMERGENCY] = agv_emg;
                                PUB.logagv.Add($"n[_AGV] ew EMERGENCY ({VAR.BOOL[eVarBool.EMERGENCY]})");
                            }


                            //차징상태변경
                            if (_charging != agv_chg)
                            {
                                if (agv_chg)
                                {
                                    VAR.TIME[eVarTime.ChargeStart] = DateTime.Now;
                                    PUB.logagv.Add($"[_AGV] 충전시작:{VAR.TIME[eVarTime.ChargeStart]}");
                                }
                                _charging = agv_chg;
                            }

                            //배터리충전상태
                            if (VAR.BOOL[eVarBool.FLAG_CHARGEONA] != agv_chg)
                            {
                                PUB.log.Add($"[_AGV] 충전상태전환 {agv_chg}");
                                VAR.BOOL[eVarBool.FLAG_CHARGEONA] = agv_chg;
                            }

                            //충전기위치오류
                            if (PUB.AGV.error.Charger_pos_error != VAR.BOOL[eVarBool.CHG_POSERR])
                            {
                                if (PUB.AGV.error.Charger_pos_error)
                                {
                                    PUB.Speak(Lang.충전기위치오류);
                                }
                                VAR.BOOL[eVarBool.CHG_POSERR] = PUB.AGV.error.Charger_pos_error;
                            }


                            //마크센서 상태가 변경이 되었다면
                            if (VAR.BOOL[eVarBool.MARK_SENSOR] != PUB.AGV.signal1.mark_sensor)
                            {
                                PUB.logagv.Add($"[_AGV] MARK_SENSOR 변경({PUB.AGV.signal1.mark_sensor})");
                                VAR.BOOL[eVarBool.MARK_SENSOR] = PUB.AGV.signal1.mark_sensor;

                                //AGV가 멈췄고 마크센서가 ON되었다면 마지막 RFID 위치가 확정된경우이다
                                if (agv_stp && VAR.BOOL[eVarBool.MARK_SENSOR])
                                {
                                    var curnode = PUB._virtualAGV.SetCurrentNodeMarkStop();
                                    if (curnode == true)
                                    {
                                        PUB.log.Add($"[_AGV] 마크스탑이 확인되어 현재위치({PUB._virtualAGV.CurrentNode.ID2})를 PASS 처리 합니다");
                                    }
                                }
                            }
                            if (VAR.BOOL[eVarBool.MARK_SENSOROFF] == VAR.BOOL[eVarBool.MARK_SENSOR])
                            {
                                VAR.BOOL[eVarBool.MARK_SENSOROFF] = !VAR.BOOL[eVarBool.MARK_SENSOR];
                                VAR.TIME[eVarTime.MarkSensorOff] = DateTime.Now;
                                PUB.log.Add($"[_AGV] MARK_SENSOROFF 변경({VAR.BOOL[eVarBool.MARK_SENSOROFF]})");
                            }

                        }
                        break;
                    case arDev.Narumi.DataType.TAG:
                        {
                            //자동 실행 중이다.
                            PUB.Result.LastTAG = PUB.AGV.data.TagNo;//.ToString("0000");
                            PUB.log.Add($"[_AGV] AGV 태그수신 : {PUB.AGV.data.TagNo} LastTag:{PUB.Result.LastTAG}");

                            //POT/NOT 보면 일단 바로 멈추게한다
                            if (PUB.Result.CurrentPos == ePosition.POT || PUB.Result.CurrentPos == ePosition.NOT)
                            {
                                var logEMsg = $"[_AGV] Stop by [POT/NOT]";
                                PUB.AGV.AGVMoveStop(logEMsg);
                                PUB.log.AddE(logEMsg);
                            }

                            //virtual agv setting
                            var CurrentNode = PUB._mapCanvas.Nodes.FirstOrDefault(t => t.RfidId == PUB.Result.LastTAG);
                            if (CurrentNode == null)
                            {
                                //없는 노드는 자동으로 추가한다
                                var newNodeId = $"[_AGV] AUTO_{PUB.Result.LastTAG}";
                                var newNode = new MapNode
                                {
                                    Id = newNodeId,
                                    RfidId = PUB.Result.LastTAG,
                                    Position = new Point(100, 100), // 기본 위치
                                    IsActive = true,
                                    CreatedDate = DateTime.Now,
                                    ModifiedDate = DateTime.Now
                                };

                                // 맵 노드 리스트에 추가
                                PUB._mapCanvas.Nodes.Add(newNode);

                                // 로그 기록
                                PUB.log.AddI($"[_AGV] RFID:{PUB.Result.LastTAG} 노드를 자동 추가했습니다 (NodeId: {newNodeId})");

                                // CurrentNode에 새로 생성한 노드 할당
                                CurrentNode = newNode;
                            }
                            else
                            {
                                //모터방향 확인해서 UI와 AGV클래스에 적용한다
                                var MotDireciton = PUB.AGV.data.Direction == 'B' ? AgvDirection.Backward : AgvDirection.Forward;
                                PUB._mapCanvas.SetAGVPosition(PUB.setting.MCID, CurrentNode, MotDireciton);
                                PUB._virtualAGV.SetPosition(CurrentNode, MotDireciton);
                                PUB.SaveLastPosition();

                                //노드가 들어왔는데. 일반 노드라면.. 턴 정보를 제거한다.
                                if (CurrentNode.StationType != Station.Buffer && PUB._virtualAGV.Turn != AGVTurn.None)
                                {
                                    PUB.log.AddAT($"현재노드위치가 버퍼가 아니라서 턴정보를 초기화합니다{PUB._virtualAGV.Turn}");
                                    PUB._virtualAGV.Turn = AGVTurn.None;
                                }

                            }

                            //태그를 읽었다면 상태를 바로 전송한다
                            PUB.XBE.SendStatus();
                        }
                        break;
                    case arDev.Narumi.DataType.ACK:
                        PUB.logagv.Add($"[_AGV] AGV_[ACK]Receive : {PUB.AGV.ACKData}");
                        break;
                    default:
                        PUB.logagv.Add($"[_AGV] AGV_DataReceive : {e.DataType}");
                        break;

                }

                //이 후 상황을 예측한다
                if (PUB._mapCanvas != null && PUB._virtualAGV != null)
                {

                    var nextAction = PUB._virtualAGV.Predict();
                    var message = $"[다음 행동 예측]\n\n";

                    if (VAR.BOOL[eVarBool.FLAG_AUTORUN] == false)
                        message += "[X] 수동모드\n";

                    if (PUB._virtualAGV.TargetNode == null) message += "[X] 목표노드없음\n";
                    if (PUB._virtualAGV.CurrentNode == null) message += "[X] 현재노드없음\n";
                    else if (PUB._virtualAGV.HasPath() == false) message += "[X] 경로계산안됨\n";

                    if (PUB._virtualAGV.PrevNode == null) message += "[X] 이전노드없음\n";
                    else message += $"이전노드: {PUB._virtualAGV.PrevNode.ID2} : {PUB._virtualAGV.PrevDirection}\n";
                    if (PUB._virtualAGV.CurrentNode != null)
                        message += $"현재노드: {PUB._virtualAGV.CurrentNode.ID2} : {PUB._virtualAGV.CurrentDirection}\n";

                    message += "-------------\n";

                    var targetpos = PUB._virtualAGV.TargetNode?.ID2 ?? "(X)";



                    var pathdetail = "";
                    if (PUB._virtualAGV.CurrentPath != null && PUB._virtualAGV.CurrentPath.DetailedPath.Any())
                    {
                        var idx = 0;
                        foreach (var item in PUB._virtualAGV.CurrentPath.DetailedPath)
                        {
                            idx += 1;
                            if (pathdetail.isEmpty() == false) pathdetail += "->";
                            if (idx % 6 == 0) pathdetail += "\n";
                            pathdetail += $"{item.RfidId:0000}({item.MotorDirection.ToString().Substring(0, 1)}{item.MagnetDirection.ToString().Substring(0, 1)}{item.Speed.ToString().Substring(0, 1)})";
                            if (item.IsPass) pathdetail += "(O)";
                        }
                    }

                    message += $"모터: {nextAction.Motor}\n" +
                     $"마그넷: {nextAction.Magnet}\n" +
                     $"속도: {nextAction.Speed}\n" +
                     $"이유: {nextAction.Message}\n" +
                     $"상태머신:{PUB.sm.Step}:{PUB.sm.RunStep}:{PUB.sm.RunStepSeq}\n" +
                     $"---\n" +
                     $"현재 상태: {PUB._virtualAGV.CurrentState}\n" +
                     $"현재 방향: {PUB._virtualAGV.CurrentDirection}\n" +
                     $"S/W 턴 상태: {PUB._virtualAGV.Turn}\n" +
                     $"H/W 턴 상태: {PUB.AGV.TurnInformation?.State}\n" +
                     $"위치 확정: {PUB._virtualAGV.IsPositionConfirmed} (RFID {PUB._virtualAGV.DetectedRfidCount}개)\n" +
                     $"대상 노드: {targetpos}\n" +
                     $"상세 경로: {pathdetail}";

                    PUB._mapCanvas.PredictMessage = message;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[_AGV] [AGV_DataReceive] {ex.Message}");
            }
        }
    }
}