using System;

namespace CncSimulator.Device
{
    /// <summary>
    /// 单台设备的状态机。
    /// 维护设备当前状态，根据场景规则更新字段。
    /// 仅包含实际FANUC采集数据中存在的字段。
    /// </summary>
    public class DeviceSimulator
    {
        private readonly DeviceState _state;
        private readonly Random _rng;
        private static readonly string[] ProgramPool = { "O0001", "O0002", "1566.NC", "PART-A", "TEST-03" };
        private int _programPoolIndex;

        /// <summary>设备当前状态（只读引用）</summary>
        public DeviceState State => _state;

        public DeviceSimulator(Config.DeviceConfig config, int dataChangeInterval)
        {
            _rng = new Random(Environment.TickCount + config.DeviceCode.GetHashCode());
            _state = new DeviceState
            {
                DeviceCode = config.DeviceCode,
                Desc = config.Desc,
                ProgramName = config.InitialProgram,
                PartCount = config.InitialPartCount,
                // 历史累计零件总数：配置值优先，否则随机
                TotalPartCount = config.InitialTotalPartCount > 0
                    ? config.InitialTotalPartCount
                    : _rng.Next(40000, 50000),
                DataChangeInterval = dataChangeInterval,
                IsOnline = true,
                DeviceStatus = 1,
                RunStatus = 0,
                OperateMode = 10,
                PowerOnTime = _rng.Next(20000000, 24000000),
                RunTime = _rng.Next(15000, 20000),
                CuttingTime = _rng.Next(5000, 12000),
                CycleTime = _rng.Next(3000, 8000),
                ProgramContent = "",
                CurrentScenario = "idle",
                ScenarioTick = 0,
                ScenarioDuration = 10
            };

            // 找到初始程序在池中的位置
            _programPoolIndex = Array.IndexOf(ProgramPool, config.InitialProgram);
            if (_programPoolIndex < 0) _programPoolIndex = 0;
        }

        /// <summary>每次tick调用，根据当前场景更新字段</summary>
        public void Tick()
        {
            if (!_state.IsOnline) return;

            _state.ScenarioTick++;
            ApplyScenarioUpdate(_state.CurrentScenario);
        }

        /// <summary>切换场景</summary>
        public void SetScenario(string scenarioName, int duration)
        {
            _state.CurrentScenario = scenarioName;
            _state.ScenarioTick = 0;
            _state.ScenarioDuration = duration;

            // 瞬时场景立即执行
            if (scenarioName == "program_change") ApplyProgramChange();
            else if (scenarioName == "manual_reset") ApplyManualReset();
            else if (scenarioName == "power_on") ApplyPowerOn();
        }

        /// <summary>手动触发事件（忽略剧本）</summary>
        public void TriggerEvent(string eventType)
        {
            switch (eventType)
            {
                case "power_off":
                    ApplyPowerOff();
                    break;
                case "power_on":
                    ApplyPowerOn();
                    break;
                case "program_change":
                    ApplyProgramChange();
                    break;
                case "manual_reset":
                    ApplyManualReset();
                    break;
                case "pause":
                    SetScenario("pause", 999);
                    break;
                case "idle":
                    SetScenario("idle", 999);
                    break;
                case "machining":
                    SetScenario("machining", 999);
                    break;
                case "same_part":
                    SetScenario("same_part", 999);
                    break;
                case "time_freeze":
                    // 冻结时间：Tag的time保持不变，value继续正常更新
                    _state.FreezeTime = true;
                    if (!_state.FrozenTimeValue.HasValue)
                        _state.FrozenTimeValue = DateTime.Now;
                    break;
                case "time_unfreeze":
                    // 解冻时间：恢复正常time更新
                    _state.FreezeTime = false;
                    _state.FrozenTimeValue = null;
                    break;
            }
        }

        /// <summary>根据场景名更新字段</summary>
        private void ApplyScenarioUpdate(string scenario)
        {
            int interval = _state.DataChangeInterval;

            switch (scenario)
            {
                case "machining":
                    _state.PartCount++;
                    _state.TotalPartCount++;
                    _state.TotalPartsSinceStart++;
                    // 按NC程序名累计零件数
                    if (!_state.PartsByProgram.ContainsKey(_state.ProgramName))
                        _state.PartsByProgram[_state.ProgramName] = 0;
                    _state.PartsByProgram[_state.ProgramName]++;
                    _state.RunStatus = 3;
                    _state.DeviceStatus = 1;
                    _state.OperateMode = 1;
                    _state.RunTime += interval;
                    _state.PowerOnTime += interval;
                    _state.CuttingTime += interval;
                    _state.CycleTime += interval;
                    _state.ProgramContent = "<" + _state.ProgramName + ">\nG40G49G80\n( SIMULATOR )";
                    break;

                case "same_part":
                    // 所有值不变，只有time会在生成JSON时更新
                    _state.PowerOnTime += interval;
                    _state.RunTime += interval;
                    break;

                case "idle":
                    _state.RunStatus = 0;
                    _state.OperateMode = 10;
                    _state.PowerOnTime += interval;
                    _state.RunTime += interval;
                    break;

                case "pause":
                    _state.RunStatus = 1;
                    _state.PowerOnTime += interval;
                    _state.RunTime += interval;
                    break;

                case "program_change":
                case "manual_reset":
                case "power_on":
                    // 瞬时场景，已在SetScenario中处理
                    break;
            }
        }

        /// <summary>换零件</summary>
        private void ApplyProgramChange()
        {
            string oldProgram = _state.ProgramName;
            int oldPartCount = _state.PartCount;
            _programPoolIndex = (_programPoolIndex + 1) % ProgramPool.Length;
            _state.ProgramName = ProgramPool[_programPoolIndex];
            _state.PartCount = 0;
            _state.RunStatus = 3;
            _state.DeviceStatus = 1;
            _state.OperateMode = 1;
            _state.ProgramContent = "<" + _state.ProgramName + ">\nG40G49G80\n( SIMULATOR )";
            // TotalPartCount不清零（终身累计）
            // 记录事件历史
            _state.RecordEvent("program_change", oldProgram, _state.ProgramName, oldPartCount, 0);
        }

        /// <summary>手动清零</summary>
        private void ApplyManualReset()
        {
            int oldPartCount = _state.PartCount;
            _state.PartCount = 0;
            _state.RunStatus = 3;
            _state.DeviceStatus = 1;
            // TotalPartCount不清零（终身累计）
            // 记录事件历史
            _state.RecordEvent("manual_reset", _state.ProgramName, _state.ProgramName, oldPartCount, 0);
        }

        /// <summary>断电</summary>
        private void ApplyPowerOff()
        {
            _state.IsOnline = false;
            _state.DeviceStatus = 0;
            // 记录事件历史
            _state.RecordEvent("power_off", _state.ProgramName, _state.ProgramName, _state.PartCount, _state.PartCount, "设备断电");
        }

        /// <summary>恢复开机</summary>
        private void ApplyPowerOn()
        {
            int oldPartCount = _state.PartCount;
            _state.IsOnline = true;
            _state.DeviceStatus = 1;
            _state.PartCount = 0;
            _state.RunStatus = 0;
            _state.OperateMode = 10;
            // TotalPartCount不清零（终身累计）
            // 记录事件历史
            _state.RecordEvent("power_on", _state.ProgramName, _state.ProgramName, oldPartCount, 0, "设备开机，零件数清零");
        }
    }
}
