using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using AGVNavigationCore.Models;
using AGVNavigationCore.PathFinding.Planning;
using Newtonsoft.Json;

namespace AGVNavigationCore.Utils
{
    /// <summary>
    /// DirectionalPathfinder 테스트 클래스
    /// NewMap.json 로드하여 방향별 다음 노드를 검증
    /// </summary>
    public class DirectionalPathfinderTest
    {
        private List<MapNode> _allNodes;
        private Dictionary<ushort, MapNode> _nodesByRfidId;
        private AGVDirectionCalculator _calculator;

        public DirectionalPathfinderTest()
        {
            _nodesByRfidId = new Dictionary<ushort, MapNode>();
            _calculator = new AGVDirectionCalculator();
        }

        /// <summary>
        /// NewMap.json 파일 로드
        /// </summary>
        public bool LoadMapFile(string filePath)
        {
            try
            {
                if (!File.Exists(filePath))
                {
                    Console.WriteLine($"파일을 찾을 수 없습니다: {filePath}");
                    return false;
                }

                string jsonContent = File.ReadAllText(filePath);
                var mapData = JsonConvert.DeserializeObject<MapFileData>(jsonContent);

                if (mapData?.Nodes == null || mapData.Nodes.Count == 0)
                {
                    Console.WriteLine("맵 파일이 비어있습니다.");
                    return false;
                }

                _allNodes = mapData.Nodes;

                // RFID ID로 인덱싱
                foreach (var node in _allNodes)
                {
                    if (node.HasRfid())
                    {
                        _nodesByRfidId[node.RfidId] = node;
                    }
                }

                Console.WriteLine($"✓ 맵 파일 로드 성공: {_allNodes.Count}개 노드 로드");
                return true;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"✗ 맵 파일 로드 실패: {ex.Message}");
                return false;
            }
        }

        /// <summary>
        /// 테스트: RFID 번호로 노드를 찾고, 다음 노드를 계산
        /// </summary>
        public void TestDirectionalMovement(ushort previousRfidId, ushort currentRfidId, AgvDirection direction)
        {
            Console.WriteLine($"\n========================================");
            Console.WriteLine($"테스트: {previousRfidId} → {currentRfidId} (방향: {direction})");
            Console.WriteLine($"========================================");

            // RFID ID로 노드 찾기
            if (!_nodesByRfidId.TryGetValue(previousRfidId, out var previousNode))
            {
                Console.WriteLine($"✗ 이전 RFID를 찾을 수 없습니다: {previousRfidId}");
                return;
            }

            if (!_nodesByRfidId.TryGetValue(currentRfidId, out var currentNode))
            {
                Console.WriteLine($"✗ 현재 RFID를 찾을 수 없습니다: {currentRfidId}");
                return;
            }

            Console.WriteLine($"이전 노드: {previousNode.Id} (RFID: {previousNode.RfidId}) - 위치: {previousNode.Position}");
            Console.WriteLine($"현재 노드: {currentNode.Id} (RFID: {currentNode.RfidId}) - 위치: {currentNode.Position}");
            Console.WriteLine($"이동 벡터: ({currentNode.Position.X - previousNode.Position.X}, " +
                            $"{currentNode.Position.Y - previousNode.Position.Y})");

            // 다음 노드 계산
            string nextNodeId = _calculator.GetNextNodeId(
                previousNode.Position,
                currentNode,
                currentNode.Position,
                direction,
                _allNodes
            );

            if (string.IsNullOrEmpty(nextNodeId))
            {
                Console.WriteLine($"✗ 다음 노드를 찾을 수 없습니다.");
                return;
            }

            // 다음 노드 정보 출력
            var nextNode = _allNodes.FirstOrDefault(n => n.Id == nextNodeId);
            if (nextNode != null)
            {
                Console.WriteLine($"✓ 다음 노드: {nextNode.Id} (RFID: {nextNode.RfidId}) - 위치: {nextNode.Position}");
                Console.WriteLine($"  ├─ 노드 타입: {GetNodeTypeName(nextNode.Type)}");
                Console.WriteLine($"  └─ 연결된 노드: {string.Join(", ", nextNode.ConnectedNodes)}");
            }
            else
            {
                Console.WriteLine($"✗ 다음 노드 정보를 찾을 수 없습니다: {nextNodeId}");
            }
        }

        /// <summary>
        /// 모든 노드 정보 출력
        /// </summary>
        public void PrintAllNodes()
        {
            Console.WriteLine("\n========== 모든 노드 정보 ==========");
            foreach (var node in _allNodes.OrderBy(n => n.RfidId))
            {
                Console.WriteLine($"{node.RfidId:D3} → {node.Id} ({GetNodeTypeName(node.Type)})");
                Console.WriteLine($"   위치: {node.Position}, 연결: {string.Join(", ", node.ConnectedNodes)}");
            }
        }

        /// <summary>
        /// 특정 RFID 노드의 상세 정보 출력
        /// </summary>
        public void PrintNodeInfo(ushort rfidId)
        {
            if (!_nodesByRfidId.TryGetValue(rfidId, out var node))
            {
                Console.WriteLine($"노드를 찾을 수 없습니다: {rfidId}");
                return;
            }

            Console.WriteLine($"\n========== RFID {rfidId} 상세 정보 ==========");
            Console.WriteLine($"노드 ID: {node.Id}");
            Console.WriteLine($"RFID: {node.RfidId}");
            Console.WriteLine($"ALIAS: {node.AliasName}");
            Console.WriteLine($"위치: {node.Position}");
            Console.WriteLine($"타입: {GetNodeTypeName(node.Type)}");
            Console.WriteLine($"TurnLeft/Right/교차로 : {(node.CanTurnLeft ? "O":"X")}/{(node.CanTurnRight ? "O" : "X")}/{(node.DisableCross ? "X" : "O")}");
            Console.WriteLine($"활성: {node.IsActive}");
            Console.WriteLine($"연결된 노드:");

            if (node.ConnectedNodes.Count == 0)
            {
                Console.WriteLine("  (없음)");
            }
            else
            {
                foreach (var connectedId in node.ConnectedNodes)
                {
                    var connectedNode = _allNodes.FirstOrDefault(n => n.Id == connectedId);
                    if (connectedNode != null)
                    {
                        Console.WriteLine($"  → {connectedId} (RFID: {connectedNode.RfidId}) - 위치: {connectedNode.Position}");
                    }
                    else
                    {
                        Console.WriteLine($"  → {connectedId} (노드 찾을 수 없음)");
                    }
                }
            }
        }

        private string GetNodeTypeName(NodeType type)
        {
            return type.ToString();
        }

        // JSON 파일 매핑을 위한 임시 클래스
        [Serializable]
        private class MapFileData
        {
            [JsonProperty("Nodes")]
            public List<MapNode> Nodes { get; set; }

            [JsonProperty("RfidMappings")]
            public List<dynamic> RfidMappings { get; set; }
        }
    }
}
