using System;
using System.Collections.Generic;

namespace StandardScene.Fass2Simulator
{
    /// <summary>
    /// 到站动作闭环：0xB1 登记期望 → 0xA1 或定时器补全字段 → 供调度 AtStation 判定完成。
    /// </summary>
    public sealed class Fass2SimActionEngine
    {
        private readonly Fass2SimVehicle _vehicle;
        private readonly Fass2SimConfig _config;
        private readonly Fass2SimNodeProfileStore _profiles;
        private readonly object _syncRoot = new object();
        private readonly List<PendingAction> _pendingActions = new List<PendingAction>();

        private Fass2SimNodeMessage _expectedStation;

        public Fass2SimActionEngine(Fass2SimVehicle vehicle, Fass2SimConfig config, Fass2SimNodeProfileStore profiles)
        {
            _vehicle = vehicle;
            _config = config;
            _profiles = profiles ?? new Fass2SimNodeProfileStore();
        }

        public event Action StationActionsCompleted;

        public void OnStationArrival(Fass2SimNodeMessage station)
        {
            if (station == null)
            {
                return;
            }

            lock (_syncRoot)
            {
                _pendingActions.Clear();
                _expectedStation = Clone(station);

                ApplyArrivalFields(station);
                _vehicle.State = 2;

                var pending = Fass2SimActionResolver.DescribePending(_expectedStation, _vehicle.CopySnapshotUnsafe());
                if (string.IsNullOrEmpty(pending))
                {
                    Fass2SimLog.WriteLine($"[{Now()}]    -> 站点 node={station.Node} 无待执行动作");
                    NotifyStationCompleteIfReady();
                    return;
                }

                Fass2SimLog.WriteLine($"[{Now()}]    -> 站点 node={station.Node} 待动作: {pending}");

                if (_config.AutoCompleteStationActions)
                {
                    SchedulePatch(Clone(station), 0, 0, ResolveActionDelayMs(station.Node));
                    Fass2SimLog.WriteLine($"[{Now()}]    -> AutoComplete 已排队，delay={ResolveActionDelayMs(station.Node)}ms");
                }
            }
        }

        public void ResetForNewTask()
        {
            lock (_syncRoot)
            {
                _pendingActions.Clear();
                _expectedStation = null;
            }
        }

        public void OnActionCommand(ulong actionId, Fass2SimNodeMessage patch)
        {
            if (patch == null)
            {
                return;
            }

            lock (_syncRoot)
            {
                var targetNode = patch.Node != 0 ? patch.Node : _vehicle.Node;
                if (patch.Node != 0 && patch.Node != _vehicle.Node)
                {
                    Fass2SimLog.WriteLine(
                        $"[{Now()}]    -> 0xA1 忽略: patch node={patch.Node}, current={_vehicle.Node}");
                    return;
                }

                var delay = ResolveActionDelayMs(targetNode);
                MergeExpectedLocked(patch);
                SchedulePatch(patch, actionId, 0, delay);
                Fass2SimLog.WriteLine(
                    $"[{Now()}]    -> 0xA1 actionId={actionId} 已排队，delay={delay}ms, pending={DescribePatch(patch)}");
            }
        }

        public void Tick(int deltaMs)
        {
            if (deltaMs <= 0)
            {
                return;
            }

            List<PendingAction> due = null;
            lock (_syncRoot)
            {
                for (var i = _pendingActions.Count - 1; i >= 0; i--)
                {
                    _pendingActions[i].RemainingMs -= deltaMs;
                    if (_pendingActions[i].RemainingMs <= 0)
                    {
                        due ??= new List<PendingAction>();
                        due.Add(_pendingActions[i]);
                        _pendingActions.RemoveAt(i);
                    }
                }
            }

            if (due == null)
            {
                return;
            }

            foreach (var action in due)
            {
                lock (_syncRoot)
                {
                    ApplyPatch(action.Patch);
                    if (action.ActionId > 0)
                    {
                        Fass2SimLog.WriteLine(
                            $"[{Now()}]    -> 动作完成 actionId={action.ActionId}, node={_vehicle.Node}, fields={DescribePatch(action.Patch)}");
                    }
                    else
                    {
                        Fass2SimLog.WriteLine(
                            $"[{Now()}]    -> 自动动作完成 node={_vehicle.Node}, fields={DescribePatch(action.Patch)}");
                    }

                    var pending = Fass2SimActionResolver.DescribePending(_expectedStation, _vehicle.CopySnapshotUnsafe());
                    if (!string.IsNullOrEmpty(pending))
                    {
                        Fass2SimLog.WriteLine($"[{Now()}]    -> 仍有待动作: {pending}");
                    }

                    NotifyStationCompleteIfReady();
                }
            }
        }

        public bool IsStationComplete()
        {
            lock (_syncRoot)
            {
                return IsStationCompleteLocked();
            }
        }

        public bool CanLeaveStation()
        {
            lock (_syncRoot)
            {
                return IsStationCompleteLocked();
            }
        }

        public Fass2SimNodeMessage ExpectedStation
        {
            get
            {
                lock (_syncRoot)
                {
                    return _expectedStation;
                }
            }
        }

        public void MergeExpected(Fass2SimNodeMessage patch)
        {
            if (patch == null)
            {
                return;
            }

            lock (_syncRoot)
            {
                MergeExpectedLocked(patch);
            }
        }

        private void MergeExpectedLocked(Fass2SimNodeMessage patch)
        {
            if (_expectedStation == null)
            {
                return;
            }

            if (patch.Node != 0 && patch.Node != _expectedStation.Node)
            {
                return;
            }

            if (patch.StartStop > 0)
            {
                _expectedStation.StartStop = patch.StartStop;
            }
        }

        private bool IsStationCompleteLocked()
        {
            if (_pendingActions.Count > 0)
            {
                return false;
            }

            if (_expectedStation == null)
            {
                return true;
            }

            return Fass2SimActionResolver.IsStationActionComplete(
                _expectedStation,
                _vehicle.CopySnapshotUnsafe(),
                _vehicle.State);
        }

        private void NotifyStationCompleteIfReady()
        {
            if (!IsStationCompleteLocked())
            {
                return;
            }

            if (_expectedStation != null)
            {
                Fass2SimLog.WriteLine($"[{Now()}]    -> 站点 node={_expectedStation.Node} 动作已全部完成");
            }

            StationActionsCompleted?.Invoke();
        }

        private void ApplyArrivalFields(Fass2SimNodeMessage station)
        {
            if (station.StartStop > 0)
            {
                _vehicle.StartStop = station.StartStop;
            }

            if (station.Orientation > 0)
            {
                _vehicle.Orientation = station.Orientation;
            }

            if (station.Direction > 0)
            {
                _vehicle.Direction = station.Direction;
            }

            if (station.Byroad > 0)
            {
                _vehicle.Byroad = station.Byroad;
            }
        }

        private void SchedulePatch(Fass2SimNodeMessage patch, ulong actionId, int source, int delayMs)
        {
            _pendingActions.Add(new PendingAction
            {
                Patch = Clone(patch),
                ActionId = actionId,
                RemainingMs = Math.Max(0, delayMs)
            });
        }

        private void ApplyPatch(Fass2SimNodeMessage patch)
        {
            if (patch.Node != 0 && patch.Node != _vehicle.Node)
            {
                return;
            }

            if (patch.StartStop > 0)
            {
                _vehicle.StartStop = patch.StartStop;
            }
            if (patch.Speed > 0)
            {
                _vehicle.Speed = patch.Speed;
            }
            if (patch.Direction > 0)
            {
                _vehicle.Direction = patch.Direction;
            }
            if (patch.Orientation > 0)
            {
                _vehicle.Orientation = patch.Orientation;
            }
            if (patch.Byroad > 0)
            {
                _vehicle.Byroad = patch.Byroad;
            }
            if (patch.Obstacle > 0)
            {
                _vehicle.Obstacle = patch.Obstacle;
            }
            if (patch.Audio > 0)
            {
                _vehicle.Audio = patch.Audio;
            }
            if (patch.Light > 0)
            {
                _vehicle.Light = patch.Light;
            }
            if (patch.Charge > 0)
            {
                _vehicle.Charge = patch.Charge;
            }
            if (patch.Rest > 0)
            {
                _vehicle.Rest = patch.Rest;
            }
            if (patch.Lift > 0)
            {
                _vehicle.Lift = patch.Lift;
            }
            if (patch.Clamp > 0)
            {
                _vehicle.Clamp = patch.Clamp;
            }
            if (patch.Tray > 0)
            {
                _vehicle.Tray = patch.Tray;
            }
            if (patch.Roll > 0)
            {
                _vehicle.Roll = patch.Roll;
            }
            if (patch.Shutdown > 0)
            {
                _vehicle.Shutdown = patch.Shutdown;
            }
        }

        private int ResolveActionDelayMs(ushort nodeId)
        {
            return _profiles.ResolveActionDelayMs(nodeId, _config.ActionDelayMs);
        }

        private static Fass2SimNodeMessage Clone(Fass2SimNodeMessage source)
        {
            return new Fass2SimNodeMessage
            {
                Node = source.Node,
                Distance = source.Distance,
                StartStop = source.StartStop,
                Direction = source.Direction,
                Orientation = source.Orientation,
                Byroad = source.Byroad,
                Speed = source.Speed,
                Obstacle = source.Obstacle,
                Audio = source.Audio,
                Light = source.Light,
                Charge = source.Charge,
                Rest = source.Rest,
                Lift = source.Lift,
                Clamp = source.Clamp,
                Tray = source.Tray,
                Roll = source.Roll,
                Shutdown = source.Shutdown
            };
        }

        private static string DescribePatch(Fass2SimNodeMessage patch)
        {
            var parts = new List<string>();
            if (patch.StartStop > 0) parts.Add($"StartStop={patch.StartStop}");
            if (patch.Lift > 0) parts.Add($"Lift={patch.Lift}");
            if (patch.Charge > 0) parts.Add($"Charge={patch.Charge}");
            if (patch.Roll > 0) parts.Add($"Roll={patch.Roll}");
            if (patch.Speed > 0) parts.Add($"Speed={patch.Speed}");
            return parts.Count == 0 ? "(empty)" : string.Join(",", parts);
        }

        private static string Now()
        {
            return DateTime.Now.ToString("HH:mm:ss.fff");
        }

        private sealed class PendingAction
        {
            public Fass2SimNodeMessage Patch { get; set; }
            public ulong ActionId { get; set; }
            public int RemainingMs { get; set; }
        }
    }
}
