using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Timers;
using CncSimulator.Admin;
using CncSimulator.Config;
using CncSimulator.Device;
using CncSimulator.Generator;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace CncSimulator.Core
{
    /// <summary>
    /// 单个模拟地址的HTTP服务。
    /// 一个端口同时提供：数据API + 管理界面。
    /// </summary>
    public class SimulatorServer
    {
        private readonly AddressConfig _config;
        private readonly List<DeviceSimulator> _devices;
        private readonly List<ScenarioPlayer> _players;
        private readonly IBrandGenerator _generator;
        private readonly LogRecorder _logRecorder;
        private readonly AdminHandler _adminHandler;
        private HttpListener _listener;
        private Timer _tickTimer;
        private bool _isRunning;
        private string _networkError = "normal";
        private DateTime _startTime;
        private long _requestCount;
        private long _successCount;
        private long _failCount;
        private bool _stopped;

        /// <summary>地址名称</summary>
        public string Name => _config.Name;

        /// <summary>端口</summary>
        public int Port => _config.Port;

        /// <summary>是否运行中</summary>
        public bool IsRunning => _isRunning;

        /// <summary>总请求次数</summary>
        public long RequestCount => _requestCount;

        /// <summary>设备总数</summary>
        public int TotalDeviceCount => _devices.Count;

        /// <summary>在线设备数</summary>
        public int OnlineDeviceCount
        {
            get
            {
                int count = 0;
                foreach (var d in _devices) if (d.State.IsOnline) count++;
                return count;
            }
        }

        /// <summary>启动时间</summary>
        public DateTime StartTime => _startTime;

        /// <summary>配置引用</summary>
        public AddressConfig Config => _config;

        /// <summary>设备列表引用</summary>
        public List<DeviceSimulator> Devices => _devices;

        /// <summary>日志记录器引用</summary>
        public LogRecorder LogRecorder => _logRecorder;

        /// <summary>获取本次启动后所有设备的总加工零件数</summary>
        public int GetTotalParts()
        {
            int total = 0;
            foreach (var d in _devices) total += d.State.TotalPartsSinceStart;
            return total;
        }

        /// <summary>获取按设备+NC程序名统计的零件数</summary>
        public JObject GetPartsByDeviceAndProgram()
        {
            var result = new JObject();
            foreach (var dev in _devices)
            {
                var s = dev.State;
                var programs = new JObject();
                foreach (var kvp in s.PartsByProgram)
                {
                    programs[kvp.Key] = kvp.Value;
                }
                result[s.DeviceCode] = new JObject
                {
                    ["desc"] = s.Desc,
                    ["totalParts"] = s.TotalPartsSinceStart,
                    ["currentProgram"] = s.ProgramName,
                    ["currentPartCount"] = s.PartCount,
                    ["programs"] = programs
                };
            }
            return result;
        }

        /// <summary>添加一台模拟设备</summary>
        public void AddDevice(string deviceCode, string desc)
        {
            var devCfg = new Config.DeviceConfig
            {
                DeviceCode = deviceCode,
                Desc = desc,
                InitialProgram = "O0001",
                InitialPartCount = 0
            };
            var sim = new DeviceSimulator(devCfg, _config.DataChangeInterval);
            _devices.Add(sim);

            var player = new ScenarioPlayer(
                sim,
                _config.ScenarioMode == "auto",
                Environment.TickCount + _devices.Count * 1000 + deviceCode.GetHashCode()
            );
            _players.Add(player);
        }

        /// <summary>移除一台模拟设备</summary>
        public bool RemoveDevice(string deviceCode)
        {
            for (int i = 0; i < _devices.Count; i++)
            {
                if (_devices[i].State.DeviceCode == deviceCode)
                {
                    _devices.RemoveAt(i);
                    _players.RemoveAt(i);
                    return true;
                }
            }
            return false;
        }

        public SimulatorServer(AddressConfig config)
        {
            _config = config;
            _devices = new List<DeviceSimulator>();
            _players = new List<ScenarioPlayer>();
            _logRecorder = new LogRecorder(200);
            _generator = new FanucDataGenerator();
            _adminHandler = new AdminHandler();

            // 初始化设备和剧本播放器
            for (int i = 0; i < config.Devices.Count; i++)
            {
                var devCfg = config.Devices[i];
                var sim = new DeviceSimulator(devCfg, config.DataChangeInterval);
                _devices.Add(sim);

                var player = new ScenarioPlayer(
                    sim,
                    config.ScenarioMode == "auto",
                    Environment.TickCount + i * 1000 + devCfg.DeviceCode.GetHashCode()
                );
                _players.Add(player);
            }
        }

        /// <summary>启动数据模拟定时器（HttpListener由构造函数或Shutdown后由外部重建）</summary>
        public void Start()
        {
            if (_isRunning) return;

            _startTime = DateTime.Now;
            _isRunning = true;
            _stopped = false;

            // 启动tick定时器
            _tickTimer = new Timer(_config.DataChangeInterval * 1000);
            _tickTimer.Elapsed += OnTick;
            _tickTimer.Start();

            // 如果HttpListener未运行，则启动
            if (_listener == null || !_listener.IsListening)
            {
                _listener = new HttpListener();
                _listener.Prefixes.Add($"http://+:{_config.Port}/");
                _listener.Start();
                _listener.BeginGetContext(OnRequest, null);
            }

            Console.WriteLine($"  [✓] {_config.Name}: http://localhost:{_config.Port}/ (管理: http://localhost:{_config.Port}/admin)");
        }

        /// <summary>停止模拟（停止Timer，HttpListener继续运行以接受管理请求）</summary>
        public void Stop()
        {
            _isRunning = false;
            _tickTimer?.Stop();
            _tickTimer?.Dispose();
            _tickTimer = null;
        }

        /// <summary>完全关闭（包括HttpListener）</summary>
        public void Shutdown()
        {
            Stop();
            _stopped = true;
            try { _listener?.Stop(); } catch { }
        }

        /// <summary>手动触发设备事件</summary>
        public void TriggerDeviceEvent(string deviceCode, string eventType)
        {
            for (int i = 0; i < _devices.Count; i++)
            {
                if (_devices[i].State.DeviceCode == deviceCode)
                {
                    _players[i].TriggerEvent(eventType);
                    return;
                }
            }
        }

        /// <summary>设置网络异常类型</summary>
        public void SetNetworkError(string type)
        {
            _networkError = type;

            if (type == "refuse")
            {
                // 停止HttpListener模拟拒绝连接
                try { _listener?.Stop(); } catch { }
            }
            else if (type == "normal")
            {
                // 恢复HttpListener
                if (_listener != null && !_stopped)
                {
                    try
                    {
                        if (!_listener.IsListening)
                        {
                            _listener.Start();
                            _listener.BeginGetContext(OnRequest, null);
                        }
                    }
                    catch { }
                }
            }
        }

        /// <summary>修改数据变化频率</summary>
        public void SetInterval(int seconds)
        {
            _config.DataChangeInterval = seconds;
            if (_tickTimer != null)
            {
                _tickTimer.Interval = seconds * 1000;
            }
        }

        /// <summary>切换剧本模式</summary>
        public void SetMode(string mode)
        {
            _config.ScenarioMode = mode;
            foreach (var player in _players)
            {
                player.SetMode(mode);
            }
        }

        /// <summary>获取所有设备状态（用于管理API）</summary>
        public JArray GetDeviceStatusArray()
        {
            var arr = new JArray();
            foreach (var dev in _devices)
            {
                var s = dev.State;
                arr.Add(new JObject
                {
                    ["deviceCode"] = s.DeviceCode,
                    ["desc"] = s.Desc,
                    ["scenario"] = s.CurrentScenario,
                    ["isOnline"] = s.IsOnline,
                    ["programName"] = s.ProgramName,
                    ["partCount"] = s.PartCount,
                    ["runStatus"] = s.RunStatus,
                    ["operateMode"] = s.OperateMode,
                    ["spindleSpeedSet"] = s.SpindleSpeedSet,
                    ["spindleSpeedActual"] = s.SpindleSpeedActual,
                    ["feedSpeedSet"] = s.FeedSpeedSet,
                    ["feedSpeedActual"] = s.FeedSpeedActual,
                    ["spindleLoad"] = s.SpindleLoad,
                    ["machiningStatus"] = s.MachiningStatus,
                    ["scenarioTick"] = s.ScenarioTick,
                    ["scenarioDuration"] = s.ScenarioDuration
                });
            }
            return arr;
        }

        // ===== 私有方法 =====

        /// <summary>定时器回调：推进每台设备的剧本和状态</summary>
        private void OnTick(object sender, ElapsedEventArgs e)
        {
            if (!_isRunning) return;

            foreach (var player in _players)
            {
                player.Tick();
                // 每台设备tick后更新状态
            }
            foreach (var dev in _devices)
            {
                dev.Tick();
            }
        }

        /// <summary>生成当前JSON响应</summary>
        private string GenerateCurrentJson()
        {
            var devices = new JArray();
            foreach (var dev in _devices)
            {
                if (dev.State.IsOnline)
                {
                    devices.Add(_generator.GenerateDevice(dev.State));
                }
            }
            return devices.ToString(Formatting.None);
        }

        /// <summary>生成关键数据摘要</summary>
        private string GenerateKeyData()
        {
            var parts = new List<string>();
            foreach (var dev in _devices)
            {
                var s = dev.State;
                if (s.IsOnline)
                {
                    parts.Add($"{s.DeviceCode}(P={s.PartCount},Prog={s.ProgramName},Run={s.RunStatus})");
                }
                else
                {
                    parts.Add($"{s.DeviceCode}(OFFLINE)");
                }
            }
            return string.Join(" ", parts);
        }

        /// <summary>HttpListener请求回调</summary>
        private void OnRequest(IAsyncResult ar)
        {
            HttpListenerContext ctx;
            try
            {
                if (_listener == null || !_listener.IsListening) return;
                ctx = _listener.EndGetContext(ar);
            }
            catch
            {
                return;
            }

            // 继续接收下一个请求
            try
            {
                if (_listener.IsListening)
                    _listener.BeginGetContext(OnRequest, null);
            }
            catch { }

            ProcessRequest(ctx);
        }

        /// <summary>处理单个HTTP请求</summary>
        private void ProcessRequest(HttpListenerContext ctx)
        {
            string path = ctx.Request.Url.AbsolutePath.TrimEnd('/');
            string method = ctx.Request.HttpMethod;

            try
            {
                // ===== 管理页面路由 =====
                if (path == "/admin")
                {
                    ServeAdminPage(ctx);
                    return;
                }

                // ===== 管理API路由 =====
                if (path.StartsWith("/admin/api/"))
                {
                    HandleAdminApi(ctx, path, method);
                    return;
                }

                // ===== 数据接口 =====
                if (path == "" || path == "/data")
                {
                    ServeData(ctx);
                    return;
                }

                // 404
                SendJsonResponse(ctx, 404, new JObject { ["error"] = "Not Found" }.ToString());
            }
            catch (Exception ex)
            {
                try
                {
                    SendJsonResponse(ctx, 500, new JObject { ["error"] = ex.Message }.ToString());
                }
                catch { }
            }
        }

        /// <summary>提供数据接口</summary>
        private void ServeData(HttpListenerContext ctx)
        {
            _requestCount++;

            // 网络异常模拟
            switch (_networkError)
            {
                case "http500":
                    _failCount++;
                    _logRecorder.RecordError("http500", "模拟HTTP 500错误", OnlineDeviceCount);
                    SendTextResponse(ctx, 500, "Internal Server Error (模拟)");
                    return;
                case "timeout":
                    _failCount++;
                    _logRecorder.RecordError("timeout", "模拟超时响应(60秒延迟)", OnlineDeviceCount);
                    System.Threading.Thread.Sleep(60000);
                    SendTextResponse(ctx, 200, "delayed response");
                    return;
                case "empty":
                    _successCount++;
                    _logRecorder.RecordError("empty", "模拟空数据返回([])", OnlineDeviceCount);
                    SendTextResponse(ctx, 200, "[]", "application/json");
                    return;
                case "malformed":
                    _successCount++;
                    _logRecorder.RecordError("malformed", "模拟畸形JSON返回({broken)", OnlineDeviceCount);
                    SendTextResponse(ctx, 200, "{broken", "application/json");
                    return;
            }

            // 正常生成数据
            var sw = System.Diagnostics.Stopwatch.StartNew();
            string json = GenerateCurrentJson();
            sw.Stop();

            string keyData = GenerateKeyData();
            _logRecorder.Record(_config.Port, OnlineDeviceCount, keyData, json, sw.ElapsedMilliseconds);
            _successCount++;

            SendTextResponse(ctx, 200, json, "application/json");

            Console.WriteLine($"{DateTime.Now:HH:mm:ss} [{_config.Port}] GET / → {OnlineDeviceCount}台设备, {sw.ElapsedMilliseconds}ms");
        }

        /// <summary>提供管理页面</summary>
        private void ServeAdminPage(HttpListenerContext ctx)
        {
            string html = _adminHandler.BuildSingleAddressPage(this);
            SendTextResponse(ctx, 200, html, "text/html; charset=utf-8");
        }

        /// <summary>处理管理API</summary>
        private void HandleAdminApi(HttpListenerContext ctx, string path, string method)
        {
            switch (path)
            {
                case "/admin/api/status":
                    var status = new JObject
                    {
                        ["name"] = _config.Name,
                        ["port"] = _config.Port,
                        ["isRunning"] = _isRunning,
                        ["requestCount"] = _requestCount,
                        ["successCount"] = _successCount,
                        ["failCount"] = _failCount,
                        ["totalDevices"] = _devices.Count,
                        ["onlineDevices"] = OnlineDeviceCount,
                        ["dataChangeInterval"] = _config.DataChangeInterval,
                        ["scenarioMode"] = _config.ScenarioMode,
                        ["networkError"] = _networkError,
                        ["startTime"] = _startTime.ToString("yyyy-MM-dd HH:mm:ss"),
                        ["uptime"] = (DateTime.Now - _startTime).ToString(@"hh\:mm\:ss"),
                        ["devices"] = GetDeviceStatusArray()
                    };
                    SendTextResponse(ctx, 200, status.ToString(), "application/json");
                    break;

                case "/admin/api/start":
                    Start();
                    SendTextResponse(ctx, 200, "{\"ok\":true}", "application/json");
                    break;

                case "/admin/api/stop":
                    Stop();
                    SendTextResponse(ctx, 200, "{\"ok\":true}", "application/json");
                    break;

                case "/admin/api/event":
                    string eventBody = ReadRequestBody(ctx);
                    var eventObj = JObject.Parse(eventBody);
                    TriggerDeviceEvent(
                        eventObj["deviceId"]?.ToString(),
                        eventObj["eventType"]?.ToString()
                    );
                    SendTextResponse(ctx, 200, "{\"ok\":true}", "application/json");
                    break;

                case "/admin/api/interval":
                    string intervalBody = ReadRequestBody(ctx);
                    var intervalObj = JObject.Parse(intervalBody);
                    SetInterval(intervalObj["value"]?.Value<int>() ?? 10);
                    SendTextResponse(ctx, 200, "{\"ok\":true}", "application/json");
                    break;

                case "/admin/api/network":
                    string netBody = ReadRequestBody(ctx);
                    var netObj = JObject.Parse(netBody);
                    SetNetworkError(netObj["type"]?.ToString() ?? "normal");
                    SendTextResponse(ctx, 200, "{\"ok\":true}", "application/json");
                    break;

                case "/admin/api/mode":
                    string modeBody = ReadRequestBody(ctx);
                    var modeObj = JObject.Parse(modeBody);
                    SetMode(modeObj["mode"]?.ToString() ?? "auto");
                    SendTextResponse(ctx, 200, "{\"ok\":true}", "application/json");
                    break;

                case "/admin/api/logs":
                    var logs = _logRecorder.GetRecentLogs(100);
                    var logsArr = new JArray();
                    for (int i = 0; i < logs.Count; i++)
                    {
                        var l = logs[i];
                        logsArr.Add(new JObject
                        {
                            ["index"] = logs.Count - i,
                            ["timestamp"] = l.Timestamp.ToString("HH:mm:ss"),
                            ["deviceCount"] = l.DeviceCount,
                            ["keyData"] = l.KeyData,
                            ["duration"] = l.Duration,
                            ["fullJson"] = l.FullJson
                        });
                    }
                    SendTextResponse(ctx, 200, logsArr.ToString(), "application/json");
                    break;

                case "/admin/api/stats":
                    var stats = new JObject
                    {
                        ["totalDevices"] = _devices.Count,
                        ["onlineDevices"] = OnlineDeviceCount,
                        ["totalParts"] = GetTotalParts(),
                        ["partsByDevice"] = GetPartsByDeviceAndProgram()
                    };
                    SendTextResponse(ctx, 200, stats.ToString(), "application/json");
                    break;

                case "/admin/api/add-device":
                    string addBody = ReadRequestBody(ctx);
                    var addObj = JObject.Parse(addBody);
                    AddDevice(
                        addObj["deviceCode"]?.ToString(),
                        addObj["desc"]?.ToString()
                    );
                    SendTextResponse(ctx, 200, "{\"ok\":true}", "application/json");
                    break;

                case "/admin/api/remove-device":
                    string remBody = ReadRequestBody(ctx);
                    var remObj = JObject.Parse(remBody);
                    bool removed = RemoveDevice(remObj["deviceCode"]?.ToString());
                    SendTextResponse(ctx, 200, removed ? "{\"ok\":true}" : "{\"ok\":false}", "application/json");
                    break;

                case "/admin/api/event-history":
                    HandleEventHistoryApi(ctx);
                    break;

                case "/admin/api/full-summary":
                    HandleFullSummaryApi(ctx);
                    break;

                case "/admin/api/error-log":
                    HandleErrorLogApi(ctx);
                    break;

                default:
                    SendJsonResponse(ctx, 404, "{\"error\":\"Unknown API\"}");
                    break;
            }
        }

        // ===== 新增API处理方法 =====

        /// <summary>事件历史API：返回所有设备的事件变更记录</summary>
        private void HandleEventHistoryApi(HttpListenerContext ctx)
        {
            var allEvents = new JArray();
            foreach (var dev in _devices)
            {
                foreach (var evt in dev.State.EventHistory)
                {
                    allEvents.Add(new JObject
                    {
                        ["timestamp"] = evt.Timestamp.ToString("yyyy-MM-dd HH:mm:ss"),
                        ["deviceCode"] = evt.DeviceCode,
                        ["eventType"] = evt.EventType,
                        ["oldProgram"] = evt.OldProgram,
                        ["newProgram"] = evt.NewProgram,
                        ["partCountBefore"] = evt.PartCountBefore,
                        ["partCountAfter"] = evt.PartCountAfter,
                        ["detail"] = evt.Detail
                    });
                }
            }
            SendTextResponse(ctx, 200, allEvents.ToString(), "application/json");
        }

        /// <summary>完整汇总导出API：用于测试结束后数据对比</summary>
        private void HandleFullSummaryApi(HttpListenerContext ctx)
        {
            var devices = new JArray();
            foreach (var dev in _devices)
            {
                var s = dev.State;
                var programs = new JObject();
                foreach (var kvp in s.PartsByProgram)
                {
                    programs[kvp.Key] = kvp.Value;
                }
                devices.Add(new JObject
                {
                    ["deviceCode"] = s.DeviceCode,
                    ["desc"] = s.Desc,
                    ["isOnline"] = s.IsOnline,
                    ["currentProgram"] = s.ProgramName,
                    ["currentPartCount"] = s.PartCount,
                    ["totalParts"] = s.TotalPartsSinceStart,
                    ["programs"] = programs,
                    ["eventCount"] = s.EventHistory.Count,
                    ["lastEvent"] = s.EventHistory.Count > 0
                        ? new JObject
                        {
                            ["type"] = s.EventHistory[s.EventHistory.Count - 1].EventType,
                            ["time"] = s.EventHistory[s.EventHistory.Count - 1].Timestamp.ToString("yyyy-MM-dd HH:mm:ss")
                        }
                        : null
                });
            }

            var summary = new JObject
            {
                ["exportTime"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
                ["addressName"] = _config.Name,
                ["port"] = _config.Port,
                ["startTime"] = _startTime.ToString("yyyy-MM-dd HH:mm:ss"),
                ["uptime"] = (DateTime.Now - _startTime).ToString(@"hh\:mm\:ss"),
                ["totalDevices"] = _devices.Count,
                ["onlineDevices"] = OnlineDeviceCount,
                ["totalParts"] = GetTotalParts(),
                ["totalRequests"] = _requestCount,
                ["successRequests"] = _successCount,
                ["failRequests"] = _failCount,
                ["errorCount"] = _logRecorder.GetErrorCount(),
                ["devices"] = devices
            };
            SendTextResponse(ctx, 200, summary.ToString(), "application/json");
        }

        /// <summary>异常日志API：返回所有异常记录</summary>
        private void HandleErrorLogApi(HttpListenerContext ctx)
        {
            var errors = _logRecorder.GetErrors();
            var arr = new JArray();
            foreach (var err in errors)
            {
                arr.Add(new JObject
                {
                    ["timestamp"] = err.Timestamp.ToString("yyyy-MM-dd HH:mm:ss"),
                    ["errorType"] = err.ErrorType,
                    ["description"] = err.Description,
                    ["affectedDevices"] = err.AffectedDevices
                });
            }
            SendTextResponse(ctx, 200, arr.ToString(), "application/json");
        }

        // ===== HTTP辅助方法 =====

        private string ReadRequestBody(HttpListenerContext ctx)
        {
            using (var reader = new StreamReader(ctx.Request.InputStream, Encoding.UTF8))
            {
                return reader.ReadToEnd();
            }
        }

        private void SendTextResponse(HttpListenerContext ctx, int statusCode, string body, string contentType = "text/plain")
        {
            try
            {
                ctx.Response.StatusCode = statusCode;
                ctx.Response.ContentType = contentType;
                byte[] bytes = Encoding.UTF8.GetBytes(body);
                ctx.Response.ContentLength64 = bytes.Length;
                ctx.Response.OutputStream.Write(bytes, 0, bytes.Length);
                ctx.Response.OutputStream.Close();
            }
            catch { }
        }

        private void SendJsonResponse(HttpListenerContext ctx, int statusCode, string json)
        {
            SendTextResponse(ctx, statusCode, json, "application/json");
        }
    }
}
