using System;

namespace CncSimulator.Device
{
    /// <summary>
    /// 单台设备的状态机。
    /// 维护设备当前状态，根据场景规则更新各字段。
    /// </summary>
    public class DeviceSimulator
    {
        private readonly DeviceState _state;
        private readonly Random _rng;
        private static readonly string[] MachiningStatusOptions = { "G01", "G01", "G01", "G02", "G00" };
        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,
                // LastPartCount removed - not in DeviceState
                DataChangeInterval = dataChangeInterval,
                IsOnline = true,
                DeviceStatus = 1,
                RunStatus = 0,
                OperateMode = 10,
                SpindleSpeedSet = 450,
                FeedSpeedSet = 60,
                SpindleSpeedActual = 0,
                FeedSpeedActual = 0,
                SpindleLoad = 0,
                SpindleOverride = 100,
                PowerOnTime = _rng.Next(20000000, 24000000),
                RunTime = _rng.Next(15000, 20000),
                CuttingTime = _rng.Next(6000000, 7000000),
                CycleTime = _rng.Next(500, 800),
                MachiningStatus = "",
                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;
            }
        }

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

            switch (scenario)
            {
                case "machining":
                    _state.PartCount++;
                    _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;
                    // 主轴实际速度 = 设定 ± 10%随机波动
                    _state.SpindleSpeedActual = _state.SpindleSpeedSet * (1m + (decimal)(_rng.NextDouble() * 0.2 - 0.1));
                    _state.FeedSpeedActual = _state.FeedSpeedSet * (1m + (decimal)(_rng.NextDouble() * 0.1 - 0.05));
                    _state.SpindleLoad = _rng.Next(15, 46);
                    _state.SpindleOverride = 100;
                    _state.MachiningStatus = MachiningStatusOptions[_rng.Next(MachiningStatusOptions.Length)];
                    _state.CuttingTime += interval;
                    _state.RunTime += interval;
                    _state.PowerOnTime += 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.SpindleSpeedActual = 0;
                    _state.FeedSpeedActual = 0;
                    _state.SpindleLoad = 0;
                    _state.FeedSpeedSet = 0;
                    _state.MachiningStatus = "";
                    _state.PowerOnTime += interval;
                    _state.RunTime += interval;
                    break;

                case "pause":
                    _state.RunStatus = 1;
                    _state.SpindleSpeedActual = 0;
                    _state.FeedSpeedActual = 0;
                    _state.SpindleLoad = 0;
                    _state.MachiningStatus = "";
                    _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.CycleTime = 0;
            _state.RunStatus = 3;
            _state.DeviceStatus = 1;
            _state.OperateMode = 1;
            _state.MachiningStatus = "G01";
            _state.SpindleSpeedSet = _rng.Next(200, 801);
            _state.FeedSpeedSet = _rng.Next(30, 151);
            _state.SpindleOverride = 100;
            _state.ProgramContent = "<" + _state.ProgramName + ">\nG40G49G80\n( SIMULATOR )";
            // 记录事件历史
            _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;
            // 记录事件历史
            _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.CycleTime = 0;
            _state.RunStatus = 0;
            _state.OperateMode = 10;
            _state.SpindleSpeedActual = 0;
            _state.FeedSpeedActual = 0;
            _state.SpindleLoad = 0;
            _state.MachiningStatus = "";
            // 记录事件历史
            _state.RecordEvent("power_on", _state.ProgramName, _state.ProgramName, oldPartCount, 0, "设备开机，零件数清零");
        }
    }
}
