using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using AGVNavigationCore.Utils;

namespace AGVNavigationCore.Models
{
    /// <summary>
    /// 맵 노드 정보를 관리하는 클래스
    /// 논리적 노드로서 실제 맵의 위치와 속성을 정의
    /// </summary>
    public class MapNode
    {
        /// <summary>
        /// 논리적 노드 ID (맵 에디터에서 관리하는 고유 ID)
        /// 예: "N001", "N002", "LOADER1", "CHARGER1"
        /// </summary>
        public string NodeId { get; set; } = string.Empty;

        /// <summary>
        /// 노드 표시 이름 (사용자 친화적)
        /// 예: "로더1", "충전기1", "교차점A", "회전지점1"
        /// </summary>
        public string Name { get; set; } = string.Empty;

        /// <summary>
        /// 맵 상의 위치 좌표 (픽셀 단위)
        /// </summary>
        public Point Position { get; set; } = Point.Empty;

        /// <summary>
        /// 노드 타입
        /// </summary>
        public NodeType Type { get; set; } = NodeType.Normal;

        /// <summary>
        /// 도킹 방향 (도킹/충전 노드인 경우에만 Forward/Backward, 일반 노드는 DontCare)
        /// </summary>
        public DockingDirection DockDirection { get; set; } = DockingDirection.DontCare;

        /// <summary>
        /// 연결된 노드 ID 목록 (경로 정보)
        /// </summary>
        public List<string> ConnectedNodes { get; set; } = new List<string>();

        /// <summary>
        /// 연결된 노드 객체 목록 (런타임 전용, JSON 무시)
        /// </summary>
        [Newtonsoft.Json.JsonIgnore]
        public List<MapNode> ConnectedMapNodes { get; set; } = new List<MapNode>();

        /// <summary>
        /// 회전 가능 여부 (180도 회전 가능한 지점)
        /// </summary>
        public bool CanRotate { get; set; } = false;

        /// <summary>
        /// 장비 ID (도킹/충전 스테이션인 경우)
        /// 예: "LOADER1", "CLEANER1", "BUFFER1", "CHARGER1"
        /// </summary>
        public string StationId { get; set; } = string.Empty;

        /// <summary>
        /// 장비 타입 (도킹/충전 스테이션인 경우)
        /// </summary>
        public StationType? StationType { get; set; } = null;

        /// <summary>
        /// 노드 생성 일자
        /// </summary>
        public DateTime CreatedDate { get; set; } = DateTime.Now;

        /// <summary>
        /// 노드 수정 일자
        /// </summary>
        public DateTime ModifiedDate { get; set; } = DateTime.Now;


        /// <summary>
        /// 노드 활성화 여부
        /// </summary>
        public bool IsActive { get; set; } = true;

        /// <summary>
        /// 노드 색상 (맵 에디터 표시용)
        /// </summary>
        public Color DisplayColor { get; set; } = Color.Blue;

        /// <summary>
        /// RFID 태그 ID (이 노드에 매핑된 RFID)
        /// </summary>
        public string RfidId { get; set; } = string.Empty;

        /// <summary>
        /// RFID 상태 (정상, 손상, 교체예정 등)
        /// </summary>
        public string RfidStatus { get; set; } = "정상";

        /// <summary>
        /// RFID 설치 위치 설명 (현장 작업자용)
        /// 예: "로더1번 앞", "충전기2번 입구", "복도 교차점" 등
        /// </summary>
        public string RfidDescription { get; set; } = string.Empty;

        /// <summary>
        /// 라벨 텍스트 (NodeType.Label인 경우 사용)
        /// </summary>
        public string LabelText { get; set; } = string.Empty;

        /// <summary>
        /// 라벨 폰트 패밀리 (NodeType.Label인 경우 사용)
        /// </summary>
        public string FontFamily { get; set; } = "Arial";

        /// <summary>
        /// 라벨 폰트 크기 (NodeType.Label인 경우 사용)
        /// </summary>
        public float FontSize { get; set; } = 12.0f;

        /// <summary>
        /// 라벨 폰트 스타일 (NodeType.Label인 경우 사용)
        /// </summary>
        public FontStyle FontStyle { get; set; } = FontStyle.Regular;

        /// <summary>
        /// 라벨 전경색 (NodeType.Label인 경우 사용)
        /// </summary>
        public Color ForeColor { get; set; } = Color.Black;

        /// <summary>
        /// 라벨 배경색 (NodeType.Label인 경우 사용)
        /// </summary>
        public Color BackColor { get; set; } = Color.Transparent;

        /// <summary>
        /// 라벨 배경 표시 여부 (NodeType.Label인 경우 사용)
        /// </summary>
        public bool ShowBackground { get; set; } = false;

        /// <summary>
        /// 라벨 패딩 (NodeType.Label인 경우 사용, 픽셀 단위)
        /// </summary>
        public int Padding { get; set; } = 8;

        /// <summary>
        /// 이미지 파일 경로 (편집용, 저장시엔 사용되지 않음)
        /// </summary>
        [Newtonsoft.Json.JsonIgnore]
        public string ImagePath { get; set; } = string.Empty;

        /// <summary>
        /// Base64 인코딩된 이미지 데이터 (JSON 저장용)
        /// </summary>
        public string ImageBase64 { get; set; } = string.Empty;

        /// <summary>
        /// 이미지 크기 배율 (NodeType.Image인 경우 사용)
        /// </summary>
        public SizeF Scale { get; set; } = new SizeF(1.0f, 1.0f);

        /// <summary>
        /// 이미지 투명도 (NodeType.Image인 경우 사용, 0.0~1.0)
        /// </summary>
        public float Opacity { get; set; } = 1.0f;

        /// <summary>
        /// 이미지 회전 각도 (NodeType.Image인 경우 사용, 도 단위)
        /// </summary>
        public float Rotation { get; set; } = 0.0f;

        /// <summary>
        /// 로딩된 이미지 (런타임에서만 사용, JSON 직렬화 제외)
        /// </summary>
        [Newtonsoft.Json.JsonIgnore]
        public Image LoadedImage { get; set; }

        /// <summary>
        /// 기본 생성자
        /// </summary>
        public MapNode()
        {
        }

        /// <summary>
        /// 매개변수 생성자
        /// </summary>
        /// <param name="nodeId">노드 ID</param>
        /// <param name="name">노드 이름</param>
        /// <param name="position">위치</param>
        /// <param name="type">노드 타입</param>
        public MapNode(string nodeId, string name, Point position, NodeType type)
        {
            NodeId = nodeId;
            Name = name;
            Position = position;
            Type = type;
            CreatedDate = DateTime.Now;
            ModifiedDate = DateTime.Now;
            
            // 타입별 기본 색상 설정
            SetDefaultColorByType(type);
        }

        /// <summary>
        /// 노드 타입에 따른 기본 색상 설정
        /// </summary>
        /// <param name="type">노드 타입</param>
        public void SetDefaultColorByType(NodeType type)
        {
            switch (type)
            {
                case NodeType.Normal:
                    DisplayColor = Color.Blue;
                    break;
                case NodeType.Rotation:
                    DisplayColor = Color.Orange;
                    break;
                case NodeType.Docking:
                    DisplayColor = Color.Green;
                    break;
                case NodeType.Charging:
                    DisplayColor = Color.Red;
                    break;
                case NodeType.Label:
                    DisplayColor = Color.Purple;
                    break;
                case NodeType.Image:
                    DisplayColor = Color.Brown;
                    break;
            }
        }

        /// <summary>
        /// 다른 노드와의 연결 추가
        /// </summary>
        /// <param name="nodeId">연결할 노드 ID</param>
        public void AddConnection(string nodeId)
        {
            if (!ConnectedNodes.Contains(nodeId))
            {
                ConnectedNodes.Add(nodeId);
                ModifiedDate = DateTime.Now;
            }
        }

        /// <summary>
        /// 다른 노드와의 연결 제거
        /// </summary>
        /// <param name="nodeId">연결 해제할 노드 ID</param>
        public void RemoveConnection(string nodeId)
        {
            if (ConnectedNodes.Remove(nodeId))
            {
                ModifiedDate = DateTime.Now;
            }
        }

        /// <summary>
        /// 도킹 스테이션 설정
        /// </summary>
        /// <param name="stationId">장비 ID</param>
        /// <param name="stationType">장비 타입</param>
        /// <param name="dockDirection">도킹 방향</param>
        public void SetDockingStation(string stationId, StationType stationType, DockingDirection dockDirection)
        {
            Type = NodeType.Docking;
            StationId = stationId;
            StationType = stationType;
            DockDirection = dockDirection;
            SetDefaultColorByType(NodeType.Docking);
            ModifiedDate = DateTime.Now;
        }

        /// <summary>
        /// 충전 스테이션 설정
        /// </summary>
        /// <param name="stationId">충전기 ID</param>
        public void SetChargingStation(string stationId)
        {
            Type = NodeType.Charging;
            StationId = stationId;
            StationType = Models.StationType.Charger;
            DockDirection = DockingDirection.Forward; // 충전기는 항상 전진 도킹
            SetDefaultColorByType(NodeType.Charging);
            ModifiedDate = DateTime.Now;
        }

        /// <summary>
        /// 문자열 표현
        /// </summary>
        public override string ToString()
        {
            return $"{RfidId}({NodeId}): {Name} ({Type}) at ({Position.X}, {Position.Y})";
        }

        /// <summary>
        /// 리스트박스 표시용 텍스트 (노드ID - 설명 - RFID 순서)
        /// </summary>
        public string DisplayText
        {
            get
            {
                var displayText = NodeId;
                
                if (!string.IsNullOrEmpty(Name))
                {
                    displayText += $" - {Name}";
                }
                
                if (!string.IsNullOrEmpty(RfidId))
                {
                    displayText += $" - [{RfidId}]";
                }
                
                return displayText;
            }
        }

        /// <summary>
        /// 노드 복사
        /// </summary>
        /// <returns>복사된 노드</returns>
        public MapNode Clone()
        {
            var clone = new MapNode
            {
                NodeId = NodeId,
                Name = Name,
                Position = Position,
                Type = Type,
                DockDirection = DockDirection,
                ConnectedNodes = new List<string>(ConnectedNodes),
                CanRotate = CanRotate,
                StationId = StationId,
                StationType = StationType,
                CreatedDate = CreatedDate,
                ModifiedDate = ModifiedDate,
                IsActive = IsActive,
                DisplayColor = DisplayColor,
                RfidId = RfidId,
                RfidStatus = RfidStatus,
                RfidDescription = RfidDescription,
                LabelText = LabelText,
                FontFamily = FontFamily,
                FontSize = FontSize,
                FontStyle = FontStyle,
                ForeColor = ForeColor,
                BackColor = BackColor,
                ShowBackground = ShowBackground,
                Padding = Padding,
                ImagePath = ImagePath,
                ImageBase64 = ImageBase64,
                Scale = Scale,
                Opacity = Opacity,
                Rotation = Rotation
            };
            return clone;
        }

        /// <summary>
        /// 이미지 로드 (Base64 또는 파일 경로에서, 256x256 이상일 경우 자동 리사이즈)
        /// </summary>
        /// <returns>로드 성공 여부</returns>
        public bool LoadImage()
        {
            if (Type != NodeType.Image) return false;

            try
            {
                Image originalImage = null;

                // 1. 먼저 Base64 데이터 시도
                if (!string.IsNullOrEmpty(ImageBase64))
                {
                    originalImage = ImageConverterUtil.Base64ToImage(ImageBase64);
                }
                // 2. Base64가 없으면 파일 경로에서 로드
                else if (!string.IsNullOrEmpty(ImagePath) && System.IO.File.Exists(ImagePath))
                {
                    originalImage = Image.FromFile(ImagePath);
                }

                if (originalImage != null)
                {
                    LoadedImage?.Dispose();

                    // 이미지 크기 체크 및 리사이즈
                    if (originalImage.Width > 256 || originalImage.Height > 256)
                    {
                        LoadedImage = ResizeImage(originalImage, 256, 256);
                        originalImage.Dispose();
                    }
                    else
                    {
                        LoadedImage = originalImage;
                    }

                    return true;
                }
            }
            catch (Exception)
            {
                // 이미지 로드 실패
            }
            return false;
        }

        /// <summary>
        /// 이미지 리사이즈 (비율 유지)
        /// </summary>
        /// <param name="image">원본 이미지</param>
        /// <param name="maxWidth">최대 너비</param>
        /// <param name="maxHeight">최대 높이</param>
        /// <returns>리사이즈된 이미지</returns>
        private Image ResizeImage(Image image, int maxWidth, int maxHeight)
        {
            // 비율 계산
            double ratioX = (double)maxWidth / image.Width;
            double ratioY = (double)maxHeight / image.Height;
            double ratio = Math.Min(ratioX, ratioY);

            // 새로운 크기 계산
            int newWidth = (int)(image.Width * ratio);
            int newHeight = (int)(image.Height * ratio);

            // 리사이즈된 이미지 생성
            var resizedImage = new Bitmap(newWidth, newHeight);
            using (var graphics = Graphics.FromImage(resizedImage))
            {
                graphics.CompositingQuality = CompositingQuality.HighQuality;
                graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
                graphics.SmoothingMode = SmoothingMode.HighQuality;
                graphics.DrawImage(image, 0, 0, newWidth, newHeight);
            }

            return resizedImage;
        }

        /// <summary>
        /// 실제 표시될 크기 계산 (이미지 노드인 경우)
        /// </summary>
        /// <returns>실제 크기</returns>
        public Size GetDisplaySize()
        {
            if (Type != NodeType.Image || LoadedImage == null) return Size.Empty;
            
            return new Size(
                (int)(LoadedImage.Width * Scale.Width),
                (int)(LoadedImage.Height * Scale.Height)
            );
        }

        /// <summary>
        /// 파일 경로에서 이미지를 Base64로 변환하여 저장
        /// </summary>
        /// <param name="filePath">이미지 파일 경로</param>
        /// <returns>변환 성공 여부</returns>
        public bool ConvertImageToBase64(string filePath)
        {
            if (Type != NodeType.Image) return false;

            try
            {
                if (!System.IO.File.Exists(filePath))
                {
                    return false;
                }

                ImageBase64 = ImageConverterUtil.FileToBase64(filePath, System.Drawing.Imaging.ImageFormat.Png);
                ImagePath = filePath; // 편집용으로 경로 유지

                return !string.IsNullOrEmpty(ImageBase64);
            }
            catch (Exception)
            {
                return false;
            }
        }

        /// <summary>
        /// 리소스 정리
        /// </summary>
        public void Dispose()
        {
            LoadedImage?.Dispose();
            LoadedImage = null;
        }

        /// <summary>
        /// 경로 찾기에 사용 가능한 노드인지 확인
        /// (라벨, 이미지 노드는 경로 찾기에서 제외)
        /// </summary>
        public bool IsNavigationNode()
        {
            return Type != NodeType.Label && Type != NodeType.Image && IsActive;
        }

        /// <summary>
        /// RFID가 할당되어 있는지 확인
        /// </summary>
        public bool HasRfid()
        {
            return !string.IsNullOrEmpty(RfidId);
        }

        /// <summary>
        /// RFID 정보 설정
        /// </summary>
        /// <param name="rfidId">RFID ID</param>
        /// <param name="rfidDescription">설치 위치 설명</param>
        /// <param name="rfidStatus">RFID 상태</param>
        public void SetRfidInfo(string rfidId, string rfidDescription = "", string rfidStatus = "정상")
        {
            RfidId = rfidId;
            RfidDescription = rfidDescription;
            RfidStatus = rfidStatus;
            ModifiedDate = DateTime.Now;
        }

        /// <summary>
        /// RFID 정보 삭제
        /// </summary>
        public void ClearRfidInfo()
        {
            RfidId = string.Empty;
            RfidDescription = string.Empty;
            RfidStatus = "정상";
            ModifiedDate = DateTime.Now;
        }

        /// <summary>
        /// RFID 기반 표시 텍스트 (RFID ID 우선, 없으면 노드ID)
        /// </summary>
        public string GetRfidDisplayText()
        {
            return HasRfid() ? RfidId : NodeId;
        }
    }
}