using AGVNavigationCore.Models;
using AGVNavigationCore.PathFinding;
using AGVNavigationCore.PathFinding.Core;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Linq;
using System.Runtime.Remoting.Channels;
using System.Windows.Forms;

namespace AGVNavigationCore.Controls
{
    public partial class UnifiedAGVCanvas
    {
        #region Paint Events

        private static int _paintCounter = 0;

        private void UnifiedAGVCanvas_Paint(object sender, PaintEventArgs e)
        {
            // 디버그: Paint 이벤트 실행 확인
            if (_isDragging)
            {
                _paintCounter++;
                //System.Diagnostics.Debug.WriteLine($"Paint #{_paintCounter} 실행! 현재 노드 위치: ({_selectedNode?.Position.X}, {_selectedNode?.Position.Y})");
            }

            var g = e.Graphics;

            // 🔥 배경색 그리기 (변환 행렬 적용 전에 전체 화면을 배경색으로 채움)
            g.Clear(this.BackColor);

            g.SmoothingMode = SmoothingMode.AntiAlias;
            g.InterpolationMode = InterpolationMode.High;

            // 변환 행렬 설정 (줌 및 팬)
            // 순서: Translate 먼저, Scale 나중 (Append로 순서 보장)
            var transform = new Matrix();
            transform.Translate(_panOffset.X, _panOffset.Y);
            transform.Scale(_zoomFactor, _zoomFactor, System.Drawing.Drawing2D.MatrixOrder.Append);
            g.Transform = transform;

            try
            {
                // 그리드 그리기
                if (_showGrid)
                {
                    DrawGrid(g);
                }

                // 노드 연결선 그리기 (가장 먼저 - 텍스트가 가려지지 않게)
                DrawConnections(g);

                // 경로 그리기
                DrawPaths(g);

                // 임시 연결선 그리기 (편집 모드)
                if (_canvasMode == CanvasMode.Edit && _isConnectionMode)
                {
                    DrawTemporaryConnection(g);
                }

                // 노드 그리기
                DrawMarkSensors(g);
                DrawImages(g); // 추가: 이미지 노드
                DrawNodesOnly(g);

                // 드래그 고스트 그리기 (노드 위에 표시되도록 나중에 그리기)
                if (_isDragging && _selectedNode != null)
                {
                    DrawDragGhost(g);
                }

                // 마그넷 방향 텍스트 그리기 (노드 위에 표시)
                DrawMagnetDirections(g);

                // AGV 그리기
                DrawAGVs(g);

                // 노드 라벨 그리기 (가장 나중 - 선이 텍스트를 가리지 않게)
                DrawNodeLabels(g);
                DrawLabels(g); // 추가: 텍스트 라벨


            }
            finally
            {
                g.Transform = new Matrix(); // 변환 행렬 리셋
            }

            // UI 정보 그리기 (변환 없이)
            //if (_showGrid)
            DrawUIInfo(g);

            // 동기화 화면 그리기 (변환 없이, 최상위)
            if (_canvasMode == CanvasMode.Sync)
            {
                DrawSyncScreen(g);
            }

            //예측문자는 디버깅시에만 표시한다.
            if (string.IsNullOrEmpty(PredictMessage) == false)
            {
                g.DrawString(this.PredictMessage, this.Font, Brushes.White, 10, 100);
            }
            DrawSystemMessage(g);
            DrawAlertMessage(g);
            DrawTagIgnoreMessage(g);

        }

        private void DrawMagnetDirections(Graphics g)
        {
            if (_nodes == null) return;

            using (var font = new Font("Arial", 8, FontStyle.Bold))
            using (var brushS = new SolidBrush(Color.Magenta))
            using (var brushL = new SolidBrush(Color.Green))
            using (var brushR = new SolidBrush(Color.Blue))
            using (var brushBg = new SolidBrush(Color.FromArgb(180, 255, 255, 255)))
            {
                foreach (var node in _nodes)
                {
                    if (node.MagnetDirections != null && node.MagnetDirections.Count > 0)
                    {
                        foreach (var kvp in node.MagnetDirections)
                        {
                            var targetId = kvp.Key;
                            var dir = kvp.Value;
                            var targetNode = _nodes.FirstOrDefault(n => n.Id == targetId);

                            if (targetNode != null)
                            {
                                // 방향 텍스트 위치 계산 (출발 -> 도착 벡터의 일정 거리 지점)
                                var start = node.Position;
                                var end = targetNode.Position;
                                var angle = Math.Atan2(end.Y - start.Y, end.X - start.X);

                                // 박스(텍스트) 중심 위치: 약 40px 거리
                                var boxDist = 40;
                                var boxX = start.X + boxDist * Math.Cos(angle);
                                var boxY = start.Y + boxDist * Math.Sin(angle);

                                string text = dir.ToString();

                                Color color = Color.Blue;
                                if (dir == MagnetPosition.L) color = Color.LimeGreen;
                                else if (dir == MagnetPosition.R) color = Color.Red;

                                // 화살표 및 텍스트 설정
                                using (var arrowBrush = new SolidBrush(color))
                                using (var arrowPen = new Pen(color, 2)) // 두께 약간 증가
                                using (var textBrush = new SolidBrush(color))
                                {
                                    // 1. 화살표 그리기 (박스를 가로지르는 선)
                                    // 시작점: 노드 근처 (25px)
                                    // 끝점: 박스 너머 (55px)
                                    var arrowStartDist = 25;
                                    var arrowEndDist = 55;

                                    var pStart = new PointF((float)(start.X + arrowStartDist * Math.Cos(angle)), (float)(start.Y + arrowStartDist * Math.Sin(angle)));
                                    var pEnd = new PointF((float)(start.X + arrowEndDist * Math.Cos(angle)), (float)(start.Y + arrowEndDist * Math.Sin(angle)));

                                    // 화살표 선 그리기
                                    g.DrawLine(arrowPen, pStart, pEnd);

                                    // 화살표 머리 그리기 (끝점에)
                                    var arrowSize = 6;
                                    var pHead1 = new PointF((float)(pEnd.X + arrowSize * Math.Cos(angle)), (float)(pEnd.Y + arrowSize * Math.Sin(angle))); // 뾰족한 끝
                                    // 삼각형 머리 (채우기)
                                    var pBackL = new PointF((float)(pEnd.X + arrowSize * Math.Cos(angle + 2.5)), (float)(pEnd.Y + arrowSize * Math.Sin(angle + 2.5)));
                                    var pBackR = new PointF((float)(pEnd.X + arrowSize * Math.Cos(angle - 2.5)), (float)(pEnd.Y + arrowSize * Math.Sin(angle - 2.5)));

                                    // pHead1이 가장 먼 쪽이 되도록 조정 (pEnd가 삼각형의 뒷부분 중심이 되도록)
                                    // pEnd에서 시작해서 앞으로 나가는 삼각형
                                    // pTip = pEnd + size * angle
                                    // pBackL = pEnd + size/2 * angle_back_L (약간 뒤로)
                                    // 현재 코드는 pEnd를 중심으로, pHead1이 앞, pBackL/R이 뒤... 가 아니라
                                    // pHead1, pBackK, pBackR로 삼각형을 그림.
                                    // pHead1이 팁.
                                    g.FillPolygon(arrowBrush, new PointF[] { pHead1, pBackL, pBackR });

                                    // 2. 텍스트 그리기 (화살표 위에 박스, 그 위에 텍스트)
                                    var textSize = g.MeasureString(text, font);
                                    var textPoint = new PointF((float)(boxX - textSize.Width / 2), (float)(boxY - textSize.Height / 2));

                                    //편집모드에서만 글자를 표시한다.
                                    if (Mode == CanvasMode.Edit)
                                    {
                                        // 텍스트 배경 (반투명 - 선이 은은하게 보이도록 투명도 조절하거나, 가독성을 위해 불투명하게 처리)
                                        // 사용자가 "박스를 가로지르는" 느낌을 원했으므로 선이 보여야 함. 하지만 텍스트 가독성도 필요.
                                        // 배경을 아주 옅게 (Alpha 100정도) 처리하여 선이 보이게 함.
                                        using (var translucentBg = new SolidBrush(Color.FromArgb(120, 255, 255, 255)))
                                        {
                                            g.FillRectangle(translucentBg, textPoint.X - 1, textPoint.Y - 1, textSize.Width + 2, textSize.Height + 2);
                                        }
                                        g.DrawString(text, font, textBrush, textPoint);
                                    }




                                }
                            }
                        }
                    }
                }
            }
        }

        void DrawSystemMessage(Graphics g)
        {
            if (!showalertsystem || String.IsNullOrEmpty(this._systemmesage)) return;

            // 상단 중앙에 반투명 빨간색 배경 바 표시
            int barHeight = 40;
            int barWidth = Math.Min(600, this.Width - 40); // 최대 600px, 좌우 여백 20px
            int barX = (this.Width - barWidth) / 2;
            int barY = 20;

            // 둥근 사각형 배경
            using (var path = new GraphicsPath())
            {
                int radius = 10;
                path.AddArc(barX, barY, radius * 2, radius * 2, 180, 90);
                path.AddArc(barX + barWidth - radius * 2, barY, radius * 2, radius * 2, 270, 90);
                path.AddArc(barX + barWidth - radius * 2, barY + barHeight - radius * 2, radius * 2, radius * 2, 0, 90);
                path.AddArc(barX, barY + barHeight - radius * 2, radius * 2, radius * 2, 90, 90);
                path.CloseFigure();

                using (var brush = new SolidBrush(Color.FromArgb(200, 255, 69, 58))) // 진한 붉은색 (Apple Red 계열)
                {
                    g.FillPath(brush, path);
                }

                using (var pen = new Pen(Color.FromArgb(255, 255, 255), 2))
                {
                    g.DrawPath(pen, path);
                }
            }

            // 텍스트 깜박임 효과 (배경은 유지하고 텍스트만 깜박임)

            using (var font = new Font("Malgun Gothic", 12, FontStyle.Bold))
            using (var brush = new SolidBrush(Color.White))
            {
                var textSize = g.MeasureString(_systemmesage, font);
                g.DrawString(_systemmesage, font, brush,
                    barX + (barWidth - textSize.Width) / 2,
                    barY + (barHeight - textSize.Height) / 2);
            }

            // 경고 아이콘 그리기 (왼쪽)
            // 간단한 느낌표 아이콘
            int iconX = barX + 15;
            int iconY = barY + barHeight / 2;
            using (var brush = new SolidBrush(Color.White))
            {
                g.FillEllipse(brush, iconX - 2, iconY - 8, 4, 16); // body
                g.FillEllipse(brush, iconX - 2, iconY + 10, 4, 4); // dot
            }

        }
        void DrawAlertMessage(Graphics g)
        {
            if (!showinfo || String.IsNullOrEmpty(this._infomessage)) return;

            // 상단 중앙에 반투명 빨간색 배경 바 표시
            int barHeight = 40;
            int barWidth = Math.Min(600, this.Width - 40); // 최대 600px, 좌우 여백 20px
            int barX = (this.Width - barWidth) / 2;
            int barY = 20+50;

            // 둥근 사각형 배경
            using (var path = new GraphicsPath())
            {
                int radius = 10;
                path.AddArc(barX, barY, radius * 2, radius * 2, 180, 90);
                path.AddArc(barX + barWidth - radius * 2, barY, radius * 2, radius * 2, 270, 90);
                path.AddArc(barX + barWidth - radius * 2, barY + barHeight - radius * 2, radius * 2, radius * 2, 0, 90);
                path.AddArc(barX, barY + barHeight - radius * 2, radius * 2, radius * 2, 90, 90);
                path.CloseFigure();

                using (var brush = new SolidBrush(Color.FromArgb(255, Color.Lime)))
                {
                    g.FillPath(brush, path);
                }

                using (var pen = new Pen(Color.FromArgb(255, 255, 255), 2))
                {
                    g.DrawPath(pen, path);
                }
            }

            // 텍스트 깜박임 효과 (배경은 유지하고 텍스트만 깜박임)

            using (var font = new Font("Malgun Gothic", 12, FontStyle.Bold))
            using (var brush = new SolidBrush(Color.Black))
            {
                var textSize = g.MeasureString(_infomessage, font);
                g.DrawString(_infomessage, font, brush,
                    barX + (barWidth - textSize.Width) / 2,
                    barY + (barHeight - textSize.Height) / 2);
            }

            // 경고 아이콘 그리기 (왼쪽)
            // 간단한 느낌표 아이콘
            int iconX = barX + 15;
            int iconY = barY + barHeight / 2;
            using (var brush = new SolidBrush(Color.Black))
            {
                g.FillEllipse(brush, iconX - 2, iconY - 8, 4, 16); // body
                g.FillEllipse(brush, iconX - 2, iconY + 10, 4, 4); // dot
            }

        }
        void DrawTagIgnoreMessage(Graphics g)
        {
            if (!showtagigreno || String.IsNullOrEmpty(this._tagignoreMessage)) return;
            var ts = DateTime.Now - tagignoretime;
            if (ts.TotalSeconds > 5) return;

            // 상단 중앙에 반투명 빨간색 배경 바 표시
            int barHeight = 40;
            int barWidth = Math.Min(600, this.Width - 40); // 최대 600px, 좌우 여백 20px
            int barX = (this.Width - barWidth) / 2;
            int barY = this.Height - barHeight-20;

            // 둥근 사각형 배경
            using (var path = new GraphicsPath())
            {
                int radius = 10;
                path.AddArc(barX, barY, radius * 2, radius * 2, 180, 90);
                path.AddArc(barX + barWidth - radius * 2, barY, radius * 2, radius * 2, 270, 90);
                path.AddArc(barX + barWidth - radius * 2, barY + barHeight - radius * 2, radius * 2, radius * 2, 0, 90);
                path.AddArc(barX, barY + barHeight - radius * 2, radius * 2, radius * 2, 90, 90);
                path.CloseFigure();

                using (var brush = new SolidBrush(Color.FromArgb(255, Color.Violet)))
                {
                    g.FillPath(brush, path);
                }

                using (var pen = new Pen(Color.FromArgb(255, 255, 255), 2))
                {
                    g.DrawPath(pen, path);
                }
            }

            // 텍스트 깜박임 효과 (배경은 유지하고 텍스트만 깜박임)

            using (var font = new Font("Malgun Gothic", 12, FontStyle.Bold))
            using (var brush = new SolidBrush(Color.Black))
            {
                var textSize = g.MeasureString(_tagignoreMessage, font);
                g.DrawString(_tagignoreMessage, font, brush,
                    barX + (barWidth - textSize.Width) / 2,
                    barY + (barHeight - textSize.Height) / 2);
            }

            // 경고 아이콘 그리기 (왼쪽)
            // 간단한 느낌표 아이콘
            int iconX = barX + 15;
            int iconY = barY + barHeight / 2;
            using (var brush = new SolidBrush(Color.Black))
            {
                g.FillEllipse(brush, iconX - 2, iconY - 8, 4, 16); // body
                g.FillEllipse(brush, iconX - 2, iconY + 10, 4, 4); // dot
            }

        }
        private void DrawSyncScreen(Graphics g)
        {
            // 반투명 검은색 배경
            using (var brush = new SolidBrush(Color.FromArgb(200, 0, 0, 0)))
            {
                g.FillRectangle(brush, this.ClientRectangle);
            }

            // 중앙에 메시지 표시
            var center = new Point(Width / 2, Height / 2);

            // 메시지 폰트
            using (var fontTitle = new Font("Malgun Gothic", 24, FontStyle.Bold))
            using (var fontDetail = new Font("Malgun Gothic", 14))
            using (var brushText = new SolidBrush(Color.White))
            {
                // 메인 메시지
                var sizeTitle = g.MeasureString(_syncMessage, fontTitle);
                g.DrawString(_syncMessage, fontTitle, brushText,
                    center.X - sizeTitle.Width / 2,
                    center.Y - sizeTitle.Height / 2 - 60);

                // 진행률 바 배경
                int barWidth = 500;
                int barHeight = 30;
                int barX = center.X - barWidth / 2;
                int barY = center.Y + 10;

                using (var brushBarBg = new SolidBrush(Color.FromArgb(64, 64, 64)))
                {
                    g.FillRectangle(brushBarBg, barX, barY, barWidth, barHeight);
                }
                g.DrawRectangle(Pens.Gray, barX, barY, barWidth, barHeight);

                // 진행률 바 채우기
                if (_syncProgress > 0)
                {
                    using (var brushProgress = new SolidBrush(Color.LimeGreen))
                    {
                        int fillWidth = (int)((barWidth - 4) * _syncProgress);
                        if (fillWidth > 0)
                            g.FillRectangle(brushProgress, barX + 2, barY + 2, fillWidth, barHeight - 4);
                    }
                }

                // 진행률 텍스트
                string progressText = $"{(_syncProgress * 100):F0}%";
                var sizeProgress = g.MeasureString(progressText, fontDetail);
                g.DrawString(progressText, fontDetail, brushText,
                    center.X - sizeProgress.Width / 2,
                    barY + 5);

                // 상세 메시지
                if (!string.IsNullOrEmpty(_syncDetail))
                {
                    var sizeDetail = g.MeasureString(_syncDetail, fontDetail);
                    g.DrawString(_syncDetail, fontDetail, brushText,
                        center.X - sizeDetail.Width / 2,
                        barY + barHeight + 20);
                }
            }
        }

        private void DrawGrid(Graphics g)
        {
            if (!_showGrid) return;

            var gridSize = (int)(GRID_SIZE * _zoomFactor);
            if (gridSize < 5) return; // 너무 작으면 그리지 않음

            // 화면 전체를 덮는 월드 좌표 범위 계산
            var topLeft = ScreenToWorld(new Point(0, 0));
            var bottomRight = ScreenToWorld(new Point(Width, Height));

            // 그리드 시작 위치 (월드 좌표에서 GRID_SIZE의 배수로 정렬)
            int startX = (topLeft.X / GRID_SIZE) * GRID_SIZE - GRID_SIZE;
            int startY = (topLeft.Y / GRID_SIZE) * GRID_SIZE - GRID_SIZE;
            int endX = bottomRight.X + GRID_SIZE;
            int endY = bottomRight.Y + GRID_SIZE;

            // 그리드 펜 (가는 선과 굵은 선)
            using (var thinPen = new Pen(Color.FromArgb(200, 200, 200), 1))
            using (var thickPen = new Pen(Color.FromArgb(150, 150, 150), 1))
            {
                // 수직선 그리기
                for (int x = startX; x <= endX; x += GRID_SIZE)
                {
                    var pen = (x % (GRID_SIZE * 5) == 0) ? thickPen : thinPen;
                    g.DrawLine(pen, x, startY, x, endY);
                }

                // 수평선 그리기
                for (int y = startY; y <= endY; y += GRID_SIZE)
                {
                    var pen = (y % (GRID_SIZE * 5) == 0) ? thickPen : thinPen;
                    g.DrawLine(pen, startX, y, endX, y);
                }
            }
        }

        private void DrawConnections(Graphics g)
        {
            if (_nodes == null) return;

            // 1. 일반 연결 그리기
            foreach (var node in _nodes)
            {
                if (node.ConnectedMapNodes != null)
                {
                    foreach (var targetNode in node.ConnectedMapNodes)
                    {
                        if (targetNode == null) continue;

                        // 강조된 연결은 나중에 그리기 위해 건너뜀
                        if (IsConnectionHighlighted(node.Id, targetNode.Id)) continue;

                        DrawConnection(g, node, targetNode);
                    }
                }
            }

            // 1.1 강조된 연결 그리기 (항상 위에 표시되도록)
            if (_highlightedConnection.HasValue)
            {
                var n1 = _nodes.FirstOrDefault(n => n.Id == _highlightedConnection.Value.FromNodeId);
                var n2 = _nodes.FirstOrDefault(n => n.Id == _highlightedConnection.Value.ToNodeId);
                if (n1 != null && n2 != null)
                {
                    DrawConnection(g, n1, n2);
                }
            }

            // 2. 마그넷 그리기 (별도 리스트 사용)
            if (_magnets != null)
            {
                foreach (var magnet in _magnets)
                {
                    DrawMagnet(g, magnet);
                }
            }
        }

        private void DrawConnection(Graphics g, MapNode fromNode, MapNode toNode)
        {
            var startPoint = fromNode.Position;
            var endPoint = toNode.Position;

            // 강조된 연결인지 확인
            bool isHighlighted = IsConnectionHighlighted(fromNode.Id, toNode.Id);

            // 펜 선택
            Pen pen = isHighlighted ? _highlightedConnectionPen : _connectionPen;

            g.DrawLine(pen, startPoint, endPoint);
        }

        private void DrawMagnet(Graphics g, MapMagnet magnet)
        {
            if (magnet == null) return;

            // 마그넷 좌표
            var startPoint = magnet.StartPoint;
            var endPoint = magnet.EndPoint;

            if (magnet.ControlPoint != null)
            {
                // Quadratic Bezier Curve (2차 베지어 곡선)
                // GDI+ DrawBezier는 Cubic(3차)이므로 2차 -> 3차 변환 필요
                // QP0 = Start, QP1 = Control, QP2 = End
                // CP0 = QP0
                // CP1 = QP0 + (2/3) * (QP1 - QP0)
                // CP2 = QP2 + (2/3) * (QP1 - QP2)
                // CP3 = QP2

                float qp0x = startPoint.X;
                float qp0y = startPoint.Y;
                float qp1x = (float)magnet.ControlPoint.X;
                float qp1y = (float)magnet.ControlPoint.Y;
                float qp2x = endPoint.X;
                float qp2y = endPoint.Y;

                float cp1x = qp0x + (2.0f / 3.0f) * (qp1x - qp0x);
                float cp1y = qp0y + (2.0f / 3.0f) * (qp1y - qp0y);

                float cp2x = qp2x + (2.0f / 3.0f) * (qp1x - qp2x);
                float cp2y = qp2y + (2.0f / 3.0f) * (qp1y - qp2y);

                g.DrawBezier(_magnetPen, qp0x, qp0y, cp1x, cp1y, cp2x, cp2y, qp2x, qp2y);
            }
            else
            {
                // 직선 그리기
                g.DrawLine(_magnetPen, startPoint, endPoint);
            }

            // 호버되거나 선택된 마그넷 강조 (선택: Red, 호버: Orange)
            bool isHovered = (magnet == _hoveredNode);
            bool isSelected = (magnet == _selectedNode);

            if (isHovered || isSelected)
            {
                Color highlightColor = isSelected ? Color.Red : Color.Orange;
                // 선택된 상태에서 호버되면? -> 선택 색상 우선 (Red) 또는 명확한 구분 필요
                // 여기서는 선택이 더 중요하므로 Red 유지

                using (var highlightPen = new Pen(highlightColor, 19) { StartCap = LineCap.Round, EndCap = LineCap.Round })
                {
                    if (magnet.ControlPoint != null)
                    {
                        // Bezier calculation duplicate
                        float qp0x = startPoint.X;
                        float qp0y = startPoint.Y;
                        float qp1x = (float)magnet.ControlPoint.X;
                        float qp1y = (float)magnet.ControlPoint.Y;
                        float qp2x = endPoint.X;
                        float qp2y = endPoint.Y;

                        float cp1x = qp0x + (2.0f / 3.0f) * (qp1x - qp0x);
                        float cp1y = qp0y + (2.0f / 3.0f) * (qp1y - qp0y);

                        float cp2x = qp2x + (2.0f / 3.0f) * (qp1x - qp2x);
                        float cp2y = qp2y + (2.0f / 3.0f) * (qp1y - qp2y);

                        g.DrawBezier(highlightPen, qp0x, qp0y, cp1x, cp1y, cp2x, cp2y, qp2x, qp2y);
                    }
                    else
                    {
                        g.DrawLine(highlightPen, startPoint, endPoint);
                    }
                }
            }

            // 선택된 마그넷 핸들 그리기
            if (magnet == _selectedNode && _canvasMode == CanvasMode.Edit)
            {
                using (var handleBrush = new SolidBrush(Color.White))
                using (var handlePen = new Pen(Color.Black, 1))
                {
                    float size = HANDLE_SIZE / _zoomFactor;
                    float half = size / 2;

                    // 시작점, 끝점 핸들
                    g.FillRectangle(handleBrush, startPoint.X - half, startPoint.Y - half, size, size);
                    g.DrawRectangle(handlePen, startPoint.X - half, startPoint.Y - half, size, size);
                    g.FillRectangle(handleBrush, endPoint.X - half, endPoint.Y - half, size, size);
                    g.DrawRectangle(handlePen, endPoint.X - half, endPoint.Y - half, size, size);

                    // 제어점 핸들 (곡선일 경우)
                    if (magnet.ControlPoint != null)
                    {
                        var cp = magnet.ControlPoint;
                        g.FillRectangle(handleBrush, (float)cp.X - half, (float)cp.Y - half, size, size);
                        g.DrawRectangle(handlePen, (float)cp.X - half, (float)cp.Y - half, size, size);
                    }
                }
            }
        }

        private void DrawMarkSensors(Graphics g)
        {
            if (_marks == null) return; // _marks 리스트 사용

            int sensorSize = 12; // 크기 설정
            foreach (var mark in _marks)
            {
                int lineLength = (int)mark.Length; // 저장된 길이 사용
                int halfLength = lineLength / 2;
                Point p = mark.Position;
                double radians = mark.Rotation * Math.PI / 180.0;

                // 회전 각도에 따른 시점과 종점 계산
                // 마크는 직선 형태로 표시됨
                int dx = (int)(halfLength * Math.Cos(radians));
                int dy = (int)(halfLength * Math.Sin(radians));

                Point p1 = new Point(p.X - dx, p.Y - dy);
                Point p2 = new Point(p.X + dx, p.Y + dy);

                g.DrawLine(_markPen, p1, p2);

                // 호버된 마크 강조
                if (mark == _hoveredNode)
                {
                    using (var highlightPen = new Pen(Color.Orange, 5))
                    {
                        g.DrawLine(highlightPen, p1, p2);
                    }
                }

                // 선택된 마크 핸들 그리기
                if (mark == _selectedNode && _canvasMode == CanvasMode.Edit)
                {
                    using (var handleBrush = new SolidBrush(Color.White))
                    using (var handlePen = new Pen(Color.Black, 1))
                    {
                        float size = HANDLE_SIZE / _zoomFactor;
                        float half = size / 2;

                        g.FillRectangle(handleBrush, p1.X - half, p1.Y - half, size, size);
                        g.DrawRectangle(handlePen, p1.X - half, p1.Y - half, size, size);
                        g.FillRectangle(handleBrush, p2.X - half, p2.Y - half, size, size);
                        g.DrawRectangle(handlePen, p2.X - half, p2.Y - half, size, size);
                    }
                }
            }
        }

        /// <summary>
        /// 연결이 강조 표시되어야 하는지 확인
        /// </summary>
        private bool IsConnectionHighlighted(string nodeId1, string nodeId2)
        {
            if (!_highlightedConnection.HasValue)
                return false;

            var highlighted = _highlightedConnection.Value;

            // 사전순으로 정렬하여 비교 (연결이 단일 방향으로 저장되므로)
            string from, to;
            if (string.Compare(nodeId1, nodeId2, StringComparison.Ordinal) <= 0)
            {
                from = nodeId1;
                to = nodeId2;
            }
            else
            {
                from = nodeId2;
                to = nodeId1;
            }

            return highlighted.FromNodeId == from && highlighted.ToNodeId == to;
        }

        private void DrawDirectionArrow(Graphics g, Point point, double angle, AgvDirection direction)
        {
            // 정삼각형 화살표 - 크기 축소 (8 픽셀)
            var arrowSize = 8;

            // 정삼각형의 3개 점 계산
            // 끝점 (방향 가르키는 점)
            var arrowTipPoint = new Point(
                (int)(point.X + arrowSize * Math.Cos(angle)),
                (int)(point.Y + arrowSize * Math.Sin(angle))
            );

            // 좌측 점 (120도 차이)
            var arrowPoint1 = new Point(
                (int)(point.X + arrowSize * Math.Cos(angle + 2 * Math.PI / 3)),
                (int)(point.Y + arrowSize * Math.Sin(angle + 2 * Math.PI / 3))
            );

            // 우측 점 (240도 차이)
            var arrowPoint2 = new Point(
                (int)(point.X + arrowSize * Math.Cos(angle + 4 * Math.PI / 3)),
                (int)(point.Y + arrowSize * Math.Sin(angle + 4 * Math.PI / 3))
            );

            var arrowColor = direction == AgvDirection.Forward ? Color.Blue : Color.Yellow;
            var arrowBrush = new SolidBrush(arrowColor);

            // 정삼각형으로 화살표 그리기 (내부 채움)
            var trianglePoints = new Point[] { arrowTipPoint, arrowPoint1, arrowPoint2 };
            g.FillPolygon(arrowBrush, trianglePoints);

            // 윤곽선 그리기
            var arrowPen = new Pen(arrowColor, 1f);
            g.DrawPolygon(arrowPen, trianglePoints);

            arrowBrush.Dispose();
            arrowPen.Dispose();
        }

        private void DrawPaths(Graphics g)
        {
            // 모든 경로 그리기
            if (_allPaths != null)
            {
                foreach (var path in _allPaths)
                {
                    DrawPath(g, path, Color.LightBlue);
                }
            }

            // 현재 선택된 경로 그리기 (AGVPathResult 활용)
            if (_currentPath != null)
            {
                DrawPath(g, _currentPath, Color.Purple);

                // 경로 내 교차로 강조 표시
                HighlightJunctionsInPath(g, _currentPath);

                // AGVPathResult의 모터방향 정보가 있다면 향상된 경로 그리기
                // 현재는 기본 PathResult를 사용하므로 향후 AGVPathResult로 업그레이드 시 활성화
                // TODO: AGVPathfinder 사용시 AGVPathResult로 업그레이드
            }
        }

        private void DrawPath(Graphics g, AGVPathResult path, Color color)
        {
            if (path?.Path == null || path.Path.Count < 2) return;

            // 현재 선택된 경로인 경우 보라색 + 투명도 50% + 선 두께 2배
            Color lineColor = color;
            float lineThickness = 4;

            if (color == Color.Purple)
            {
                // 투명도 50% (Alpha = 128 / 255)
                lineColor = Color.FromArgb(128, color.R, color.G, color.B);
                lineThickness = 8; // 2배 증가
            }

            var pathPen = new Pen(lineColor, lineThickness) { DashStyle = DashStyle.Dash };

            // 왕복 경로 감지: 방문한 노드 추적
            var visitedSegments = new Dictionary<string, int>();

            for (int i = 0; i < path.Path.Count - 1; i++)
            {
                var currentNode = path.Path[i];
                var nextNode = path.Path[i + 1];

                if (currentNode == null || nextNode == null) continue;

                var currentNodeId = currentNode.Id;
                var nextNodeId = nextNode.Id;

                // 왕복 구간 키 생성 (양방향 모두 같은 키)
                var segmentKey = string.Compare(currentNodeId, nextNodeId) < 0
                    ? $"{currentNodeId}_{nextNodeId}"
                    : $"{nextNodeId}_{currentNodeId}";

                if (!visitedSegments.ContainsKey(segmentKey))
                    visitedSegments[segmentKey] = 0;
                visitedSegments[segmentKey]++;

                if (currentNode != null && nextNode != null)
                {
                    // 왕복 경로면 더 진한 색상으로 표시
                    if (visitedSegments[segmentKey] > 1 && color == Color.Purple)
                    {
                        // 왕복 경로는 투명도를 낮춤 (더 진하게)
                        var darkPathColor = Color.FromArgb(200, color.R, color.G, color.B);
                        var darkPathPen = new Pen(darkPathColor, lineThickness) { DashStyle = DashStyle.Dash };
                        g.DrawLine(darkPathPen, currentNode.Position, nextNode.Position);
                        darkPathPen.Dispose();
                    }
                    else
                    {
                        // 일반 경로 선 그리기
                        g.DrawLine(pathPen, currentNode.Position, nextNode.Position);
                    }

                    // 경로 방향 표시 (계산된 경로의 경우에만 방향 화살표 표시)
                    var midPoint = new Point(
                        (currentNode.Position.X + nextNode.Position.X) / 2,
                        (currentNode.Position.Y + nextNode.Position.Y) / 2
                    );

                    var angle = Math.Atan2(nextNode.Position.Y - currentNode.Position.Y,
                                         nextNode.Position.X - currentNode.Position.X);

                    // 상세 경로 정보가 있으면 해당 방향 사용, 없으면 Forward
                    AgvDirection arrowDir = AgvDirection.Forward;
                    if (path.DetailedPath != null && i < path.DetailedPath.Count)
                    {
                        arrowDir = path.DetailedPath[i].MotorDirection;
                    }

                    DrawDirectionArrow(g, midPoint, angle, arrowDir);
                }
            }

            pathPen.Dispose();
        }

        /// <summary>
        /// 경로에 포함된 교차로(3개 이상의 노드가 연결된 노드)를 파란색으로 강조 표시
        /// </summary>
        /// <summary>
        /// 경로에 포함된 특정 노드(Gateway 등)를 강조 표시
        /// HighlightNodeId가 설정된 경우 해당 노드만 표시하고, 없으면 기존대로 교차로 표시(또는 표시 안함)
        /// 사용자가 "교차로 대신 게이트웨이만 강조"를 원하므로 우선순위 적용
        /// </summary>
        private void HighlightJunctionsInPath(Graphics g, AGVPathResult path)
        {
            if (path?.Path == null || _nodes == null || _nodes.Count == 0)
                return;

            // 1. HighlightNodeId가 설정되어 있다면 해당 노드만 강조
            if (!string.IsNullOrEmpty(HighlightNodeId))
            {
                var targetNode = path.Path.FirstOrDefault(n => n.Id == HighlightNodeId);
                if (targetNode != null)
                {
                    DrawJunctionHighlight(g, targetNode, true); // true = Gateway 강조 색상 사용
                }
                // HighlightNodeId가 설정된 경우 다른 교차로는 표시하지 않음 (사용자 요청)
                return;
            }

            // 2. 설정이 없다면 기존 로직 (교차로 표시) 유지 여부 결정
            // 사용자가 "게이트웨이만 강조해줘"라고 했으므로, 혼란을 피하기 위해
            // HighlightNodeId가 없을 때는 아무것도 표시하지 않거나, 필요한 경우 복구.
            // 현재는 사용자 요청에 따라 Gateway 지정이 안된 경우(일반 경로)에는 교차로 강조를 끄는 것이 맞아 보임.
            // 하지만 일반 주행시에도 교차로 정보가 필요할 수 있으니 일단 둡니다.
            // 단, Gateway 로직을 타는 경우(HighlightNodeId가 Set됨)에는 위에서 return 되므로 OK.

            /*
            const int JUNCTION_CONNECTIONS = 3; 

            foreach (var node in path.Path)
            {
                if (node == null) continue;

                if (node.ConnectedMapNodes != null && node.ConnectedMapNodes.Count >= JUNCTION_CONNECTIONS)
                {
                    DrawJunctionHighlight(g, node, false);
                }
            }
            */
        }

        /// <summary>
        /// 노드 강조 표시
        /// </summary>
        private void DrawJunctionHighlight(Graphics g, MapNode junctionNode, bool isGateway)
        {
            if (junctionNode == null) return;

            int radius = isGateway ? 23 : 18; // 게이트웨이는 좀 더 크게

            // 색상 결정: Gateway=진한 주황/골드, 일반 교차로=기존 파랑
            Color fillColor = isGateway ? Color.FromArgb(100, 255, 140, 0) : Color.FromArgb(80, 70, 130, 200);
            Color penColor = isGateway ? Color.OrangeRed : Color.FromArgb(150, 100, 150, 220);

            using (var highlightBrush = new SolidBrush(fillColor))
            using (var highlightPen = new Pen(penColor, 3))
            {
                g.FillEllipse(
                    highlightBrush,
                    junctionNode.Position.X - radius,
                    junctionNode.Position.Y - radius,
                    radius * 2,
                    radius * 2
                );

                // 테두리 점선 효과 (Gateway 인 경우)
                if (isGateway) highlightPen.DashStyle = DashStyle.Dot;

                g.DrawEllipse(
                    highlightPen,
                    junctionNode.Position.X - radius,
                    junctionNode.Position.Y - radius,
                    radius * 2,
                    radius * 2
                );
            }
        }

        /// <summary>
        /// 교차로 라벨을 표시 (선택사항)
        /// </summary>
        private void DrawJunctionLabel(Graphics g, MapNode junctionNode)
        {
            if (junctionNode == null) return;

            using (var font = new Font("Arial", 9, FontStyle.Bold))
            using (var brush = new SolidBrush(Color.Blue))
            {
                var text = "교차로";
                var textSize = g.MeasureString(text, font);

                // 노드 위쪽에 라벨 표시
                var labelX = junctionNode.Position.X - textSize.Width / 2;
                var labelY = junctionNode.Position.Y - 35;

                // 배경 박스 그리기
                using (var bgBrush = new SolidBrush(Color.FromArgb(220, 255, 255, 200)))
                {
                    g.FillRectangle(
                        bgBrush,
                        labelX - 3,
                        labelY - 3,
                        textSize.Width + 6,
                        textSize.Height + 6
                    );
                }

                g.DrawString(text, font, brush, labelX, labelY);
            }
        }

        /// <summary>
        /// 드래그 고스트 그리기 - 원래 위치에 반투명 노드 표시
        /// </summary>
        private void DrawDragGhost(Graphics g)
        {
            if (!_isDragging) return;

            if (_selectedNode != null)
            {
                // 반투명 효과를 위한 브러시 생성
                Brush ghostBrush = new SolidBrush(Color.FromArgb(120, 200, 200, 200)); // 반투명 회색

                // 고스트 노드 그리기
                switch (_selectedNode.Type)
                {
                    case NodeType.Normal:
                        var item = _selectedNode as MapNode;
                        if (item.StationType == Station.Charger)
                            DrawTriangleGhost(g, ghostBrush);
                        else
                            DrawPentagonGhost(g, ghostBrush);
                        break;
                    case NodeType.Label:
                        DrawLabelGhost(g, SelectedLabel);
                        break;
                    case NodeType.Image:
                        DrawImageGhost(g, SelectedImage);
                        break;
                    default: //mark, magnet
                        DrawCircleGhost(g, ghostBrush);
                        break;
                }

                ghostBrush?.Dispose();
            }

        }

        private void DrawCircleGhost(Graphics g, Brush ghostBrush)
        {
            var rect = new Rectangle(
                _dragStartPosition.X - NODE_RADIUS,
                _dragStartPosition.Y - NODE_RADIUS,
                NODE_SIZE,
                NODE_SIZE
            );
            g.FillEllipse(ghostBrush, rect);
            // 회색 점선 테두리
            g.DrawEllipse(new Pen(Color.FromArgb(180, 128, 128, 128), 2) { DashStyle = DashStyle.Dash }, rect);
            // 빨간색 외곽 테두리 (디버깅용 - 고스트가 확실히 보이도록)
            var outerRect = new Rectangle(rect.X - 2, rect.Y - 2, rect.Width + 4, rect.Height + 4);
            g.DrawEllipse(new Pen(Color.FromArgb(200, 255, 0, 0), 1), outerRect);
        }

        private void DrawPentagonGhost(Graphics g, Brush ghostBrush)
        {
            var points = new Point[5];
            for (int i = 0; i < 5; i++)
            {
                var angle = (Math.PI * 2 * i / 5) - Math.PI / 2;
                points[i] = new Point(
                    (int)(_dragStartPosition.X + NODE_RADIUS * Math.Cos(angle)),
                    (int)(_dragStartPosition.Y + NODE_RADIUS * Math.Sin(angle))
                );
            }
            g.FillPolygon(ghostBrush, points);
            // 회색 점선 테두리
            g.DrawPolygon(new Pen(Color.FromArgb(180, 128, 128, 128), 2) { DashStyle = DashStyle.Dash }, points);
            // 빨간색 외곽 테두리 (디버깅용)
            var outerPoints = new Point[5];
            for (int i = 0; i < 5; i++)
            {
                var angle = (Math.PI * 2 * i / 5) - Math.PI / 2;
                outerPoints[i] = new Point(
                    (int)(_dragStartPosition.X + (NODE_RADIUS + 3) * Math.Cos(angle)),
                    (int)(_dragStartPosition.Y + (NODE_RADIUS + 3) * Math.Sin(angle))
                );
            }
            g.DrawPolygon(new Pen(Color.FromArgb(200, 255, 0, 0), 1), outerPoints);
        }

        private void DrawTriangleGhost(Graphics g, Brush ghostBrush)
        {
            var points = new Point[3];
            for (int i = 0; i < 3; i++)
            {
                var angle = (Math.PI * 2 * i / 3) - Math.PI / 2;
                points[i] = new Point(
                    (int)(_dragStartPosition.X + NODE_RADIUS * Math.Cos(angle)),
                    (int)(_dragStartPosition.Y + NODE_RADIUS * Math.Sin(angle))
                );
            }
            g.FillPolygon(ghostBrush, points);
            // 회색 점선 테두리
            g.DrawPolygon(new Pen(Color.FromArgb(180, 128, 128, 128), 2) { DashStyle = DashStyle.Dash }, points);
            // 빨간색 외곽 테두리 (디버깅용)
            var outerPoints = new Point[3];
            for (int i = 0; i < 3; i++)
            {
                var angle = (Math.PI * 2 * i / 3) - Math.PI / 2;
                outerPoints[i] = new Point(
                    (int)(_dragStartPosition.X + (NODE_RADIUS + 3) * Math.Cos(angle)),
                    (int)(_dragStartPosition.Y + (NODE_RADIUS + 3) * Math.Sin(angle))
                );
            }
            g.DrawPolygon(new Pen(Color.FromArgb(200, 255, 0, 0), 1), outerPoints);
        }

        private void DrawLabelGhost(Graphics g, MapLabel label)
        {
            var text = string.IsNullOrEmpty(label.Text) ? label.Id : label.Text;
            using (var font = new Font(label.FontFamily, label.FontSize, label.FontStyle))
            using (var textBrush = new SolidBrush(Color.FromArgb(120, label.ForeColor)))
            {
                var textSize = g.MeasureString(text, font);
                var textPoint = new Point(
                    (int)(_dragStartPosition.X - textSize.Width / 2),
                    (int)(_dragStartPosition.Y - textSize.Height / 2)
                );

                if (label.BackColor != Color.Transparent)
                {
                    using (var backgroundBrush = new SolidBrush(Color.FromArgb(120, label.BackColor)))
                    {
                        var backgroundRect = new Rectangle(
                            textPoint.X - label.Padding,
                            textPoint.Y - label.Padding,
                            (int)textSize.Width + (label.Padding * 2),
                            (int)textSize.Height + (label.Padding * 2)
                        );
                        g.FillRectangle(backgroundBrush, backgroundRect);
                        g.DrawRectangle(new Pen(Color.FromArgb(180, 128, 128, 128), 2) { DashStyle = DashStyle.Dash }, backgroundRect);
                    }
                }

                g.DrawString(text, font, textBrush, textPoint);

                // 배경이 없어도 테두리 표시
                if (label.BackColor != Color.Transparent)
                {
                    var borderRect = new Rectangle(
                        textPoint.X - 2,
                        textPoint.Y - 2,
                        (int)textSize.Width + 4,
                        (int)textSize.Height + 4
                    );
                    g.DrawRectangle(new Pen(Color.FromArgb(180, 128, 128, 128), 2) { DashStyle = DashStyle.Dash }, borderRect);
                }

                // 빨간색 외곽 테두리 (디버깅용)
                var outerRect = new Rectangle(
                    textPoint.X - 4,
                    textPoint.Y - 4,
                    (int)textSize.Width + 8,
                    (int)textSize.Height + 8
                );
                g.DrawRectangle(new Pen(Color.FromArgb(200, 255, 0, 0), 1), outerRect);
            }
        }

        private void DrawImageGhost(Graphics g, MapImage image)
        {
            var displaySize = image.GetDisplaySize();
            if (displaySize.IsEmpty)
                displaySize = new Size(50, 50);

            var imageRect = new Rectangle(
                _dragStartPosition.X - displaySize.Width / 2,
                _dragStartPosition.Y - displaySize.Height / 2,
                displaySize.Width,
                displaySize.Height
            );

            // 반투명 회색 사각형
            using (var ghostBrush = new SolidBrush(Color.FromArgb(120, 200, 200, 200)))
            {
                g.FillRectangle(ghostBrush, imageRect);
                g.DrawRectangle(new Pen(Color.FromArgb(180, 128, 128, 128), 2) { DashStyle = DashStyle.Dash }, imageRect);
            }

            // 빨간색 외곽 테두리 (디버깅용)
            var outerRect = new Rectangle(imageRect.X - 2, imageRect.Y - 2, imageRect.Width + 4, imageRect.Height + 4);
            g.DrawRectangle(new Pen(Color.FromArgb(200, 255, 0, 0), 1), outerRect);
        }

        private void DrawNodeLabels(Graphics g)
        {
            if (_nodes == null) return;

            foreach (var node in _nodes)
            {
                // 일반 노드 라벨 그리기
                DrawNodeLabel(g, node);
            }
        }

        private void DrawNodesOnly(Graphics g)
        {
            if (_nodes == null) return;

            foreach (var node in _nodes)
            {
                var brush = GetNodeBrush(node);

                switch (node.StationType)
                {
                    case Station.Loder:
                    case Station.Cleaner:
                    case Station.Plating:
                    case Station.Buffer:
                        DrawPentagonNodeShape(g, node, brush);
                        break;
                    case Station.Charger:
                        DrawTriangleNodeShape(g, node, brush);
                        break;
                    case Station.Lmt:
                        DrawRectangleNodeShape(g, node, brush);
                        break;
                    default:
                        DrawCircleNodeShape(g, node, brush);
                        break;
                }
            }
        }


        private void DrawRectangleNodeShape(Graphics g, MapNode node, Brush brush)
        {
            // 드래그 중인 노드는 약간 크게 그리기
            bool isDraggingThisNode = _isDragging && node == _selectedNode;
            int sizeAdjustment = isDraggingThisNode ? 4 : 0;

            var rect = new Rectangle(
                node.Position.X - NODE_RADIUS - sizeAdjustment,
                node.Position.Y - NODE_RADIUS - sizeAdjustment,
                NODE_SIZE + sizeAdjustment * 2,
                NODE_SIZE + sizeAdjustment * 2
            );

            // 드래그 중인 노드의 그림자 효과
            if (isDraggingThisNode)
            {
                var shadowRect = new Rectangle(rect.X + 3, rect.Y + 3, rect.Width, rect.Height);
                using (var shadowBrush = new SolidBrush(Color.FromArgb(100, 0, 0, 0)))
                {
                    g.FillRectangle(shadowBrush, shadowRect);
                }
            }

            // 노드 그리기
            g.FillRectangle(brush, rect);
            g.DrawRectangle(Pens.Black, rect);

            // 드래그 중인 노드 강조 (가장 강력한 효과)
            if (isDraggingThisNode)
            {
                // 청록색 두꺼운 테두리
                g.DrawRectangle(new Pen(Color.Cyan, 3), rect);
                // 펄스 효과
                var pulseRect = new Rectangle(rect.X - 4, rect.Y - 4, rect.Width + 8, rect.Height + 8);
                g.DrawRectangle(new Pen(Color.FromArgb(150, 0, 255, 255), 2) { DashStyle = DashStyle.Dash }, pulseRect);
            }
            // 선택된 노드 강조 (단일 또는 다중)
            else if (node == _selectedNode || (_selectedNodes != null && _selectedNodes.Contains(node)))
            {
                g.DrawRectangle(_selectedNodePen, rect);
            }

            // 목적지 노드 강조
            if (node == _destinationNode)
            {
                // 금색 테두리로 목적지 강조
                g.DrawRectangle(_destinationNodePen, rect);

                // 펄싱 효과를 위한 추가 원 그리기
                var pulseRect = new Rectangle(rect.X - 3, rect.Y - 3, rect.Width + 6, rect.Height + 6);
                g.DrawRectangle(new Pen(Color.Gold, 2) { DashStyle = DashStyle.Dash }, pulseRect);
            }

            // 호버된 노드 강조 (드래그 중이 아닐 때만)
            if (node == _hoveredNode && !isDraggingThisNode)
            {
                var hoverRect = new Rectangle(rect.X - 2, rect.Y - 2, rect.Width + 4, rect.Height + 4);
                g.DrawRectangle(new Pen(Color.Orange, 2), hoverRect);
            }

            // RFID 중복 노드 표시 (빨간 X자)
            if (_duplicateRfidNodes.Contains(node.Id))
            {
                DrawDuplicateRfidMarker(g, node);
            }

            // CanCross 가능 노드 표시 (교차지점으로 사용 가능)
            if (node.DisableCross == true)
            {
                var crossRect = new Rectangle(rect.X - 3, rect.Y - 3, rect.Width + 6, rect.Height + 6);
                g.DrawRectangle(new Pen(Color.DeepSkyBlue, 3), crossRect);
            }

            g.DrawLine(Pens.Black, rect.X, rect.Y, rect.Right, rect.Bottom);
            g.DrawLine(Pens.Black, rect.Right, rect.Top, rect.X, rect.Bottom);

        }
        private void DrawCircleNodeShape(Graphics g, MapNode node, Brush brush)
        {
            // 드래그 중인 노드는 약간 크게 그리기
            bool isDraggingThisNode = _isDragging && node == _selectedNode;
            int sizeAdjustment = isDraggingThisNode ? 4 : 0;

            var rect = new Rectangle(
                node.Position.X - NODE_RADIUS - sizeAdjustment,
                node.Position.Y - NODE_RADIUS - sizeAdjustment,
                NODE_SIZE + sizeAdjustment * 2,
                NODE_SIZE + sizeAdjustment * 2
            );

            // 드래그 중인 노드의 그림자 효과
            if (isDraggingThisNode)
            {
                var shadowRect = new Rectangle(rect.X + 3, rect.Y + 3, rect.Width, rect.Height);
                using (var shadowBrush = new SolidBrush(Color.FromArgb(100, 0, 0, 0)))
                {
                    g.FillEllipse(shadowBrush, shadowRect);
                }
            }

            // 노드 그리기
            g.FillEllipse(brush, rect);
            g.DrawEllipse(Pens.Black, rect);

            // 드래그 중인 노드 강조 (가장 강력한 효과)
            if (isDraggingThisNode)
            {
                // 청록색 두꺼운 테두리
                g.DrawEllipse(new Pen(Color.Cyan, 3), rect);
                // 펄스 효과
                var pulseRect = new Rectangle(rect.X - 4, rect.Y - 4, rect.Width + 8, rect.Height + 8);
                g.DrawEllipse(new Pen(Color.FromArgb(150, 0, 255, 255), 2) { DashStyle = DashStyle.Dash }, pulseRect);
            }
            // 선택된 노드 강조 (단일 또는 다중)
            else if (node == _selectedNode || (_selectedNodes != null && _selectedNodes.Contains(node)))
            {
                g.DrawEllipse(_selectedNodePen, rect);
            }

            // 목적지 노드 강조
            if (node == _destinationNode)
            {
                // 금색 테두리로 목적지 강조
                g.DrawEllipse(_destinationNodePen, rect);

                // 펄싱 효과를 위한 추가 원 그리기
                var pulseRect = new Rectangle(rect.X - 3, rect.Y - 3, rect.Width + 6, rect.Height + 6);
                g.DrawEllipse(new Pen(Color.Gold, 2) { DashStyle = DashStyle.Dash }, pulseRect);
            }

            // 호버된 노드 강조 (드래그 중이 아닐 때만)
            if (node == _hoveredNode && !isDraggingThisNode)
            {
                var hoverRect = new Rectangle(rect.X - 2, rect.Y - 2, rect.Width + 4, rect.Height + 4);
                g.DrawEllipse(new Pen(Color.Orange, 2), hoverRect);
            }

            // RFID 중복 노드 표시 (빨간 X자)
            if (_duplicateRfidNodes.Contains(node.Id))
            {
                DrawDuplicateRfidMarker(g, node);
            }

            // CanCross 가능 노드 표시 (교차지점으로 사용 가능)
            if (node.DisableCross == true)
            {
                var crossRect = new Rectangle(rect.X - 3, rect.Y - 3, rect.Width + 6, rect.Height + 6);
                g.DrawEllipse(new Pen(Color.DeepSkyBlue, 3), crossRect);
            }
        }

        private void DrawPentagonNodeShape(Graphics g, MapNode node, Brush brush)
        {
            // 드래그 중인 노드는 약간 크게 그리기
            bool isDraggingThisNode = _isDragging && node == _selectedNode;
            int radiusAdjustment = isDraggingThisNode ? 4 : 0;

            var radius = NODE_RADIUS + radiusAdjustment;
            var center = node.Position;

            // 5각형 꼭짓점 계산 (위쪽부터 시계방향)
            var points = new Point[5];
            for (int i = 0; i < 5; i++)
            {
                var angle = (Math.PI * 2 * i / 5) - Math.PI / 2; // -90도부터 시작 (위쪽)
                points[i] = new Point(
                    (int)(center.X + radius * Math.Cos(angle)),
                    (int)(center.Y + radius * Math.Sin(angle))
                );
            }

            // 드래그 중인 노드의 그림자 효과
            if (isDraggingThisNode)
            {
                var shadowPoints = new Point[5];
                for (int i = 0; i < 5; i++)
                {
                    shadowPoints[i] = new Point(points[i].X + 3, points[i].Y + 3);
                }
                using (var shadowBrush = new SolidBrush(Color.FromArgb(100, 0, 0, 0)))
                {
                    g.FillPolygon(shadowBrush, shadowPoints);
                }
            }

            // 5각형 그리기
            g.FillPolygon(brush, points);
            g.DrawPolygon(Pens.Black, points);

            // 드래그 중인 노드 강조 (가장 강력한 효과)
            if (isDraggingThisNode)
            {
                // 청록색 두꺼운 테두리
                g.DrawPolygon(new Pen(Color.Cyan, 3), points);
                // 펄스 효과
                var pulsePoints = new Point[5];
                for (int i = 0; i < 5; i++)
                {
                    var angle = (Math.PI * 2 * i / 5) - Math.PI / 2;
                    pulsePoints[i] = new Point(
                        (int)(center.X + (radius + 5) * Math.Cos(angle)),
                        (int)(center.Y + (radius + 5) * Math.Sin(angle))
                    );
                }
                g.DrawPolygon(new Pen(Color.FromArgb(150, 0, 255, 255), 2) { DashStyle = DashStyle.Dash }, pulsePoints);
            }
            // 선택된 노드 강조
            else if (node == _selectedNode)
            {
                g.DrawPolygon(_selectedNodePen, points);
            }

            // 목적지 노드 강조
            if (node == _destinationNode)
            {
                // 금색 테두리로 목적지 강조
                g.DrawPolygon(_destinationNodePen, points);

                // 펄싱 효과를 위한 추가 오각형 그리기
                var pulsePoints = new Point[5];
                for (int i = 0; i < 5; i++)
                {
                    var angle = (Math.PI * 2 * i / 5) - Math.PI / 2;
                    pulsePoints[i] = new Point(
                        (int)(center.X + (radius + 4) * Math.Cos(angle)),
                        (int)(center.Y + (radius + 4) * Math.Sin(angle))
                    );
                }
                g.DrawPolygon(new Pen(Color.Gold, 2) { DashStyle = DashStyle.Dash }, pulsePoints);
            }

            // 호버된 노드 강조 (드래그 중이 아닐 때만)
            if (node == _hoveredNode && !isDraggingThisNode)
            {
                // 확장된 5각형 계산
                var hoverPoints = new Point[5];
                for (int i = 0; i < 5; i++)
                {
                    var angle = (Math.PI * 2 * i / 5) - Math.PI / 2;
                    hoverPoints[i] = new Point(
                        (int)(center.X + (radius + 3) * Math.Cos(angle)),
                        (int)(center.Y + (radius + 3) * Math.Sin(angle))
                    );
                }
                g.DrawPolygon(new Pen(Color.Orange, 2), hoverPoints);
            }

            // RFID 중복 노드 표시 (빨간 X자)
            if (_duplicateRfidNodes.Contains(node.Id))
            {
                DrawDuplicateRfidMarker(g, node);
            }

            // CanCross 가능 노드 표시 (교차지점으로 사용 가능)
            if (node.DisableCross == false)
            {
                var crossPoints = new Point[5];
                for (int i = 0; i < 5; i++)
                {
                    var angle = (Math.PI * 2 * i / 5) - Math.PI / 2;
                    crossPoints[i] = new Point(
                        (int)(center.X + (radius + 4) * Math.Cos(angle)),
                        (int)(center.Y + (radius + 4) * Math.Sin(angle))
                    );
                }
                g.DrawPolygon(new Pen(Color.Gold, 3), crossPoints);
            }
        }

        private void DrawTriangleNodeShape(Graphics g, MapNode node, Brush brush)
        {
            // 드래그 중인 노드는 약간 크게 그리기
            bool isDraggingThisNode = _isDragging && node == _selectedNode;
            int radiusAdjustment = isDraggingThisNode ? 4 : 0;

            var radius = NODE_RADIUS + radiusAdjustment;
            var center = node.Position;

            // 삼각형 꼭짓점 계산 (위쪽 꼭짓점부터 시계방향)
            var points = new Point[3];
            for (int i = 0; i < 3; i++)
            {
                var angle = (Math.PI * 2 * i / 3) - Math.PI / 2; // -90도부터 시작 (위쪽)
                points[i] = new Point(
                    (int)(center.X + radius * Math.Cos(angle)),
                    (int)(center.Y + radius * Math.Sin(angle))
                );
            }

            // 드래그 중인 노드의 그림자 효과
            if (isDraggingThisNode)
            {
                var shadowPoints = new Point[3];
                for (int i = 0; i < 3; i++)
                {
                    shadowPoints[i] = new Point(points[i].X + 3, points[i].Y + 3);
                }
                using (var shadowBrush = new SolidBrush(Color.FromArgb(100, 0, 0, 0)))
                {
                    g.FillPolygon(shadowBrush, shadowPoints);
                }
            }

            // 삼각형 그리기
            g.FillPolygon(brush, points);
            g.DrawPolygon(Pens.Black, points);

            // 드래그 중인 노드 강조 (가장 강력한 효과)
            if (isDraggingThisNode)
            {
                // 청록색 두꺼운 테두리
                g.DrawPolygon(new Pen(Color.Cyan, 3), points);
                // 펄스 효과
                var pulsePoints = new Point[3];
                for (int i = 0; i < 3; i++)
                {
                    var angle = (Math.PI * 2 * i / 3) - Math.PI / 2;
                    pulsePoints[i] = new Point(
                        (int)(center.X + (radius + 5) * Math.Cos(angle)),
                        (int)(center.Y + (radius + 5) * Math.Sin(angle))
                    );
                }
                g.DrawPolygon(new Pen(Color.FromArgb(150, 0, 255, 255), 2) { DashStyle = DashStyle.Dash }, pulsePoints);
            }
            // 선택된 노드 강조
            else if (node == _selectedNode)
            {
                g.DrawPolygon(_selectedNodePen, points);
            }

            // 목적지 노드 강조
            if (node == _destinationNode)
            {
                // 금색 테두리로 목적지 강조
                g.DrawPolygon(_destinationNodePen, points);

                // 펄싱 효과를 위한 추가 삼각형 그리기
                var pulsePoints = new Point[3];
                for (int i = 0; i < 3; i++)
                {
                    var angle = (Math.PI * 2 * i / 3) - Math.PI / 2;
                    pulsePoints[i] = new Point(
                        (int)(center.X + (radius + 4) * Math.Cos(angle)),
                        (int)(center.Y + (radius + 4) * Math.Sin(angle))
                    );
                }
                g.DrawPolygon(new Pen(Color.Gold, 2) { DashStyle = DashStyle.Dash }, pulsePoints);
            }

            // 호버된 노드 강조 (드래그 중이 아닐 때만)
            if (node == _hoveredNode && !isDraggingThisNode)
            {
                // 확장된 삼각형 계산
                var hoverPoints = new Point[3];
                for (int i = 0; i < 3; i++)
                {
                    var angle = (Math.PI * 2 * i / 3) - Math.PI / 2;
                    hoverPoints[i] = new Point(
                        (int)(center.X + (radius + 3) * Math.Cos(angle)),
                        (int)(center.Y + (radius + 3) * Math.Sin(angle))
                    );
                }
                g.DrawPolygon(new Pen(Color.Orange, 2), hoverPoints);
            }

            // RFID 중복 노드 표시 (빨간 X자)
            if (_duplicateRfidNodes.Contains(node.Id))
            {
                DrawDuplicateRfidMarker(g, node);
            }

            // CanCross 가능 노드 표시 (교차지점으로 사용 가능)
            if (node.DisableCross == false)
            {
                var crossPoints = new Point[3];
                for (int i = 0; i < 3; i++)
                {
                    var angle = (Math.PI * 2 * i / 3) - Math.PI / 2;
                    crossPoints[i] = new Point(
                        (int)(center.X + (radius + 4) * Math.Cos(angle)),
                        (int)(center.Y + (radius + 4) * Math.Sin(angle))
                    );
                }
                g.DrawPolygon(new Pen(Color.Gold, 3), crossPoints);
            }
        }

        private void DrawNodeLabel(Graphics g, MapNode node)
        {

            Color textColor = Color.White;


            // 위쪽에 표시할 이름 (노드의 Name 속성)
            string TopIDText = node.HasRfid() ? node.RfidId.ToString("0000") : $"[{node.Id}]";

            // 아래쪽에 표시할 값 (RFID 우선, 없으면 노드ID)
            string BottomLabelText = node.Text;

            // 🔥 노드의 폰트 설정 사용 (0 이하일 경우 기본값 7.0f 사용)
            var topFont = new Font("Arial", 9, FontStyle.Bold);
            var btmFont = new Font("Arial", node.NodeTextFontSize, FontStyle.Bold);

            // 메인 텍스트 크기 측정
            var TopSize = g.MeasureString(TopIDText, topFont);
            var BtmSize = g.MeasureString(BottomLabelText, btmFont);

            // 메인 텍스트 위치 (RFID는 노드 위쪽)
            var topPoint = new Point(
                (int)(node.Position.X - TopSize.Width / 2),
                (int)(node.Position.Y - NODE_RADIUS - TopSize.Height - 2)
            );

            // 설명 텍스트 위치 (설명은 노드 아래쪽)
            var btmPoint = new Point(
                (int)(node.Position.X - BtmSize.Width / 2),
                (int)(node.Position.Y + NODE_RADIUS + 2)
            );

            // 설명 텍스트 그리기 (설명이 있는 경우에만)
            if (!string.IsNullOrEmpty(BottomLabelText))
            {
                // 🔥 노드의 말풍선 글자색 사용 (NameBubbleForeColor)
                Color fgColor = Color.Black;
                Color bgColor = Color.White;
                switch (node.StationType)
                {
                    case Station.Charger:
                        fgColor = Color.White;
                        bgColor = Color.Tomato;
                        break;
                    case Station.Buffer:
                        fgColor = Color.Black;
                        bgColor = Color.White;
                        break;
                    case Station.Plating:
                        fgColor = Color.Black;
                        bgColor = Color.DeepSkyBlue;
                        break;
                    case Station.Loder:
                    case Station.Cleaner:
                        fgColor = Color.Black;
                        bgColor = Color.Gold;
                        break;
                    default:
                        fgColor = Color.Black;
                        break;
                }





                var rectpaddingx = 4;
                var rectpaddingy = 2;
                var roundRect = new Rectangle((int)(btmPoint.X - rectpaddingx),
                    (int)(btmPoint.Y),
                    (int)BtmSize.Width + rectpaddingx * 2,
                    (int)BtmSize.Height + rectpaddingy * 2);

                // 라운드 사각형 그리기 (노드 이름 말풍선 배경색 사용)
                using (var backgroundBrush = new SolidBrush(bgColor))
                {
                    DrawRoundedRectangle(g, backgroundBrush, roundRect, 3); // 모서리 반지름 3px
                }

                // 라운드 사각형 테두리 그리기 (진한 빨간색)
                using (var borderPen = new Pen(Color.DimGray, 1))
                {
                    DrawRoundedRectangleBorder(g, borderPen, roundRect, 3);
                }



                using (var descBrush = new SolidBrush(node.NodeTextForeColor))
                {
                    g.DrawString(BottomLabelText, btmFont, descBrush, roundRect, new StringFormat
                    {
                        Alignment = StringAlignment.Center,
                        LineAlignment = StringAlignment.Center,
                    });
                }
            }

            // 메인 텍스트 그리기 (RFID 중복인 경우 특별 처리)
            if (node.HasRfid() && _duplicateRfidNodes.Contains(node.Id))
            {
                // 중복 RFID 노드: 빨간 배경의 라운드 사각형
                DrawDuplicateRfidLabel(g, TopIDText, topPoint, topFont);
            }
            else
            {
                // 일반 텍스트 그리기
                using (var textBrush = new SolidBrush(textColor))
                {
                    g.DrawString(TopIDText, topFont, textBrush, topPoint);
                }
            }

            topFont.Dispose();
            btmFont.Dispose();
        }
        private void DrawLabels(Graphics g)
        {
            if (_labels == null) return;
            foreach (var label in _labels)
            {
                DrawLabel(g, label);
            }
        }

        private void DrawImages(Graphics g)
        {
            if (_images == null) return;
            foreach (var image in _images)
            {
                DrawImage(g, image);
            }
        }

        private void DrawLabel(Graphics g, MapLabel label)
        {
            // 드래그 중인 라벨 확인 (TODO: NodeBase 선택/드래그 로직 통합 시 수정 필요)
            bool isDraggingThisLabel = _isDragging && label == SelectedLabel;
            var text = string.IsNullOrEmpty(label.Text) ? label.Id : label.Text;

            // 폰트 설정
            using (var font = new Font(label.FontFamily, label.FontSize, label.FontStyle))
            using (var textBrush = new SolidBrush(label.ForeColor)) // MapLabel.ForeColor (NodeTextForeColor -> ForeColor)
            {
                // 텍스트 크기 측정
                var textSize = g.MeasureString(text, font);
                var textPoint = new Point(
                    (int)(label.Position.X - textSize.Width / 2),
                    (int)(label.Position.Y - textSize.Height / 2)
                );

                // 드래그 중일 때 그림자 효과
                if (isDraggingThisLabel)
                {
                    var shadowPoint = new Point(textPoint.X + 3, textPoint.Y + 3);
                    using (var shadowBrush = new SolidBrush(Color.FromArgb(100, 0, 0, 0)))
                    {
                        g.DrawString(text, font, shadowBrush, shadowPoint);
                    }
                }

                // 배경 그리기 (설정된 경우)
                if (label.BackColor != Color.Transparent)
                {
                    using (var backgroundBrush = new SolidBrush(label.BackColor))
                    {
                        var backgroundRect = new Rectangle(
                            textPoint.X - label.Padding,
                            textPoint.Y - label.Padding,
                            (int)textSize.Width + (label.Padding * 2),
                            (int)textSize.Height + (label.Padding * 2)
                        );
                        g.FillRectangle(backgroundBrush, backgroundRect);
                        g.DrawRectangle(Pens.Black, backgroundRect);
                    }
                }

                // 텍스트 그리기
                g.DrawString(text, font, textBrush, textPoint);

                // 드래그 중인 노드 강조
                if (isDraggingThisLabel)
                {
                    var dragPadding = label.Padding + 4;
                    var dragRect = new Rectangle(
                        textPoint.X - dragPadding,
                        textPoint.Y - dragPadding,
                        (int)textSize.Width + (dragPadding * 2),
                        (int)textSize.Height + (dragPadding * 2)
                    );
                    g.DrawRectangle(new Pen(Color.Cyan, 3), dragRect);
                }
                // 선택된 노드 강조
                else if (label == SelectedLabel)
                {
                    var selectionPadding = label.Padding + 2;
                    var selectionRect = new Rectangle(
                        textPoint.X - selectionPadding,
                        textPoint.Y - selectionPadding,
                        (int)textSize.Width + (selectionPadding * 2),
                        (int)textSize.Height + (selectionPadding * 2)
                    );
                    g.DrawRectangle(_selectedNodePen, selectionRect);
                }
                // 호버된 라벨 강조
                else if (label == _hoveredNode)
                {
                    var hoverPadding = label.Padding + 2;
                    var hoverRect = new Rectangle(
                        textPoint.X - hoverPadding,
                        textPoint.Y - hoverPadding,
                        (int)textSize.Width + (hoverPadding * 2),
                        (int)textSize.Height + (hoverPadding * 2)
                    );
                    g.DrawRectangle(new Pen(Color.Orange, 2), hoverRect);
                }
            }
        }

        private void DrawImage(Graphics g, MapImage image)
        {
            bool isDraggingThisImage = _isDragging && image == SelectedImage;

            // 이미지 로드 (필요시)
            if (image.LoadedImage == null && !string.IsNullOrEmpty(image.ImagePath))
            {
                image.LoadImage();
            }

            if (image.LoadedImage != null)
            {
                // 실제 표시 크기 계산
                var displaySize = image.GetDisplaySize();
                if (displaySize.IsEmpty)
                    displaySize = new Size(50, 50); // 기본 크기

                // 드래그 중일 때 약간 크게 표시
                if (isDraggingThisImage)
                {
                    displaySize = new Size((int)(displaySize.Width * 1.1), (int)(displaySize.Height * 1.1));
                }

                var imageRect = new Rectangle(
                    image.Position.X - displaySize.Width / 2,
                    image.Position.Y - displaySize.Height / 2,
                    displaySize.Width,
                    displaySize.Height
                );

                // 드래그 중일 때 그림자 효과
                if (isDraggingThisImage)
                {
                    var shadowRect = new Rectangle(imageRect.X + 3, imageRect.Y + 3, imageRect.Width, imageRect.Height);
                    using (var shadowBrush = new SolidBrush(Color.FromArgb(100, 0, 0, 0)))
                    {
                        g.FillRectangle(shadowBrush, shadowRect);
                    }
                }

                // 회전이 있는 경우
                if (image.Rotation != 0)
                {
                    var oldTransform = g.Transform;
                    g.TranslateTransform(image.Position.X, image.Position.Y);
                    g.RotateTransform(image.Rotation);
                    g.TranslateTransform(-image.Position.X, -image.Position.Y);

                    DrawImageContent(g, image, imageRect);

                    g.Transform = oldTransform;
                }
                else
                {
                    DrawImageContent(g, image, imageRect);
                }

                // 선택/드래그 효과
                if (isDraggingThisImage)
                {
                    g.DrawRectangle(new Pen(Color.Cyan, 3), imageRect);
                }
                else if (image == SelectedImage)
                {
                    g.DrawRectangle(_selectedNodePen, imageRect);
                }
                // 호버된 이미지 강조
                else if (image == _hoveredNode)
                {
                    g.DrawRectangle(new Pen(Color.Orange, 2), imageRect);
                }
            }
            else
            {
                // 이미지가 없는 경우 표시 로직 (기존과 유사하게 구현)
                var rect = new Rectangle(image.Position.X - 25, image.Position.Y - 25, 50, 50);
                g.FillRectangle(Brushes.LightGray, rect);
                g.DrawRectangle(Pens.Black, rect);
                using (var font = new Font("Arial", 8))
                    g.DrawString("No Image", font, Brushes.Black, rect);

                if (image == SelectedImage) g.DrawRectangle(_selectedNodePen, rect);
                // 호버된 이미지 강조 (No Image case)
                else if (image == _hoveredNode)
                {
                    g.DrawRectangle(new Pen(Color.Orange, 2), rect);
                }
            }
        }

        private void DrawImageContent(Graphics g, MapImage image, Rectangle rect)
        {
            // 투명도 적용하여 이미지 그리기
            if (image.Opacity < 1.0f)
            {
                using (var imageAttributes = new System.Drawing.Imaging.ImageAttributes())
                {
                    var colorMatrix = new System.Drawing.Imaging.ColorMatrix();
                    colorMatrix.Matrix33 = image.Opacity;
                    imageAttributes.SetColorMatrix(colorMatrix, System.Drawing.Imaging.ColorMatrixFlag.Default,
                        System.Drawing.Imaging.ColorAdjustType.Bitmap);
                    g.DrawImage(image.LoadedImage, rect, 0, 0, image.LoadedImage.Width, image.LoadedImage.Height,
                        GraphicsUnit.Pixel, imageAttributes);
                }
            }
            else
            {
                g.DrawImage(image.LoadedImage, rect);
            }
        }

        private Brush GetNodeBrush(MapNode node)
        {
            // 🔥 노드의 DisplayColor를 배경색으로 사용
            // RFID가 없는 노드는 DisplayColor를 50% 투명도로 표시
            bool hasRfid = node.HasRfid();

            Color bgColor = Color.Transparent;

            switch (node.StationType)
            {
                case Station.Normal:
                    if (node.CanTurnLeft || node.CanTurnRight)
                        bgColor = Color.Violet;
                    else
                        bgColor = Color.DeepSkyBlue;
                    break;
                case Station.Charger: bgColor = Color.Tomato; break;
                case Station.Loder:
                case Station.Cleaner: bgColor = Color.Gold; break;
                case Station.Plating: bgColor = Color.DeepSkyBlue; break;
                case Station.Buffer: bgColor = Color.WhiteSmoke; break;
                case Station.Lmt: bgColor = Color.Red; break;
                default: bgColor = Color.White; break;
            }

            return new SolidBrush(bgColor);
        }

        private void DrawAGVs(Graphics g)
        {
            if (_agvList == null) return;

            foreach (var agv in _agvList)
            {
                if (_agvPositions.ContainsKey(agv.AgvId))
                {
                    DrawAGV(g, agv);
                }
            }
        }

        private void DrawAGV(Graphics g, IAGV agv)
        {
            if (!_agvPositions.ContainsKey(agv.AgvId)) return;

            var position = _agvPositions[agv.AgvId];
            var direction = _agvDirections.ContainsKey(agv.AgvId) ? _agvDirections[agv.AgvId] : AgvDirection.Forward;
            var state = _agvStates.ContainsKey(agv.AgvId) ? _agvStates[agv.AgvId] : AGVState.Idle;

            // AGV 색상 결정
            var brush = GetAGVBrush(state);

            // AGV 개선된 원형 디자인 그리기
            var rect = new Rectangle(
                position.X - AGV_SIZE / 2,
                position.Y - AGV_SIZE / 2,
                AGV_SIZE,
                AGV_SIZE
            );

            // 방사형 그라디언트 효과를 위한 브러시 생성
            using (var gradientBrush = new System.Drawing.Drawing2D.PathGradientBrush(
                new Point[] {
                    new Point(rect.Left, rect.Top),
                    new Point(rect.Right, rect.Top),
                    new Point(rect.Right, rect.Bottom),
                    new Point(rect.Left, rect.Bottom)
                }))
            {
                gradientBrush.CenterPoint = new PointF(position.X, position.Y);
                gradientBrush.CenterColor = GetAGVCenterColor(state);
                gradientBrush.SurroundColors = new Color[] {
                    GetAGVOuterColor(state), GetAGVOuterColor(state),
                    GetAGVOuterColor(state), GetAGVOuterColor(state)
                };

                // 원형으로 AGV 본체 그리기 (3D 효과)
                g.FillEllipse(gradientBrush, rect);

                // 외곽선 (두께 조절)
                using (var outerPen = new Pen(Color.DarkGray, 3))
                {
                    g.DrawEllipse(outerPen, rect);
                }

                // 내부 링 (입체감)
                var innerSize = AGV_SIZE - 8;
                var innerRect = new Rectangle(
                    position.X - innerSize / 2,
                    position.Y - innerSize / 2,
                    innerSize,
                    innerSize
                );
                using (var innerPen = new Pen(GetAGVInnerRingColor(state), 2))
                {
                    g.DrawEllipse(innerPen, innerRect);
                }

                // 중앙 상태 표시등 (더 크고 화려하게)
                var indicatorSize = 10;
                var indicatorRect = new Rectangle(
                    position.X - indicatorSize / 2,
                    position.Y - indicatorSize / 2,
                    indicatorSize,
                    indicatorSize
                );

                // 표시등 글로우 효과
                using (var glowBrush = new System.Drawing.Drawing2D.PathGradientBrush(
                    new Point[] {
                        new Point(indicatorRect.Left, indicatorRect.Top),
                        new Point(indicatorRect.Right, indicatorRect.Top),
                        new Point(indicatorRect.Right, indicatorRect.Bottom),
                        new Point(indicatorRect.Left, indicatorRect.Bottom)
                    }))
                {
                    glowBrush.CenterPoint = new PointF(position.X, position.Y);
                    glowBrush.CenterColor = Color.White;
                    glowBrush.SurroundColors = new Color[] {
                        GetStatusIndicatorColor(state), GetStatusIndicatorColor(state),
                        GetStatusIndicatorColor(state), GetStatusIndicatorColor(state)
                    };

                    g.FillEllipse(glowBrush, indicatorRect);
                    g.DrawEllipse(new Pen(Color.DarkGray, 1), indicatorRect);
                }

                // 원형 센서 패턴 (방사형 배치)
                DrawCircularSensors(g, position, state);
            }

            // 리프트 그리기 (이동 경로 기반)
            DrawAGVLiftAdvanced(g, agv);

            // 모니터 그리기 (리프트 반대편)
            DrawAGVMonitor(g, agv);

            // AGV ID 표시
            var font = new Font("Arial", 10, FontStyle.Bold);
            var textSize = g.MeasureString(agv.AgvId, font);
            var textPoint = new Point(
                (int)(position.X - textSize.Width / 2),
                (int)(position.Y - AGV_SIZE / 2 - textSize.Height - 2)
            );

            g.DrawString(agv.AgvId, font, Brushes.Black, textPoint);

            // 배터리 레벨 표시
            var batteryText = $"{agv.BatteryLevel:F0}%";
            var batterySize = g.MeasureString(batteryText, font);
            var batteryPoint = new Point(
                (int)(position.X - batterySize.Width / 2),
                (int)(position.Y + AGV_SIZE / 2 + 2)
            );

            g.DrawString(batteryText, font, Brushes.Black, batteryPoint);
            font.Dispose();
        }

        private Brush GetAGVBrush(AGVState state)
        {
            switch (state)
            {
                case AGVState.Idle:
                    return Brushes.LightGray;
                case AGVState.Moving:
                    return Brushes.LightGreen;
                case AGVState.Rotating:
                    return Brushes.Yellow;
                case AGVState.Docking:
                    return Brushes.Orange;
                case AGVState.Charging:
                    return Brushes.Blue;
                case AGVState.Error:
                    return Brushes.Red;
                default:
                    return Brushes.LightGray;
            }
        }


        /// <summary>
        /// 이동 경로 기반 개선된 리프트 그리기 (각도 기반 동적 디자인)
        /// </summary>
        private void DrawAGVLiftAdvanced(Graphics g, IAGV agv)
        {
            const int liftLength = 28;  // 리프트 길이 (더욱 크게)
            const int liftWidth = 16;   // 리프트 너비 (더욱 크게)
            const int liftDistance = AGV_SIZE / 2 + 2; // AGV 본체 면에 바로 붙도록


            var currentPos = agv.CurrentPosition;
            var targetPos = agv.PrevPosition;
            var dockingDirection = agv.DockingDirection;
            var currentDirection = agv.CurrentDirection;

            // 경로 예측 기반 LiftCalculator 사용
            Point fallbackTarget = targetPos ?? new Point(currentPos.X + 1, currentPos.Y); // 기본 타겟
            var liftInfo = AGVNavigationCore.Utils.LiftCalculator.CalculateLiftInfoWithPathPrediction(
                currentPos, fallbackTarget, currentDirection, _nodes);

            float liftAngle = (float)liftInfo.AngleRadians;

            // 리프트 위치 계산 (각도 기반)
            Point liftPosition = new Point(
                (int)(currentPos.X + liftDistance * Math.Cos(liftAngle)),
                (int)(currentPos.Y + liftDistance * Math.Sin(liftAngle))
            );

            // 방향을 알 수 있는지 확인
            bool hasDirection = targetPos.HasValue && targetPos.Value != currentPos;

            // 방향에 따른 리프트 색상 및 스타일 결정
            Color liftColor;
            Color borderColor;

            // 모터 방향과 경로 상태에 따른 색상 결정 (더 눈에 띄게)
            switch (currentDirection)
            {
                case AgvDirection.Forward:
                    liftColor = Color.Yellow;        // 전진 - 노란색 (잘 보임)
                    borderColor = Color.Orange;
                    break;
                case AgvDirection.Backward:
                    liftColor = Color.Cyan;          // 후진 - 시안색 (잘 보임)
                    borderColor = Color.DarkCyan;
                    break;
                default:
                    liftColor = Color.LightGray;     // 방향 불명 - 회색
                    borderColor = Color.Gray;
                    break;
            }

            // 경로 예측 결과에 따른 색상 조정
            if (liftInfo.CalculationMethod.Contains("경로 예측"))
            {
                // 경로 예측이 성공한 경우 더 선명한 색상
                if (currentDirection == AgvDirection.Forward)
                {
                    liftColor = Color.Gold;          // 전진 예측 - 골드
                    borderColor = Color.DarkGoldenrod;
                }
                else if (currentDirection == AgvDirection.Backward)
                {
                    liftColor = Color.DeepSkyBlue;   // 후진 예측 - 딥 스카이 블루
                    borderColor = Color.Navy;
                }
            }
            else if (liftInfo.CalculationMethod.Contains("갈래길"))
            {
                // 갈래길에서는 약간 흐린 색상
                liftColor = Color.FromArgb(200, liftColor.R, liftColor.G, liftColor.B);
                borderColor = Color.FromArgb(150, borderColor.R, borderColor.G, borderColor.B);
            }

            // Graphics 상태 저장
            var oldTransform = g.Transform;

            // 리프트 중심으로 회전 변환 적용
            g.TranslateTransform(liftPosition.X, liftPosition.Y);
            g.RotateTransform((float)(liftAngle * 180.0 / Math.PI));

            // 회전된 좌표계에서 리프트 그리기 (중심이 원점)
            var liftRect = new Rectangle(
                -liftLength / 2,   // 중심 기준 왼쪽
                -liftWidth / 2,    // 중심 기준 위쪽  
                liftLength,
                liftWidth
            );

            using (var liftBrush = new SolidBrush(liftColor))
            using (var liftPen = new Pen(borderColor, 3)) // 두껍게 테두리
            {
                // 둥근 사각형으로 리프트 그리기
                DrawRoundedRectangle(g, liftBrush, liftPen, liftRect, 4);

                // 추가 강조 테두리 (더 잘 보이게)
                using (var emphasisPen = new Pen(Color.Black, 1))
                {
                    DrawRoundedRectangle(g, null, emphasisPen, liftRect, 4);
                }
            }

            if (hasDirection)
            {
                // 리프트 세부 표현 (방향 표시용 선들)
                using (var detailPen = new Pen(Color.Gray, 1))
                {
                    int lineSpacing = 4;
                    for (int i = -liftLength / 2 + 3; i < liftLength / 2 - 3; i += lineSpacing)
                    {
                        g.DrawLine(detailPen, i, -liftWidth / 2 + 2, i, liftWidth / 2 - 2);
                    }
                }

                // 이동 방향 표시 화살표 (리프트 끝쪽)
                using (var arrowPen = new Pen(borderColor, 2))
                {
                    var arrowSize = 3;
                    var arrowX = liftLength / 2 - 4;

                    // 화살표 모양
                    g.DrawLine(arrowPen, arrowX, 0, arrowX + arrowSize, -arrowSize);
                    g.DrawLine(arrowPen, arrowX, 0, arrowX + arrowSize, arrowSize);
                }
            }
            else
            {
                // 방향을 모를 때 '?' 표시
                using (var questionBrush = new SolidBrush(Color.DarkGray))
                using (var questionFont = new Font("Arial", 9, FontStyle.Bold))
                {
                    var questionSize = g.MeasureString("?", questionFont);
                    var questionPoint = new PointF(
                        -questionSize.Width / 2,
                        -questionSize.Height / 2
                    );
                    g.DrawString("?", questionFont, questionBrush, questionPoint);
                }
            }

            // Graphics 상태 복원
            g.Transform = oldTransform;
        }

        /// <summary>
        /// 둥근 모서리 사각형 그리기
        /// </summary>
        private void DrawRoundedRectangle(Graphics g, Brush fillBrush, Pen borderPen, Rectangle rect, int cornerRadius)
        {
            if (cornerRadius <= 0)
            {
                if (fillBrush != null)
                    g.FillRectangle(fillBrush, rect);
                if (borderPen != null)
                    g.DrawRectangle(borderPen, rect);
                return;
            }

            using (var path = new System.Drawing.Drawing2D.GraphicsPath())
            {
                // 둥근 모서리 경로 생성
                path.AddArc(rect.X, rect.Y, cornerRadius * 2, cornerRadius * 2, 180, 90);
                path.AddArc(rect.Right - cornerRadius * 2, rect.Y, cornerRadius * 2, cornerRadius * 2, 270, 90);
                path.AddArc(rect.Right - cornerRadius * 2, rect.Bottom - cornerRadius * 2, cornerRadius * 2, cornerRadius * 2, 0, 90);
                path.AddArc(rect.X, rect.Bottom - cornerRadius * 2, cornerRadius * 2, cornerRadius * 2, 90, 90);
                path.CloseFigure();

                // 채우기와 테두리 그리기 (null 체크 추가)
                if (fillBrush != null)
                    g.FillPath(fillBrush, path);
                if (borderPen != null)
                    g.DrawPath(borderPen, path);
            }
        }

        private void DrawAGVLiftDebugInfo(Graphics g, IAGV agv)
        {
            var currentPos = agv.CurrentPosition;
            var targetPos = agv.PrevPosition;

            // 디버그 정보 (개발용)
            if (targetPos.HasValue)
            {
                // 이동 방향 벡터 그리기 (얇은 점선)
                using (var debugPen = new Pen(Color.Red, 1) { DashStyle = System.Drawing.Drawing2D.DashStyle.Dot })
                {
                    g.DrawLine(debugPen, currentPos, targetPos.Value);
                }
            }
        }

        private void DrawTemporaryConnection(Graphics g)
        {
            if (_connectionStartNode != null && _connectionEndPoint != Point.Empty)
            {
                g.DrawLine(_tempConnectionPen, _connectionStartNode.Position, _connectionEndPoint);
            }
        }

        /// <summary>
        /// AGV 중앙 색상 (방사형 그라디언트)
        /// </summary>
        private Color GetAGVCenterColor(AGVState state)
        {
            // Stop-Mark 상태 (Error 상태와 유사하게 처리하거나 별도 처리)
            // 여기서는 AGVState에 StopMark가 없으므로, 외부에서 상태를 Error로 설정하거나
            // 별도의 플래그를 확인해야 함. 하지만 IAGV 인터페이스에는 플래그가 없음.
            // 따라서 fMain에서 상태를 Error로 설정하는 것을 권장.

            switch (state)
            {
                case AGVState.Moving: return Color.White;
                case AGVState.Charging: return Color.LightCyan;
                case AGVState.Error: return Color.LightPink;
                case AGVState.Docking: return Color.LightYellow;
                default: return Color.WhiteSmoke;
            }
        }

        /// <summary>
        /// AGV 외곽 색상 (방사형 그라디언트)
        /// </summary>
        private Color GetAGVOuterColor(AGVState state)
        {
            switch (state)
            {
                case AGVState.Moving: return Color.DarkGreen;
                case AGVState.Charging: return Color.DarkBlue;
                case AGVState.Error: return Color.DarkRed; // Stop-Mark 시 Error 상태 사용
                case AGVState.Docking: return Color.DarkOrange;
                default: return Color.DarkGray;
            }
        }

        /// <summary>
        /// AGV 내부 링 색상
        /// </summary>
        private Color GetAGVInnerRingColor(AGVState state)
        {
            switch (state)
            {
                case AGVState.Moving: return Color.Green;
                case AGVState.Charging: return Color.Blue;
                case AGVState.Error: return Color.Red;
                case AGVState.Docking: return Color.Orange;
                default: return Color.Gray;
            }
        }

        /// <summary>
        /// AGV 중앙 표시등 색상
        /// </summary>
        private Color GetStatusIndicatorColor(AGVState state)
        {
            switch (state)
            {
                case AGVState.Moving: return Color.Lime;
                case AGVState.Charging: return Color.Blue;
                case AGVState.Error: return Color.Red;
                case AGVState.Docking: return Color.Yellow;
                default: return Color.Gray;
            }
        }

        /// <summary>
        /// AGV 원형 센서 패턴 (방사형 배치)
        /// </summary>
        private void DrawCircularSensors(Graphics g, Point center, AGVState state)
        {
            var sensorSize = 3;
            var sensorColor = state == AGVState.Error ? Color.Red : Color.Silver;
            var radius = AGV_SIZE / 2 - 6;

            // 8방향으로 센서 배치 (45도씩)
            for (int i = 0; i < 8; i++)
            {
                double angle = i * Math.PI / 4; // 45도씩
                int sensorX = (int)(center.X + radius * Math.Cos(angle));
                int sensorY = (int)(center.Y + radius * Math.Sin(angle));

                var sensorRect = new Rectangle(
                    sensorX - sensorSize / 2,
                    sensorY - sensorSize / 2,
                    sensorSize,
                    sensorSize
                );

                using (var sensorBrush = new SolidBrush(sensorColor))
                {
                    g.FillEllipse(sensorBrush, sensorRect);
                    g.DrawEllipse(new Pen(Color.Black, 1), sensorRect);
                }
            }

            // 내부 원형 패턴 (장식)
            var innerRadius = AGV_SIZE / 2 - 12;
            for (int i = 0; i < 4; i++)
            {
                double angle = i * Math.PI / 2 + Math.PI / 4; // 45도 오프셋된 4방향
                int dotX = (int)(center.X + innerRadius * Math.Cos(angle));
                int dotY = (int)(center.Y + innerRadius * Math.Sin(angle));

                var dotRect = new Rectangle(dotX - 1, dotY - 1, 2, 2);
                using (var dotBrush = new SolidBrush(GetAGVInnerRingColor(state)))
                {
                    g.FillEllipse(dotBrush, dotRect);
                }
            }
        }

        /// <summary>
        /// AGV 모니터 그리기 (리프트 반대편)
        /// </summary>
        private void DrawAGVMonitor(Graphics g, IAGV agv)
        {
            const int monitorWidth = 12;   // 모니터 너비 (가로로 더 길게)
            const int monitorHeight = 24;  // 모니터 높이 (세로는 줄임)
            const int monitorDistance = AGV_SIZE / 2 + 2; // AGV 본체에서 거리 (리프트와 동일)

            var currentPos = agv.CurrentPosition;
            var targetPos = agv.PrevPosition;
            var dockingDirection = agv.DockingDirection;
            var currentDirection = agv.CurrentDirection;

            // 리프트 방향 계산 (모니터는 정반대)
            Point fallbackTarget = targetPos ?? new Point(currentPos.X + 50, currentPos.Y);

            var liftInfo = AGVNavigationCore.Utils.LiftCalculator.CalculateLiftInfoWithPathPrediction(
                currentPos, fallbackTarget, currentDirection, _nodes);

            bool hasDirection = liftInfo != null;
            double monitorAngle = hasDirection ? liftInfo.AngleRadians + Math.PI : 0; // 리프트 반대 방향 (180도 회전)

            // Graphics 변환 설정
            var oldTransform = g.Transform;
            var transform = oldTransform.Clone();
            transform.Translate(currentPos.X, currentPos.Y);
            transform.Rotate((float)(monitorAngle * 180.0 / Math.PI));
            g.Transform = transform;

            // 모니터 위치 (AGV 면에 붙도록)
            var monitorRect = new Rectangle(
                monitorDistance - monitorWidth / 2,
                -monitorHeight / 2,
                monitorWidth,
                monitorHeight
            );

            if (hasDirection)
            {
                // 모니터 상태에 따른 색상
                var monitorBackColor = GetMonitorBackColor(agv.CurrentState);
                var monitorBorderColor = Color.DarkGray;

                // 모니터 본체 (둥근 모서리)
                using (var monitorBrush = new SolidBrush(monitorBackColor))
                using (var borderPen = new Pen(monitorBorderColor, 2))
                {
                    DrawRoundedRectangle(g, monitorBrush, borderPen, monitorRect, 2);
                }

                // 모니터 화면 (내부 사각형)
                var screenRect = new Rectangle(
                    monitorRect.X + 2,
                    monitorRect.Y + 2,
                    monitorRect.Width - 4,
                    monitorRect.Height - 4
                );

                using (var screenBrush = new SolidBrush(GetMonitorScreenColor(agv.CurrentState)))
                {
                    g.FillRectangle(screenBrush, screenRect);
                }

                // 화면 패턴 (상태별)
                DrawMonitorScreen(g, screenRect, agv.CurrentState);

                // 모니터 스탠드
                var standRect = new Rectangle(
                    monitorDistance - 2,
                    monitorHeight / 2 - 1,
                    4,
                    3
                );
                using (var standBrush = new SolidBrush(Color.Gray))
                {
                    g.FillRectangle(standBrush, standRect);
                }
            }
            else
            {
                // 방향을 모를 때 기본 모니터 (스카이블루로)
                using (var monitorBrush = new SolidBrush(Color.SkyBlue))
                using (var borderPen = new Pen(Color.DarkGray, 2))
                {
                    DrawRoundedRectangle(g, monitorBrush, borderPen, monitorRect, 2);
                }
            }

            // Graphics 상태 복원
            g.Transform = oldTransform;
        }

        /// <summary>
        /// 모니터 배경 색상 (스카이블루 계통으로 통일)
        /// </summary>
        private Color GetMonitorBackColor(AGVState state)
        {
            // 모든 상태에서 스카이블루 계통으로 통일하여 AGV와 구분
            return Color.SkyBlue;
        }

        /// <summary>
        /// 모니터 화면 색상 (상태별로 구분)
        /// </summary>
        private Color GetMonitorScreenColor(AGVState state)
        {
            switch (state)
            {
                case AGVState.Moving: return Color.Navy;        // 이동: 네이비
                case AGVState.Charging: return Color.DarkBlue; // 충전: 다크블루
                case AGVState.Error: return Color.DarkRed;     // 에러: 다크레드
                case AGVState.Docking: return Color.DarkGreen; // 도킹: 다크그린
                default: return Color.DarkSlateGray;           // 대기: 다크슬레이트그레이
            }
        }

        /// <summary>
        /// 모니터 화면 패턴 그리기
        /// </summary>
        private void DrawMonitorScreen(Graphics g, Rectangle screenRect, AGVState state)
        {
            using (var patternPen = new Pen(Color.White, 1))
            {
                switch (state)
                {
                    case AGVState.Moving:
                        // 이동 중: 작은 점들 (데이터 표시)
                        for (int i = 1; i < screenRect.Width; i += 3)
                        {
                            for (int j = 1; j < screenRect.Height; j += 3)
                            {
                                g.DrawRectangle(patternPen, screenRect.X + i, screenRect.Y + j, 1, 1);
                            }
                        }
                        break;

                    case AGVState.Charging:
                        // 충전 중: 배터리 아이콘
                        var batteryRect = new Rectangle(
                            screenRect.X + screenRect.Width / 2 - 3,
                            screenRect.Y + screenRect.Height / 2 - 2,
                            6,
                            4
                        );
                        g.DrawRectangle(patternPen, batteryRect);
                        g.DrawLine(patternPen, batteryRect.Right, batteryRect.Y + 1, batteryRect.Right, batteryRect.Bottom - 1);
                        break;

                    case AGVState.Error:
                        // 에러: X 마크
                        g.DrawLine(patternPen, screenRect.X + 2, screenRect.Y + 2,
                                  screenRect.Right - 2, screenRect.Bottom - 2);
                        g.DrawLine(patternPen, screenRect.Right - 2, screenRect.Y + 2,
                                  screenRect.X + 2, screenRect.Bottom - 2);
                        break;

                    case AGVState.Docking:
                        // 도킹: 화살표
                        var centerX = screenRect.X + screenRect.Width / 2;
                        var centerY = screenRect.Y + screenRect.Height / 2;
                        g.DrawLine(patternPen, centerX - 4, centerY, centerX + 2, centerY);
                        g.DrawLine(patternPen, centerX, centerY - 2, centerX + 2, centerY);
                        g.DrawLine(patternPen, centerX, centerY + 2, centerX + 2, centerY);
                        break;

                    default:
                        // 대기: 중앙 점
                        g.DrawRectangle(patternPen,
                                      screenRect.X + screenRect.Width / 2 - 1,
                                      screenRect.Y + screenRect.Height / 2 - 1,
                                      2, 2);
                        break;
                }
            }
        }

        private void DrawUIInfo(Graphics g)
        {
            // 회사 로고
            if (_companyLogo != null)
            {
                var logoRect = new Rectangle(10, 10, 100, 50);
                g.DrawImage(_companyLogo, logoRect);
            }

            // 줌 및 스케일 정보 (동적 계산)
            // 스케일: 1픽셀 = GRID_SIZE / _zoomFactor mm
            // 예: GRID_SIZE=10, zoom=1.0 → 1:10, zoom=0.1 → 1:100
            double scaleRatio = GRID_SIZE / _zoomFactor;
            var zoomText = $"Zoom: {_zoomFactor:P0}";
            var scaleText = $"스케일: 1:{scaleRatio:F0}";

            using (var font = new Font("맑은 고딕", 10, FontStyle.Bold))
            using (var bgBrush = new SolidBrush(Color.FromArgb(220, Color.White)))
            {
                // 줌 정보 (좌하단)
                var zoomSize = g.MeasureString(zoomText, font);
                var zoomRect = new RectangleF(10, Height - zoomSize.Height - 15, zoomSize.Width + 10, zoomSize.Height + 5);
                g.FillRectangle(bgBrush, zoomRect);
                g.DrawRectangle(Pens.Gray, zoomRect.X, zoomRect.Y, zoomRect.Width, zoomRect.Height);
                g.DrawString(zoomText, font, Brushes.Black, zoomRect.X + 5, zoomRect.Y + 2);

                // 스케일 정보 (줌 정보 위에)
                var scaleSize = g.MeasureString(scaleText, font);
                var scaleRect = new RectangleF(10, Height - zoomSize.Height - scaleSize.Height - 25, scaleSize.Width + 10, scaleSize.Height + 5);
                g.FillRectangle(bgBrush, scaleRect);
                g.DrawRectangle(Pens.Gray, scaleRect.X, scaleRect.Y, scaleRect.Width, scaleRect.Height);
                g.DrawString(scaleText, font, Brushes.Black, scaleRect.X + 5, scaleRect.Y + 2);

                // 팬 정보 (스케일 정보 위에)
                var panText = $"Pan: {_panOffset.X:F1}, {_panOffset.Y:F1}";
                var panSize = g.MeasureString(panText, font);
                var panRect = new RectangleF(10, Height - zoomSize.Height - scaleSize.Height - panSize.Height - 35, panSize.Width + 10, panSize.Height + 5);
                g.FillRectangle(bgBrush, panRect);
                g.DrawRectangle(Pens.Gray, panRect.X, panRect.Y, panRect.Width, panRect.Height);
                g.DrawString(panText, font, Brushes.Black, panRect.X + 5, panRect.Y + 2);
            }


            // 측정 정보 (우하단 - 사용자 정의 정보가 있을 경우)
            if (!string.IsNullOrEmpty(_measurementInfo))
            {
                using (var font = new Font("맑은 고딕", 9))
                using (var textBrush = new SolidBrush(Color.Black))
                using (var backgroundBrush = new SolidBrush(Color.FromArgb(200, Color.White)))
                {
                    var textSize = g.MeasureString(_measurementInfo, font);
                    var textRect = new Rectangle(
                        Width - (int)textSize.Width - 20,
                        Height - (int)textSize.Height - 20,
                        (int)textSize.Width + 10,
                        (int)textSize.Height + 10
                    );

                    g.FillRectangle(backgroundBrush, textRect);
                    g.DrawRectangle(Pens.Gray, textRect);
                    g.DrawString(_measurementInfo, font, textBrush, textRect.X + 5, textRect.Y + 5);
                }
            }
        }

        /// <summary>
        /// RFID 중복 노드에 빨간 X자 표시를 그림
        /// </summary>
        private void DrawDuplicateRfidMarker(Graphics g, MapNode node)
        {
            // X자를 그리기 위한 펜 (빨간색, 굵기 3)
            using (var pen = new Pen(Color.Red, 3))
            {
                var center = node.Position;
                var size = NODE_RADIUS; // 노드 반지름 크기로 X자 크기 설정

                // X자의 두 대각선 그리기
                // 좌상 → 우하 대각선
                g.DrawLine(pen,
                    center.X - size, center.Y - size,
                    center.X + size, center.Y + size);

                // 우상 → 좌하 대각선
                g.DrawLine(pen,
                    center.X + size, center.Y - size,
                    center.X - size, center.Y + size);
            }
        }

        /// <summary>
        /// 중복 RFID 값을 빨간 배경의 라운드 사각형으로 표시
        /// </summary>
        private void DrawDuplicateRfidLabel(Graphics g, string text, Point position, Font font)
        {
            // 텍스트 크기 측정
            var textSize = g.MeasureString(text, font);

            // 라운드 사각형 영역 계산 (텍스트보다 약간 크게)
            var padding = 2;
            var rectWidth = (int)textSize.Width + padding * 2;
            var rectHeight = (int)textSize.Height + padding * 2;
            var rectX = position.X - padding;
            var rectY = position.Y - padding - 5;

            var roundRect = new Rectangle(rectX, rectY, rectWidth, rectHeight);

            // 라운드 사각형 그리기 (빨간 배경)
            using (var backgroundBrush = new SolidBrush(Color.Red))
            {
                DrawRoundedRectangle(g, backgroundBrush, roundRect, 6); // 모서리 반지름 6px
            }

            // 라운드 사각형 테두리 그리기 (진한 빨간색)
            using (var borderPen = new Pen(Color.DarkRed, 1))
            {
                DrawRoundedRectangleBorder(g, borderPen, roundRect, 6);
            }

            // 흰색 텍스트 그리기
            using (var textBrush = new SolidBrush(Color.White))
            {
                g.DrawString(text, font, textBrush, roundRect, new StringFormat
                {
                    Alignment = StringAlignment.Center,
                    LineAlignment = StringAlignment.Center,
                });
            }
        }

        /// <summary>
        /// 라운드 사각형 채우기
        /// </summary>
        private void DrawRoundedRectangle(Graphics g, Brush brush, Rectangle rect, int radius)
        {
            using (var path = new GraphicsPath())
            {
                path.AddArc(rect.X, rect.Y, radius * 2, radius * 2, 180, 90);
                path.AddArc(rect.Right - radius * 2, rect.Y, radius * 2, radius * 2, 270, 90);
                path.AddArc(rect.Right - radius * 2, rect.Bottom - radius * 2, radius * 2, radius * 2, 0, 90);
                path.AddArc(rect.X, rect.Bottom - radius * 2, radius * 2, radius * 2, 90, 90);
                path.CloseFigure();

                g.FillPath(brush, path);
            }
        }

        /// <summary>
        /// 라운드 사각형 테두리 그리기
        /// </summary>
        private void DrawRoundedRectangleBorder(Graphics g, Pen pen, Rectangle rect, int radius)
        {
            using (var path = new GraphicsPath())
            {
                path.AddArc(rect.X, rect.Y, radius * 2, radius * 2, 180, 90);
                path.AddArc(rect.Right - radius * 2, rect.Y, radius * 2, radius * 2, 270, 90);
                path.AddArc(rect.Right - radius * 2, rect.Bottom - radius * 2, radius * 2, radius * 2, 0, 90);
                path.AddArc(rect.X, rect.Bottom - radius * 2, radius * 2, radius * 2, 90, 90);
                path.CloseFigure();

                g.DrawPath(pen, path);
            }
        }

        private Rectangle GetVisibleBounds()
        {
            // Graphics Transform: Screen = (World + Pan) * Zoom
            // World = Screen / Zoom - Pan
            var left = (int)(0 / _zoomFactor - _panOffset.X);
            var top = (int)(0 / _zoomFactor - _panOffset.Y);
            var right = (int)(Width / _zoomFactor - _panOffset.X);
            var bottom = (int)(Height / _zoomFactor - _panOffset.Y);

            return new Rectangle(left, top, right - left, bottom - top);
        }

        #endregion
    }
}