using SimpleCore.Traffic;
using System;
using System.Collections.Generic;
using System.Linq;
using Simple3.RCS;
using Simple3.RCS.CarTypes;
using SimpleCore.Library;
using SimpleCore.PropType;
using SimpleCore;
using System.Threading;
using Simple3.CADTools;
using Simple3.Props;
using Simple3.UI;
using Simple3;
using StandardScene.Utils;
using Newtonsoft.Json;

namespace StandardScene.InterLock
{
	public class MyDictionary<TKey, TItem> where TItem : new()
	{
		private readonly Dictionary<TKey, TItem> dictionary = new();

		public TItem this[TKey key]
		{
			get
			{
				if (dictionary.TryGetValue(key, out var item)) return item;
				var newItem = new TItem();
				dictionary[key] = newItem;
				return newItem;
			}
			set => dictionary[key] = value;
		}

		public ICollection<TKey> Keys
		{
			get => dictionary.Keys;
		}
	}

	public class AbstractInterlockMission : Mission
	{
		public bool GetAskEnter(int siteId)
		{
			if (!SiteFilter(siteId)) return false;
			lock (sync) return askEnter[siteId];
		}

		public void SetAllowEnter(int siteId, bool value)
		{
			if (!SiteFilter(siteId)) return;
			lock (sync) allowEnter[siteId] = value;
		}

		public bool GetAskExit(int siteId)
		{
			if (!SiteFilter(siteId)) return false;
			lock (sync) return askExit[siteId];
		}

		public void SetAllowExit(int siteId, bool value)
		{
			if (!SiteFilter(siteId)) return;
			lock (sync) allowExit[siteId] = value;
		}

		public bool GetReportLeave(int siteId)
		{
			if (!SiteFilter(siteId)) return false;
			lock (sync) return reportLeave[siteId];
		}

		public void SetAcknowledgeLeave(int siteId, bool value)
		{
			if (!SiteFilter(siteId)) return;
			lock (sync) acknowledgeLeave[siteId] = value;
		}

		public int GetInSiteCarId(int siteId)
		{
			if (!SiteFilter(siteId)) return -1;
			lock (sync) return inSiteCarId[siteId];
		}

		// 请求进站（写）
		[JsonIgnore] private readonly MyDictionary<int, bool> askEnter = new();
		// 允许进站（读）
		[JsonIgnore] private readonly MyDictionary<int, bool> allowEnter = new();

		// 请求离站（写）
		[JsonIgnore] private readonly MyDictionary<int, bool> askExit = new();
		// 允许离站（读）
		[JsonIgnore] private readonly MyDictionary<int, bool> allowExit = new();

		// 报告离开（写）
		[JsonIgnore] private readonly MyDictionary<int, bool> reportLeave = new();
		// 确认离开（读）
		[JsonIgnore] private readonly MyDictionary<int, bool> acknowledgeLeave = new();

		// 站点上所在的小车（状态）
		[JsonIgnore] private readonly MyDictionary<int, int> inSiteCarId = new();

		[JsonIgnore] private object sync = new();

		public virtual string GetSiteDisplay(int siteId)
		{
			return $"{siteId}";
		}

		/// <summary>
		/// 返回为true的站点，是当前互锁机制关注的站点
		/// </summary>
		/// <param name="siteId"></param>
		/// <returns></returns>
		public virtual bool SiteFilter(int siteId)
		{
			return true;
		}

		/// <summary>
		/// 互锁站点进站条件
		/// </summary>
		/// <param name="car"></param>
		/// <param name="siteId"></param>
		/// <returns></returns>
		private bool EnterCondition(AbstractCar car, int siteId)
		{
			// todo: 是否考虑提前更多申请进入，加快节拍？
			if (car.status.pendingLocks.First() != siteId) return false;
			//DateTime startTime = DateTime.Now;
			//bool validTime = false;

            lock (sync)
			{
				// if (askEnter[siteId] == false)
				// { 
				// 	Diagnosis.Post($"{car.name}({car.id}) 申请进站 {GetSiteDisplay(siteId)}", "intertime", true);
    //                 //startTime = DateTime.Now; 
				// 	//validTime = true;
    //             }
                askEnter[siteId] = true;
				if (reportLeave[siteId])
				{
					Diagnosis.Post($"{car.name}({car.id})未被准许进站{GetSiteDisplay(siteId)}，前车离开信号未被确认", "interlock", true);
					return false;
				}

				if (allowEnter[siteId])
				{
					Diagnosis.Post($"{car.name}({car.id})准许进站{GetSiteDisplay(siteId)}", "interlock", true);
					// Diagnosis.Post($"{car.name}({car.id}) 准许进站 {GetSiteDisplay(siteId)}", "intertime", true);
                    lock (sync) askEnter[siteId] = false;
					return true;
				}
				Diagnosis.Post($"{car.name}({car.id})未被准许进站{GetSiteDisplay(siteId)}", "interlock", true);
				return false;
			}
		}
		
		/// <summary>
		/// 互锁站点离站条件
		/// </summary>
		/// <param name="car"></param>
		/// <param name="siteId"></param>
		/// <returns></returns>
		private bool ExitCondition(AbstractCar car, int siteId)
		{
			lock (sync)
			{
				askExit[siteId] = true;

				if (allowExit[siteId])
				{
					Diagnosis.Post($"{car.name}({car.id})准许离站{GetSiteDisplay(siteId)}", "interlock", true);
					askExit[siteId] = false;
					return true;
				}
				Diagnosis.Post($"{car.name}({car.id})未被准许离站{GetSiteDisplay(siteId)}", "interlock", true);
				return false;
			}
		}

		/// <summary>
		/// 告知对方设备小车离开，直到对方设备确认收到离开信号
		/// </summary>
		/// <param name="car"></param>
		/// <param name="siteId"></param>
		private void LeaveEvent(AbstractCar car, int siteId)
		{
			new Thread(() =>
			{
				while (true)
				{
					Thread.Sleep(100);
					lock (sync)
					{
						if (acknowledgeLeave[siteId]) // 已经确认小车离开
						{
							Diagnosis.Post($"{GetSiteDisplay(siteId)}确认{car.name}({car.id})离开", "interlock", true);
							break;
						}
					}
					Diagnosis.Post($"{car.name}({car.id})告知离开{GetSiteDisplay(siteId)}", "interlock", true);
					lock (sync) reportLeave[siteId] = true;
				}

				lock (sync) reportLeave[siteId] = false;
			}).Start();
		}

		[JsonIgnore] private bool enableSimulation = false;
		[JsonIgnore] public  bool started = false;
		[JsonIgnore] public Thread showT;

		[MethodMember(Name = "启动进程", Description = "处理安全互锁")]
		public override void Execute()
		{
			if (started) return;
			// started = true;
			status.status = "已启动";



            showT = new Thread(() =>
			{
				while (true)
				{
					Thread.Sleep(300);
					try
					{
						if (fields.TryGetValue("enableSimulation", out var userEnableSimulation))
							enableSimulation = bool.Parse(userEnableSimulation);
						foreach (var site in SimpleLib.GetAllSites().Where(ss => SiteFilter(ss.id)))
						{
							var carId = -1;
							foreach (var car in SimpleLib.GetAllCars())
							{
								lock (TrafficControl.syncTrafficSequence)
								{
									if (car.status.holdingLocks.Length == 1 && car.status.holdingLocks[0] == site.id)
									{
										carId = car.id;
										break;
									}
								}
							}

							lock (sync) inSiteCarId[site.id] = carId;
						}

						// if (!onDisplay) continue;
						var painter = SimpleMonitor.getPainter("DemoInterlockMission");
						painter.clear();
                        if (!onDisplay) continue;
                        //string str;
						//lock (sync)
						//{
						//	var keys = askEnter.Keys.Concat(askExit.Keys).Concat(reportLeave.Keys).ToHashSet()
						//		.OrderBy(kk => int.Parse(SimpleLib.GetSite(kk).fields["ASNub"])).ToList();
						//	str = $"站点\t\t请求进站\t允许进站\t请求离站\t允许离站\t上报离开\t确认离开\t小车id\n" +
						//	      $"{string.Join("\n", keys.Select(key => 
						//		      $"{GetSiteDisplay(key)}\t{askEnter[key]}\t\t{allowEnter[key]}\t\t" +
						//		      $"{askExit[key]}\t\t{allowExit[key]}\t\t" +
						//			  $"{reportLeave[key]}\t\t{acknowledgeLeave[key]}\t\t{inSiteCarId[key]}"))}";
						//}
						//painter.drawTextFixed(str, new SolidBrush(Color.Black), VirtualPainter.DrawPosition.RightTop, Color.AliceBlue);
					}
					catch (Exception ex)
					{
						Diagnosis.Post(ExceptionFormatter.FormatEx(ex), "interlock", true);
					}
				}
			}) { Name = "InterlockMission" };

			showT.Start();

           
        }

		[JsonIgnore] private bool onDisplay = true;

		[MethodMember(Name = "切换显示", Description = "是否在右下角显示")]
		public void SwitchAlwaysOnDisplay()
		{
			onDisplay = !onDisplay;
		}

		private async void SimButton(string title, MyDictionary<int, bool> toManipulate)
		{
			//if (!enableSimulation) return;
			G.pushStatus("请选择站点");
			var pt = await Startup.UI.getPoint(new UIOps.getPointOptions() { site = true });
			var site = SimpleLib.GetSite(pt.site);
			if (SiteFilter(site.id))
			{
				var vv = await Startup.UI.Input("请输入true/false", title, "true");
				if (vv == null || !bool.TryParse(vv, out var allow))
				{
					FairyUiHelper.Alert("错误", "输入错误");
					return;
				}
				lock (sync) toManipulate[site.id] = allow;
			}
		}

		[MethodMember(Name = "模拟准许进站")]
		public void SimAllowEnter()
		{
			SimButton("模拟准许进入状态", allowEnter);
		}

		[MethodMember(Name = "模拟准许离站")]
		public void SimAllowExit()
		{
			SimButton("模拟准许离站状态", allowExit);
		}

		[MethodMember(Name = "模拟确认离开")]
		public void SimLeaveNoted()
		{
			SimButton("模拟确认离开状态", acknowledgeLeave);
		}

        [MethodMember(Name = "模拟发送离开")]
        public async void SimReportLeave()
        {
            // if (!enableSimulation) return;
            G.pushStatus("请选择站点");
            var pt = await Startup.UI.getPoint(new UIOps.getPointOptions() { site = true });
            var site = SimpleLib.GetSite(pt.site);
            if (SiteFilter(site.id))
            {
                lock (sync) reportLeave[site.id] = true;
            }
            new Thread(() =>
            {
				var t1 = DateTime.Now;
                while (true)
                {
                    Thread.Sleep(100);
                    lock (sync)
                    {
						var deltaT = (DateTime.Now - t1).TotalSeconds;
                        if (acknowledgeLeave[site.id]||deltaT>5) // 已经确认小车离开
                        {
                            Diagnosis.Post($"{GetSiteDisplay(site.id)}  停止发送离开", "simlikai", true);
                            break;
                        }
                    }
                    Diagnosis.Post($"模拟告知离开{GetSiteDisplay(site.id)}", "simlikai", true);
                    lock (sync) reportLeave[site.id] = true;
                }

                lock (sync) reportLeave[site.id] = false;
            }).Start();
            // SimButton("模拟确认离开状态", reportLeave);
        }

        public AbstractInterlockMission()
		{
			Diagnosis.Post($"InterlockMechanism loaded", "interlock", true);
			TrafficControl.BeforeLock += (car, siteId) =>
			{
				if (SiteFilter(siteId)) // EnterCondition
					return EnterCondition(car, siteId);

                var site = SimpleLib.GetSite(siteId);
                if (site.fields.ContainsKey("PreAskEnterSite") && int.TryParse(site.fields["PreAskEnterSite"], out int PreAskEnterSiteId))
                {
                    var presite = SimpleLib.GetSite(PreAskEnterSiteId);
                    if (presite != null && SiteFilter(PreAskEnterSiteId))
                    {
                        Diagnosis.Post($"{car.name}({car.id})在{siteId}-{GetSiteDisplay(siteId)}，提前申请 {PreAskEnterSiteId} 的请求进入", "interlock", true);
                        askEnter[PreAskEnterSiteId] = true;
                    }

                }
                // ExitCondition
                lock (TrafficControl.syncTrafficSequence)
					if (!car.status.holdingLocks.Any(ss => SiteFilter(ss)))
						return true;

				
                var isNeighbor = false;
				var lockSiteId = -1;
				foreach (var trackId in site.relatedTracks)
				{
					var track = SimpleLib.GetTrack(trackId);
					if (SiteFilter(track.siteA))
					{
						isNeighbor = true;
						lockSiteId = track.siteA;
						break;
					}

					if (SiteFilter(track.siteB))
					{
						isNeighbor = true;
						lockSiteId = track.siteB;
						break;
					}
				}

				return !isNeighbor || ExitCondition(car, lockSiteId);
			};
			TrafficControl.AfterLeave += (car, siteId) =>
			{
				if (SiteFilter(siteId)) LeaveEvent(car, siteId);
			};
		}
	}
}
