using System;
using System.Collections.Generic;
using System.Linq;
using AGVNavigationCore.Models;
using AGVNavigationCore.PathFinding.Planning;
using AGVNavigationCore.PathFinding.Validation;

namespace AGVNavigationCore.PathFinding.Core
{
    /// <summary>
    /// AGV 경로 계산 결과 (방향성 및 명령어 포함)
    /// </summary>
    public class AGVPathResult
    {
        /// <summary>
        /// 경로 찾기 성공 여부
        /// </summary>
        public bool Success { get; set; }

        /// <summary>
        /// 경로 노드 목록 (시작 → 목적지 순서)
        /// </summary>
        public List<MapNode> Path { get; set; }

        /// <summary>
        /// AGV 명령어 목록 (이동 방향 시퀀스)
        /// </summary>
        public List<AgvDirection> Commands { get; set; }

        /// <summary>
        /// 총 거리
        /// </summary>
        public float TotalDistance { get; set; }

        /// <summary>
        /// 계산 소요 시간 (밀리초)
        /// </summary>
        public long CalculationTimeMs { get; set; }

        /// <summary>
        /// 탐색된 노드 수
        /// </summary>
        public int ExploredNodeCount { get; set; }

        /// <summary>
        /// 탐색된 노드 수 (호환성용)
        /// </summary>
        public int ExploredNodes
        {
            get => ExploredNodeCount;
            set => ExploredNodeCount = value;
        }

        /// <summary>
        /// 예상 소요 시간 (초)
        /// </summary>
        public float EstimatedTimeSeconds { get; set; }

        /// <summary>
        /// 회전 횟수
        /// </summary>
        public int RotationCount { get; set; }

        /// <summary>
        /// 오류 메시지 (실패시)
        /// </summary>
        public string Message { get; set; }

        /// <summary>
        /// 도킹 검증 결과
        /// </summary>
        public DockingValidationResult DockingValidation { get; set; }

        /// <summary>
        /// 상세 경로 정보 (NodeMotorInfo 목록)
        /// </summary>
        public List<NodeMotorInfo> DetailedPath { get; set; }

        /// <summary>
        /// 계획 설명
        /// </summary>
        public string PlanDescription { get; set; }

        /// <summary>
        /// 방향 전환 필요 여부
        /// </summary>
        public bool RequiredDirectionChange { get; set; }

        /// <summary>
        /// 방향 전환 노드 ID
        /// </summary>
        public string DirectionChangeNode { get; set; }

        /// <summary>
        /// 경로계산시 사용했던 최초 이전 포인트 이전의 노드
        /// </summary>
        public MapNode PrevNode { get; set; }


        /// <summary>
        /// PrevNode 에서 현재위치까지 이동한 모터의 방향값
        /// </summary>
        public AgvDirection PrevDirection { get; set; }

        public MapNode Gateway { get; set; }

        /// <summary>
        /// 기본 생성자
        /// </summary>
        public AGVPathResult()
        {
            Success = false;
            Path = new List<MapNode>();
            Commands = new List<AgvDirection>();
            DetailedPath = new List<NodeMotorInfo>();
            TotalDistance = 0;
            CalculationTimeMs = 0;
            ExploredNodes = 0;
            EstimatedTimeSeconds = 0;
            RotationCount = 0;
            Message = string.Empty;
            PlanDescription = string.Empty;
            RequiredDirectionChange = false;
            DirectionChangeNode = string.Empty;
            DockingValidation = DockingValidationResult.CreateNotRequired();
            PrevNode = null;
            PrevDirection = AgvDirection.Stop;
        }

        /// <summary>
        /// 성공 결과 생성
        /// </summary>
        /// <param name="path">경로</param>
        /// <param name="commands">AGV 명령어 목록</param>
        /// <param name="totalDistance">총 거리</param>
        /// <param name="calculationTimeMs">계산 시간</param>
        /// <returns>성공 결과</returns>
        public static AGVPathResult CreateSuccess(List<MapNode> path, List<AgvDirection> commands, float totalDistance, long calculationTimeMs)
        {
            var result = new AGVPathResult
            {
                Success = true,
                Path = new List<MapNode>(path),
                Commands = new List<AgvDirection>(commands),
                TotalDistance = totalDistance,
                CalculationTimeMs = calculationTimeMs
            };

            result.CalculateMetrics();
            return result;
        }


        /// <summary>
        /// 실패 결과 생성
        /// </summary>
        /// <param name="errorMessage">오류 메시지</param>
        /// <param name="calculationTimeMs">계산 시간</param>
        /// <param name="exploredNodes">탐색된 노드 수</param>
        /// <returns>실패 결과</returns>
        public static AGVPathResult CreateFailure(string errorMessage, long calculationTimeMs = 0, int exploredNodes = 0)
        {
            return new AGVPathResult
            {
                Success = false,
                Message = errorMessage,
                CalculationTimeMs = calculationTimeMs,
                ExploredNodes = exploredNodes
            };
        }


        /// <summary>
        /// 경로 메트릭 계산
        /// </summary>
        private void CalculateMetrics()
        {
            RotationCount = CountRotations();
            EstimatedTimeSeconds = CalculateEstimatedTime();
        }

        /// <summary>
        /// 회전 횟수 계산
        /// </summary>
        private int CountRotations()
        {
            int count = 0;
            foreach (var command in Commands)
            {
                if (command == AgvDirection.Left || command == AgvDirection.Right)
                {
                    count++;
                }
            }
            return count;
        }

        /// <summary>
        /// 예상 소요 시간 계산
        /// </summary>
        /// <param name="agvSpeed">AGV 속도 (픽셀/초, 기본값: 100)</param>
        /// <param name="rotationTime">회전 시간 (초, 기본값: 3)</param>
        /// <returns>예상 소요 시간 (초)</returns>
        private float CalculateEstimatedTime(float agvSpeed = 100.0f, float rotationTime = 3.0f)
        {
            float moveTime = TotalDistance / agvSpeed;
            float totalRotationTime = RotationCount * rotationTime;
            return moveTime + totalRotationTime;
        }

        /// <summary>
        /// 명령어 요약 생성
        /// </summary>
        /// <returns>명령어 요약 문자열</returns>
        public string GetCommandSummary()
        {
            if (!Success) return "실패";

            var summary = new List<string>();
            var currentCommand = AgvDirection.Stop;
            var count = 0;

            foreach (var command in Commands)
            {
                if (command == currentCommand)
                {
                    count++;
                }
                else
                {
                    if (count > 0)
                    {
                        summary.Add($"{GetCommandText(currentCommand)}×{count}");
                    }
                    currentCommand = command;
                    count = 1;
                }
            }

            if (count > 0)
            {
                summary.Add($"{GetCommandText(currentCommand)}×{count}");
            }

            return string.Join(" → ", summary);
        }

        /// <summary>
        /// 명령어 텍스트 반환
        /// </summary>
        private string GetCommandText(AgvDirection command)
        {
            switch (command)
            {
                case AgvDirection.Forward: return "전진";
                case AgvDirection.Backward: return "후진";
                case AgvDirection.Left: return "좌회전";
                case AgvDirection.Right: return "우회전";
                case AgvDirection.Stop: return "정지";
                default: return command.ToString();
            }
        }

        /// <summary>
        /// 경로의 노드 정보를 포함
        /// </summary>
        /// <returns></returns>
        public string GetDetailedPathInfo(bool shortmessage = false)
        {
            if (!Success)
            {
                return $"경로 계산 실패: {Message} (계산시간: {CalculationTimeMs}ms)";
            }

            var data = DetailedPath.Select(t =>
            {
                if (shortmessage)
                    return $"{t.RfidId:00}{t.MotorDirection.ToString().Substring(0, 1)}{t.MagnetDirection.ToString().Substring(0, 1)}";
                else
                    return $"{t.RfidId}[{t.NodeId}] {t.MotorDirection.ToString().Substring(0, 1)}-{t.MagnetDirection.ToString().Substring(0, 1)}";
            });
            return string.Join(" → ", data);
        }


        /// <summary>
        /// 단순 경로 목록 반환 (호환성용 - 노드 ID 문자열 목록)
        /// </summary>
        /// <returns>노드 ID 목록</returns>
        public List<string> GetSimplePath()
        {
            if (DetailedPath != null && DetailedPath.Count > 0)
            {
                return DetailedPath.Select(n => n.NodeId).ToList();
            }
            return Path?.Select(n => n.Id).ToList() ?? new List<string>();
        }

        /// <summary>
        /// 문자열 표현
        /// </summary>
        public override string ToString()
        {
            if (Success)
            {
                return $"Success: {Path.Count} nodes, {TotalDistance:F1}px, {RotationCount} rotations, {EstimatedTimeSeconds:F1}s";
            }
            else
            {
                return $"Failed: {Message}";
            }
        }
    }
}