using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using CncSimulator.Admin;
using CncSimulator.Config;
using Newtonsoft.Json.Linq;

namespace CncSimulator.Core
{
    /// <summary>
    /// 引擎主控。启动时只开启9000管理页面，从数据库读取地址信息，
    /// 用户手动启动各端口模拟。
    /// </summary>
    public class SimulatorEngine
    {
        private readonly List<SimulatorServer> _servers = new List<SimulatorServer>();
        private SimulatorConfig _config;
        private HttpListener _gatewayListener;
        private readonly AdminHandler _adminHandler = new AdminHandler();
        private DatabaseReader _dbReader;
        private List<AddressInfo> _dbAddresses = new List<AddressInfo>();
        private int _nextPort;

        /// <summary>所有已创建的地址服务</summary>
        public List<SimulatorServer> Servers => _servers;

        /// <summary>数据库中的采集地址列表</summary>
        public List<AddressInfo> DbAddresses => _dbAddresses;

        /// <summary>配置</summary>
        public SimulatorConfig Config => _config;

        /// <summary>加载数据库配置</summary>
        public void LoadConfig(SimulatorConfig config)
        {
            _config = config;
            _nextPort = config.GatewayPort + 1;
        }

        /// <summary>连接数据库并读取采集地址</summary>
        public bool LoadFromDatabase(out string error)
        {
            _dbReader = new DatabaseReader(_config.DbConnection);
            if (!_dbReader.TestConnection(out error))
            {
                return false;
            }

            _dbAddresses = _dbReader.ReadAddresses();
            return true;
        }

        /// <summary>只启动总管理页面（不启动模拟端口）</summary>
        public void StartGateway()
        {
            StartGatewayListener();
        }

        /// <summary>为指定采集地址创建并启动模拟端口</summary>
        /// <param name="deviceCodes">要模拟的机床编码列表，为空则模拟全部</param>
        public SimulatorServer StartAddress(int dbAddressId, int? port = null, int? interval = null, List<string> deviceCodes = null)
        {
            // 查找数据库中的地址信息
            AddressInfo addrInfo = null;
            foreach (var a in _dbAddresses)
            {
                if (a.DbId == dbAddressId) { addrInfo = a; break; }
            }
            if (addrInfo == null) return null;

            // 检查是否已存在
            foreach (var s in _servers)
            {
                if (s.Config.DbAddressId == dbAddressId) return s;
            }

            // 分配端口
            int usePort = port ?? _nextPort;
            if (usePort <= _config.GatewayPort) usePort = _config.GatewayPort + 1;
            _nextPort = usePort + 1;

            // 创建配置
            var addrConfig = new AddressConfig
            {
                DbAddressId = dbAddressId,
                Name = addrInfo.Name + "模拟",
                Port = usePort,
                Brand = "fanuc",
                DataChangeInterval = interval ?? _config.DefaultDataChangeInterval,
                ScenarioMode = "auto"
            };

            // 筛选要模拟的机床（如果指定了deviceCodes则只模拟选中的，否则模拟全部）
            var machines = addrInfo.Machines;
            if (deviceCodes != null && deviceCodes.Count > 0)
            {
                machines = new List<MachineInfo>();
                foreach (var m in addrInfo.Machines)
                {
                    foreach (var code in deviceCodes)
                    {
                        if (string.Equals(m.DeviceCode, code, StringComparison.OrdinalIgnoreCase))
                        {
                            machines.Add(m);
                            break;
                        }
                    }
                }
            }

            // 为筛选后的机床创建设备配置
            foreach (var m in machines)
            {
                addrConfig.Devices.Add(new DeviceConfig
                {
                    DeviceCode = m.DeviceCode,
                    Desc = m.Name,
                    InitialProgram = "O0001",
                    InitialPartCount = 0
                });
            }

            // 创建并启动服务
            var server = new SimulatorServer(addrConfig);
            server.Start(); // 启动HttpListener + Timer（数据模拟）
            _servers.Add(server);

            Console.WriteLine($"  [✓] 启动模拟: {addrConfig.Name} → http://localhost:{usePort}/ ({machines.Count}/{addrInfo.Machines.Count}台设备)");
            return server;
        }

        /// <summary>停止指定地址的模拟</summary>
        public void StopAddress(int dbAddressId)
        {
            for (int i = _servers.Count - 1; i >= 0; i--)
            {
                if (_servers[i].Config.DbAddressId == dbAddressId)
                {
                    _servers[i].Shutdown();
                    _servers.RemoveAt(i);
                }
            }
        }

        /// <summary>停止所有服务</summary>
        public void StopAll()
        {
            foreach (var server in _servers)
            {
                server.Shutdown();
            }
            _servers.Clear();
            try { _gatewayListener?.Stop(); } catch { }
        }

        /// <summary>按端口查找SimulatorServer</summary>
        public SimulatorServer GetServerByPort(int port)
        {
            foreach (var s in _servers)
            {
                if (s.Port == port) return s;
            }
            return null;
        }

        /// <summary>获取所有地址的状态汇总</summary>
        public JArray GetStatusSummary()
        {
            var arr = new JArray();
            foreach (var server in _servers)
            {
                arr.Add(new JObject
                {
                    ["dbAddressId"] = server.Config.DbAddressId,
                    ["name"] = server.Name,
                    ["port"] = server.Port,
                    ["isRunning"] = server.IsRunning,
                    ["totalDevices"] = server.TotalDeviceCount,
                    ["onlineDevices"] = server.OnlineDeviceCount,
                    ["requestCount"] = server.RequestCount,
                    ["dataChangeInterval"] = server.Config.DataChangeInterval,
                    ["totalParts"] = server.GetTotalParts(),
                    ["partsByDevice"] = server.GetPartsByDeviceAndProgram()
                });
            }
            return arr;
        }

        // ===== 总管理页面 =====

        private void StartGatewayListener()
        {
            try
            {
                _gatewayListener = new HttpListener();
                _gatewayListener.Prefixes.Add($"http://+:{_config.GatewayPort}/");
                _gatewayListener.Start();
                _gatewayListener.BeginGetContext(OnGatewayRequest, null);
                Console.WriteLine($"  [✓] 总管理页面: http://localhost:{_config.GatewayPort}/admin");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"  [✗] 总管理页面启动失败(端口 {_config.GatewayPort}): {ex.Message}");
            }
        }

        private void OnGatewayRequest(IAsyncResult ar)
        {
            HttpListenerContext ctx;
            try
            {
                if (_gatewayListener == null || !_gatewayListener.IsListening) return;
                ctx = _gatewayListener.EndGetContext(ar);
            }
            catch { return; }

            try
            {
                if (_gatewayListener.IsListening)
                    _gatewayListener.BeginGetContext(OnGatewayRequest, null);
            }
            catch { }

            string path = ctx.Request.Url.AbsolutePath.TrimEnd('/');

            try
            {
                if (path == "/admin")
                {
                    string html = _adminHandler.BuildGatewayPage(this);
                    SendResponse(ctx, 200, html, "text/html; charset=utf-8");
                }
                else if (path == "/admin/api/db-addresses")
                {
                    // 返回数据库中的采集地址列表
                    var arr = new JArray();
                    foreach (var a in _dbAddresses)
                    {
                        // 检查是否已在运行
                        bool running = false;
                        int runningPort = 0;
                        foreach (var s in _servers)
                        {
                            if (s.Config.DbAddressId == a.DbId)
                            {
                                running = true;
                                runningPort = s.Port;
                                break;
                            }
                        }
                        arr.Add(new JObject
                        {
                            ["dbId"] = a.DbId,
                            ["name"] = a.Name,
                            ["url"] = a.Url,
                            ["machineCount"] = a.Machines.Count,
                            ["machines"] = JArray.FromObject(a.Machines.Select(m => new JObject
                            {
                                ["id"] = m.Id,
                                ["deviceCode"] = m.DeviceCode,
                                ["name"] = m.Name
                            }).ToList()),
                            ["isRunning"] = running,
                            ["runningPort"] = runningPort
                        });
                    }
                    SendResponse(ctx, 200, arr.ToString(), "application/json");
                }
                else if (path == "/admin/api/status")
                {
                    var summary = GetStatusSummary();
                    SendResponse(ctx, 200, summary.ToString(), "application/json");
                }
                else if (path == "/admin/api/start-address")
                {
                    string body = ReadRequestBody(ctx);
                    var obj = JObject.Parse(body);
                    int dbId = obj["dbAddressId"]?.Value<int>() ?? 0;
                    int? port = obj["port"]?.Value<int>();
                    int? interval = obj["interval"]?.Value<int>();
                    // 解析deviceCodes数组
                    List<string> deviceCodes = null;
                    var codesArr = obj["deviceCodes"] as JArray;
                    if (codesArr != null && codesArr.Count > 0)
                    {
                        deviceCodes = new List<string>();
                        foreach (var c in codesArr) deviceCodes.Add(c.ToString());
                    }
                    var server = StartAddress(dbId, port, interval, deviceCodes);
                    SendResponse(ctx, 200, server != null ? "{\"ok\":true,\"port\":" + server.Port + "}" : "{\"ok\":false}", "application/json");
                }
                else if (path == "/admin/api/stop-address")
                {
                    string body = ReadRequestBody(ctx);
                    var obj = JObject.Parse(body);
                    int dbId = obj["dbAddressId"]?.Value<int>() ?? 0;
                    StopAddress(dbId);
                    SendResponse(ctx, 200, "{\"ok\":true}", "application/json");
                }
                else if (path == "/admin/api/start-all")
                {
                    foreach (var a in _dbAddresses)
                    {
                        bool alreadyRunning = false;
                        foreach (var s in _servers)
                        {
                            if (s.Config.DbAddressId == a.DbId) { alreadyRunning = true; break; }
                        }
                        if (!alreadyRunning) StartAddress(a.DbId);
                    }
                    SendResponse(ctx, 200, "{\"ok\":true}", "application/json");
                }
                else if (path == "/admin/api/stop-all")
                {
                    foreach (var server in _servers.ToArray())
                    {
                        server.Shutdown();
                    }
                    _servers.Clear();
                    SendResponse(ctx, 200, "{\"ok\":true}", "application/json");
                }
                else if (path == "/admin/api/reload-db")
                {
                    _dbAddresses = _dbReader.ReadAddresses();
                    SendResponse(ctx, 200, "{\"ok\":true,\"count\":" + _dbAddresses.Count + "}", "application/json");
                }
                else
                {
                    SendResponse(ctx, 200, "CNC模拟采集服务网关。请访问 /admin 管理页面。", "text/plain");
                }
            }
            catch (Exception ex)
            {
                try { SendResponse(ctx, 500, "{\"error\":\"" + ex.Message.Replace("\"", "'") + "\"}", "application/json"); } catch { }
            }
        }

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

        private void SendResponse(HttpListenerContext ctx, int status, string body, string contentType)
        {
            try
            {
                ctx.Response.StatusCode = status;
                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 { }
        }
    }
}
