using System;
using System.Collections.Generic;

namespace StandardScene.Fass2Simulator
{
    /// <summary>
    /// 对齐 <c>Fass2ActionResolver</c> 的到站动作判定（独立副本，避免引用 Magnetic）。
    /// </summary>
    public static class Fass2SimActionResolver
    {
        public const byte StartStopPass = 1;
        public const byte StartStopStop = 2;
        public const byte StartStopControlStart = 11;
        public const byte StartStopControlStop = 12;
        public const byte StartStopPrecision = 22;

        public static bool VerifyTrajectoryFields { get; set; }

        private static readonly (string Name, Func<Fass2SimNodeMessage, byte> Get)[] MechanismFields =
        {
            ("Obstacle", n => n.Obstacle),
            ("Audio", n => n.Audio),
            ("Light", n => n.Light),
            ("Charge", n => n.Charge),
            ("Rest", n => n.Rest),
            ("Lift", n => n.Lift),
            ("Clamp", n => n.Clamp),
            ("Tray", n => n.Tray),
            ("Roll", n => n.Roll),
            ("Shutdown", n => n.Shutdown)
        };

        private static readonly (string Name, Func<Fass2SimNodeMessage, byte> Get)[] TrajectoryFields =
        {
            ("Direction", n => n.Direction),
            ("Orientation", n => n.Orientation),
            ("Byroad", n => n.Byroad)
        };

        public static bool AllowsAutoContinue(byte startStop)
        {
            return startStop == StartStopPass || startStop == StartStopControlStart;
        }

        public static bool RequiresActionWait(Fass2SimNodeMessage expected)
        {
            if (expected == null)
            {
                return false;
            }

            if (expected.StartStop is StartStopStop or StartStopPrecision or StartStopControlStop or StartStopControlStart)
            {
                return true;
            }

            foreach (var field in MechanismFields)
            {
                if (field.Get(expected) != 0)
                {
                    return true;
                }
            }

            if (!VerifyTrajectoryFields)
            {
                return false;
            }

            foreach (var field in TrajectoryFields)
            {
                if (field.Get(expected) != 0)
                {
                    return true;
                }
            }

            return expected.Speed != 0;
        }

        public static bool IsStationActionComplete(Fass2SimNodeMessage expected, Fass2SimVehicleSnapshot actual, byte vehicleState)
        {
            if (expected == null || actual == null)
            {
                return false;
            }

            if (actual.Node != expected.Node)
            {
                return false;
            }

            if (vehicleState is 1 or 5)
            {
                return false;
            }

            if (!RequiresActionWait(expected))
            {
                return true;
            }

            if (expected.StartStop == StartStopPass)
            {
                return true;
            }

            if (expected.StartStop == StartStopControlStop)
            {
                return false;
            }

            return ListPendingFields(expected, actual).Count == 0;
        }

        public static List<string> ListPendingFields(Fass2SimNodeMessage expected, Fass2SimVehicleSnapshot actual)
        {
            var pending = new List<string>();
            if (expected == null || actual == null)
            {
                return pending;
            }

            if (expected.StartStop != 0 && actual.StartStop != expected.StartStop)
            {
                pending.Add("StartStop");
            }

            if (VerifyTrajectoryFields)
            {
                if (expected.Speed != 0 && actual.Speed != expected.Speed)
                {
                    pending.Add("Speed");
                }

                foreach (var field in TrajectoryFields)
                {
                    var expectedValue = field.Get(expected);
                    if (expectedValue != 0 && GetActualField(actual, field.Name) != expectedValue)
                    {
                        pending.Add(field.Name);
                    }
                }
            }

            foreach (var field in MechanismFields)
            {
                var expectedValue = field.Get(expected);
                if (expectedValue != 0 && GetActualField(actual, field.Name) != expectedValue)
                {
                    pending.Add(field.Name);
                }
            }

            return pending;
        }

        public static string DescribePending(Fass2SimNodeMessage expected, Fass2SimVehicleSnapshot actual)
        {
            var pending = ListPendingFields(expected, actual);
            return pending.Count == 0 ? string.Empty : string.Join(",", pending);
        }

        private static byte GetActualField(Fass2SimVehicleSnapshot actual, string name)
        {
            switch (name)
            {
                case "Direction": return actual.Direction;
                case "Orientation": return actual.Orientation;
                case "Byroad": return actual.Byroad;
                case "Obstacle": return actual.Obstacle;
                case "Audio": return actual.Audio;
                case "Light": return actual.Light;
                case "Charge": return actual.Charge;
                case "Rest": return actual.Rest;
                case "Lift": return actual.Lift;
                case "Clamp": return actual.Clamp;
                case "Tray": return actual.Tray;
                case "Roll": return actual.Roll;
                case "Shutdown": return actual.Shutdown;
                default: return 0;
            }
        }
    }
}
