using StandardScene.Magnetic.Tasking;
using System.Collections.Generic;
using Xunit;

namespace StandardScene.Magnetic.Tests.Tasking
{
    public class Fass2ReconnectChainSelectorTests
    {
        [Fact]
        public void PreferGoal_OnRemainingPath_Wins()
        {
            var matches = new List<Fass2ChainMatch>
            {
                Match(1, start: 6, target: 10, site: 8, index: 1, remain: new[] { 8, 9, 10 }, prio: 9),
                Match(2, start: 1, target: 5, site: 8, index: 3, remain: new[] { 8, 4, 5 }, prio: 1)
            };

            var ok = Fass2ReconnectChainSelector.TrySelect(matches, preferGoalSiteId: 5, out var selected, out var reason);

            Assert.True(ok);
            Assert.Equal(5, selected.TargetSiteId);
            Assert.Contains("preferGoal=5", reason);
        }

        [Fact]
        public void StartPoint_Beats_Priority_WhenGoalNotOnPath()
        {
            var matches = new List<Fass2ChainMatch>
            {
                Match(1, start: 8, target: 12, site: 8, index: 0, remain: new[] { 8, 12 }, prio: 1, atStart: true),
                Match(2, start: 6, target: 10, site: 8, index: 1, remain: new[] { 8, 9, 10 }, prio: 9)
            };

            var ok = Fass2ReconnectChainSelector.TrySelect(matches, preferGoalSiteId: 99, out var selected, out _);

            Assert.True(ok);
            Assert.Equal(12, selected.TargetSiteId);
            Assert.True(selected.IsAtStartPoint);
        }

        [Fact]
        public void Ambiguous_DifferentTargets_SameScore_Fails()
        {
            var matches = new List<Fass2ChainMatch>
            {
                Match(1, start: 1, target: 5, site: 3, index: 1, remain: new[] { 3, 4, 5 }, prio: 1),
                Match(2, start: 9, target: 7, site: 3, index: 1, remain: new[] { 3, 6, 7 }, prio: 1)
            };

            var ok = Fass2ReconnectChainSelector.TrySelect(matches, preferGoalSiteId: null, out var selected, out var reason);

            Assert.False(ok);
            Assert.Null(selected);
            Assert.Contains("ambiguous", reason);
        }

        [Fact]
        public void Empty_Fails()
        {
            var ok = Fass2ReconnectChainSelector.TrySelect(new List<Fass2ChainMatch>(), null, out _, out var reason);
            Assert.False(ok);
            Assert.Equal("no chain", reason);
        }

        private static Fass2ChainMatch Match(
            int taskId, int start, int target, int site, int index, int[] remain, int prio, bool atStart = false)
        {
            return new Fass2ChainMatch
            {
                TaskId = taskId,
                TaskPriority = prio,
                CurrentSiteId = site,
                TargetSiteId = target,
                IndexInPath = index,
                DistanceToTarget = remain.Length > 0 ? remain.Length - 1 : 0,
                IsAtStartPoint = atStart || index == 0,
                IsAtEndPoint = remain.Length <= 1,
                RemainingPath = remain,
                FullPath = remain
            };
        }
    }
}
