using System;
using SimpleCore.Library;
using StandardScene.Signal.Model;

namespace StandardScene.Signal.Plc
{
    /// <summary>
    /// 单个机构的运行态（不进 JSON）。扫车线程改写目标写字节，PLC Worker 负责真正下发。
    /// </summary>
    /// <remarks>
    /// 赋值 <see cref="WriteSignal"/> 会把 <see cref="WriteSuccess"/> 置 false，下一拍 Worker 发现
    /// 目标与回读不一致就会重写 PLC。回读与目标一致后再标成功，AutoLeave 才继续往下一状态走。
    /// 所有读写应在 <see cref="Sync"/> 内进行。
    /// </remarks>
    public sealed class PlcStationRuntime
    {
        private SignalWriteValue _writeSignal;
        private SignalReadValue _readSignal;
        private SignalWriteValue _readWriteSignal;

        public PlcStationRuntime(PlcStationModel config)
        {
            Config = config ?? throw new ArgumentNullException(nameof(config));
        }

        /// <summary>本机构静态配置（IP、DB 地址、地标、机构类型）。</summary>
        public PlcStationModel Config { get; }

        /// <summary>扫车线程与 PLC Worker 共用运行态，写入时加此锁。</summary>
        public object Sync { get; } = new object();

        /// <summary>PLC→调度：允许进入 / 允许离开 / 无状态。变化时打诊断。</summary>
        public SignalReadValue ReadSignal
        {
            get => _readSignal;
            set
            {
                if (_readSignal != value)
                    Diagnosis.Log($"{Config.JgName} 读信号 {_readSignal} → {value}", "PLC", true);
                _readSignal = value;
            }
        }

        /// <summary>
        /// 调度→PLC 的目标写字节。赋值即视为尚未写成功，驱动 Worker 重写。
        /// </summary>
        public SignalWriteValue WriteSignal
        {
            get => _writeSignal;
            set
            {
                if (_writeSignal != value)
                    Diagnosis.Log($"{Config.JgName} 写信号 {_writeSignal} → {value}", "PLC", true);
                _writeSignal = value;
                WriteSuccess = false;
            }
        }

        /// <summary>从写地址回读到的当前值，用来确认 PLC 是否已吃进目标字节。</summary>
        public SignalWriteValue ReadWriteSignal
        {
            get => _readWriteSignal;
            set
            {
                if (_readWriteSignal != value)
                    Diagnosis.Log($"{Config.JgName} 回读写值 {_readWriteSignal} → {value}", "PLC", true);
                _readWriteSignal = value;
            }
        }

        /// <summary>已报到在机构内的 AGV 号；0 表示没有。Arrived / 上线自动到位 时写入。</summary>
        public int InAgvNo { get; set; }

        /// <summary>已获准进入、正在往机构开的 AGV 号；到位或离站清空后为 0。</summary>
        public int RequestInAgvNo { get; set; }

        /// <summary>最近一拍 PLC 读写是否成功。心跳或读写失败会立刻变 false。</summary>
        public bool IsConnected { get; set; }

        /// <summary>目标写字节是否已与 PLC 回读一致。改 WriteSignal 时自动清掉。</summary>
        public bool WriteSuccess { get; set; }

        /// <summary>内存侧心跳翻转标志，供监视面板看到 Worker 在跑；真正写 PLC 的是 HeartDb 位翻转。</summary>
        public bool Heart { get; set; }

        /// <summary>最近一次断线或周期异常原因，连接正常时清空。</summary>
        public string LastError { get; set; } = "";

        /// <summary>拷贝一份给 MissionStatus / 监视列表，避免 UI 直接绑运行态。</summary>
        public PlcStationSnapshot ToSnapshot() => new PlcStationSnapshot
        {
            JgName = Config.JgName,
            IsConnected = IsConnected,
            ReadSignal = ReadSignal.ToString(),
            WriteSignal = WriteSignal.ToString(),
            ReadWriteSignal = ReadWriteSignal.ToString(),
            InAgvNo = InAgvNo,
            RequestInAgvNo = RequestInAgvNo,
            WriteSuccess = WriteSuccess,
            Heart = Heart,
            LastError = LastError ?? ""
        };
    }
}
