using System.Collections.Generic;
using System.Linq;

namespace StandardScene.Magnetic.Tasking
{
    /// <summary>
    /// 断线重连后，用当前占点匹配 tasklist 链路的结果。
    /// </summary>
    public sealed class Fass2ChainMatch
    {
        public int TaskId { get; set; }
        public int TaskPriority { get; set; }
        public int CurrentSiteId { get; set; }
        public int TargetSiteId { get; set; }
        public int IndexInPath { get; set; }
        public int DistanceToTarget { get; set; }
        public bool IsAtStartPoint { get; set; }
        public bool IsAtEndPoint { get; set; }
        public IReadOnlyList<int> FullPath { get; set; } = new List<int>();
        public IReadOnlyList<int> RemainingPath { get; set; } = new List<int>();

        public override string ToString()
        {
            var position = IsAtStartPoint ? "start" : (IsAtEndPoint ? "end" : "mid");
            return $"task={TaskId} {CurrentSiteId}->{TargetSiteId} pos={position} remain={DistanceToTarget} prio={TaskPriority}";
        }
    }

    /// <summary>
    /// 一站多链路时的固定裁决：原 goal 仍在剩余路径 → 起点 → 优先级 → 距目标更近。
    /// </summary>
    public static class Fass2ReconnectChainSelector
    {
        public static bool TrySelect(
            IReadOnlyList<Fass2ChainMatch> matches,
            int? preferGoalSiteId,
            out Fass2ChainMatch selected,
            out string reason)
        {
            selected = null;
            reason = "no chain";
            if (matches == null || matches.Count == 0)
            {
                return false;
            }

            var candidates = matches.Where(m => m != null && m.TargetSiteId > 0).ToList();
            if (candidates.Count == 0)
            {
                return false;
            }

            if (preferGoalSiteId != null && preferGoalSiteId.Value > 0)
            {
                var keepGoal = candidates
                    .Where(m => RemainingContains(m, preferGoalSiteId.Value))
                    .ToList();
                if (keepGoal.Count == 1)
                {
                    selected = keepGoal[0];
                    reason = $"preferGoal={preferGoalSiteId.Value}";
                    return true;
                }

                if (keepGoal.Count > 1)
                {
                    candidates = keepGoal;
                    reason = $"preferGoal={preferGoalSiteId.Value} narrowed={keepGoal.Count}";
                }
            }

            var ranked = candidates
                .OrderByDescending(m => m.IsAtStartPoint ? 1 : 0)
                .ThenByDescending(m => m.TaskPriority)
                .ThenBy(m => m.DistanceToTarget)
                .ThenBy(m => m.TaskId)
                .ToList();

            if (ranked.Count == 0)
            {
                return false;
            }

            var best = ranked[0];
            if (ranked.Count > 1)
            {
                var second = ranked[1];
                var tied = best.IsAtStartPoint == second.IsAtStartPoint &&
                           best.TaskPriority == second.TaskPriority &&
                           best.DistanceToTarget == second.DistanceToTarget;
                if (tied && best.TargetSiteId != second.TargetSiteId)
                {
                    reason = $"ambiguous {best} vs {second}";
                    return false;
                }
            }

            selected = best;
            if (string.IsNullOrEmpty(reason) || reason == "no chain")
            {
                reason = $"selected {best}";
            }
            else
            {
                reason = $"{reason}; selected {best}";
            }

            return true;
        }

        private static bool RemainingContains(Fass2ChainMatch match, int siteId)
        {
            if (match.RemainingPath != null)
            {
                for (var i = 0; i < match.RemainingPath.Count; i++)
                {
                    if (match.RemainingPath[i] == siteId)
                    {
                        return true;
                    }
                }
            }

            return match.TargetSiteId == siteId;
        }
    }
}
