using SimpleCore.PropType;
using StandardScene.Magnetic.Protocol;
using System;
using System.Collections.Generic;

namespace StandardScene.Magnetic.Tasking
{
    public enum Fass2TaskPhase
    {
        Idle,
        Planning,
        Dispatching,
        Moving,
        AtStation,
        SegmentDone,
        Complete,
        Fault,
        Cancelled
    }

    /// <summary>
    /// 一次 FASS 2.0 任务执行上下文，供状态机推进与重启恢复使用。
    /// </summary>
    public sealed class Fass2TaskContext
    {
        public Fass2TaskPhase Phase { get; set; } = Fass2TaskPhase.Idle;
        public int StartSiteId { get; set; }
        public int GoalSiteId { get; set; }
        public int CurrentIndex { get; set; }
        public ulong TaskId { get; set; }
        public Fass2TaskPlan Plan { get; set; }
        public string FieldsSignature { get; set; } = string.Empty;
        public double DefaultSpeed { get; set; } = -1;
        public string FaultReason { get; set; }
        public DateTime StartedAt { get; set; }
        public DateTime LastDispatchAt { get; set; } = DateTime.MinValue;
        public ulong LastActionId { get; set; }
        public DateTime LastActionSentAt { get; set; } = DateTime.MinValue;

        /// <summary>交管窗口未齐、正在等锁；此期间不消耗移动超时预算。</summary>
        public bool WaitingForTraffic { get; set; }

        /// <summary>停在管控停止点等待按车放行；此期间不消耗移动超时预算。</summary>
        public bool WaitingForRelease { get; set; }

        /// <summary>本任务已对哪个路径下标发过放行报文；-1 表示尚未放行。</summary>
        public int ControlReleasedIndex { get; set; } = -1;

        /// <summary>最近一次规划的站点链路，供断线重连判断是否仍在原路径上。</summary>
        public int[] RouteSiteIds { get; set; } = Array.Empty<int>();
    }

    public static class Fass2TaskPersistence
    {
        public const string TagPhase = "Fass2Task_Phase";
        public const string TagStartSite = "Fass2Task_StartSite";
        public const string TagGoalSite = "Fass2Task_GoalSite";
        public const string TagCurrentIndex = "Fass2Task_CurrentIndex";
        public const string TagTaskId = "Fass2Task_TaskId";
        public const string TagFieldsSignature = "Fass2Task_FieldsSig";
        public const string TagDefaultSpeed = "Fass2Task_DefaultSpeed";
        public const string TagRouteSites = "Fass2Task_RouteSites";

        public static void Save(TagSet tags, Fass2TaskContext context)
        {
            if (tags == null || context == null)
            {
                return;
            }

            SetTag(tags, TagPhase, context.Phase.ToString());
            SetTag(tags, TagStartSite, context.StartSiteId.ToString());
            SetTag(tags, TagGoalSite, context.GoalSiteId.ToString());
            SetTag(tags, TagCurrentIndex, context.CurrentIndex.ToString());
            SetTag(tags, TagTaskId, context.TaskId.ToString());
            SetTag(tags, TagFieldsSignature, context.FieldsSignature ?? string.Empty);
            SetTag(tags, TagDefaultSpeed, context.DefaultSpeed.ToString(System.Globalization.CultureInfo.InvariantCulture));
            SetTag(tags, TagRouteSites, FormatIntList(context.RouteSiteIds));
        }

        public static bool TryLoad(TagSet tags, out Fass2TaskContext context)
        {
            context = null;
            if (tags == null || !tags.TryGetValue(TagPhase, out var phaseText) ||
                !Enum.TryParse(phaseText, out Fass2TaskPhase phase))
            {
                return false;
            }

            if (phase is Fass2TaskPhase.Idle or Fass2TaskPhase.Complete or Fass2TaskPhase.Cancelled)
            {
                return false;
            }

            if (!TryReadInt(tags, TagStartSite, out var startSite) ||
                !TryReadInt(tags, TagGoalSite, out var goalSite) ||
                !TryReadInt(tags, TagCurrentIndex, out var currentIndex))
            {
                return false;
            }

            tags.TryGetValue(TagFieldsSignature, out var fieldsSignature);
            ulong.TryParse(tags.TryGetValue(TagTaskId, out var taskIdText) ? taskIdText : "0", out var taskId);
            double.TryParse(
                tags.TryGetValue(TagDefaultSpeed, out var speedText) ? speedText : "-1",
                System.Globalization.NumberStyles.Float,
                System.Globalization.CultureInfo.InvariantCulture,
                out var defaultSpeed);

            tags.TryGetValue(TagRouteSites, out var routeSitesText);
            context = new Fass2TaskContext
            {
                Phase = phase,
                StartSiteId = startSite,
                GoalSiteId = goalSite,
                CurrentIndex = currentIndex,
                TaskId = taskId,
                FieldsSignature = fieldsSignature ?? string.Empty,
                DefaultSpeed = defaultSpeed,
                RouteSiteIds = ParseIntList(routeSitesText)
            };
            return true;
        }

        public static void Clear(TagSet tags)
        {
            if (tags == null)
            {
                return;
            }

            RemoveTag(tags, TagPhase);
            RemoveTag(tags, TagStartSite);
            RemoveTag(tags, TagGoalSite);
            RemoveTag(tags, TagCurrentIndex);
            RemoveTag(tags, TagTaskId);
            RemoveTag(tags, TagFieldsSignature);
            RemoveTag(tags, TagDefaultSpeed);
            RemoveTag(tags, TagRouteSites);
        }

        private static void SetTag(TagSet tags, string key, string value)
        {
            if (tags.Contains(key))
            {
                tags.Remove(key);
            }

            tags.Add(key, value);
        }

        private static void RemoveTag(TagSet tags, string key)
        {
            if (tags.Contains(key))
            {
                tags.Remove(key);
            }
        }

        private static bool TryReadInt(TagSet tags, string key, out int value)
        {
            value = 0;
            return tags.TryGetValue(key, out var text) && int.TryParse(text, out value);
        }

        private static string FormatIntList(int[] values)
        {
            return values == null || values.Length == 0 ? string.Empty : string.Join(",", values);
        }

        private static int[] ParseIntList(string text)
        {
            if (string.IsNullOrWhiteSpace(text))
            {
                return Array.Empty<int>();
            }

            var parts = text.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
            var ids = new List<int>(parts.Length);
            foreach (var part in parts)
            {
                if (int.TryParse(part.Trim(), out var id) && id > 0)
                {
                    ids.Add(id);
                }
            }

            return ids.ToArray();
        }
    }
}
