using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Text;
using System.Windows.Forms;

namespace StandardScene.MagCarSimulator
{
    public sealed class MainForm : Form
    {
        private const int MaxLogLines = 400;
        private const int MaxPendingLogs = 300;

        private readonly MagCarSimConfig _config;
        private readonly MagCarSimHost _host;
        private readonly StringBuilder _logBuffer = new StringBuilder();
        private readonly Queue<string> _pendingLogs = new Queue<string>();
        private readonly object _logLock = new object();
        private readonly Timer _uiTimer;
        private bool _logFlushScheduled;
        private int _logLineCount;

        private TextBox _mapPathBox;
        private CheckBox _useTagValueBox;
        private Label _mapInfoLabel;
        private DataGridView _grid;
        private ListBox _siteList;
        private TextBox _logBox;
        private Button _listenButton;
        private Button _loopButton;
        private Button _stopButton;
        private Button _releaseButton;
        private Button _addButton;
        private Button _removeButton;
        private Button _saveButton;

        public MainForm()
        {
            _config = MagCarSimConfig.Load();
            MagCarSimLog.Configure(_config);
            _host = new MagCarSimHost(_config);

            Text = "MagCar 模拟器（FASS 1.0 / SimpleLite 地图循环）";
            Width = 1280;
            Height = 820;
            MinimumSize = new Size(980, 640);
            StartPosition = FormStartPosition.CenterScreen;
            Font = new Font("Microsoft YaHei UI", 9F);

            BuildLayout();
            LoadConfigToUi();

            MagCarSimLog.MessageWritten += OnLogMessage;
            _uiTimer = new Timer { Interval = 250 };
            _uiTimer.Tick += (_, __) => RefreshGridStatus();
            _uiTimer.Start();

            FormClosed += (_, __) =>
            {
                MagCarSimLog.MessageWritten -= OnLogMessage;
                _uiTimer.Stop();
                _host.Dispose();
                MagCarSimLog.Shutdown();
            };

            AppendLog($"就绪。文件日志目录: {MagCarSimLog.GetLogDirectory()}。加载 SimpleLite 地图后启动监听，再开始循环。普通站可叠车；停止点和交管点同时只允许一辆。");
            TryLoadMap(_config.MapPath, silent: true);
        }

        private void BuildLayout()
        {
            var root = new TableLayoutPanel
            {
                Dock = DockStyle.Fill,
                ColumnCount = 1,
                RowCount = 4,
                Padding = new Padding(8)
            };
            root.RowStyles.Add(new RowStyle(SizeType.AutoSize));
            root.RowStyles.Add(new RowStyle(SizeType.Percent, 42));
            root.RowStyles.Add(new RowStyle(SizeType.AutoSize));
            root.RowStyles.Add(new RowStyle(SizeType.Percent, 58));
            Controls.Add(root);

            root.Controls.Add(BuildToolbar(), 0, 0);
            _grid = BuildGrid();
            root.Controls.Add(_grid, 0, 1);
            root.Controls.Add(BuildVehicleButtons(), 0, 2);

            var split = new SplitContainer
            {
                Dock = DockStyle.Fill,
                Orientation = Orientation.Vertical,
                SplitterDistance = 280
            };
            _siteList = new ListBox { Dock = DockStyle.Fill, IntegralHeight = false };
            var sitePanel = new Panel { Dock = DockStyle.Fill, Padding = new Padding(0, 4, 4, 0) };
            sitePanel.Controls.Add(_siteList);
            sitePanel.Controls.Add(new Label
            {
                Text = "地图站点（带 [停止] 的为 Mag_NeedStop）",
                Dock = DockStyle.Top,
                Height = 22
            });
            split.Panel1.Controls.Add(sitePanel);

            _logBox = new TextBox
            {
                Dock = DockStyle.Fill,
                Multiline = true,
                ReadOnly = true,
                ScrollBars = ScrollBars.Both,
                WordWrap = false,
                Font = new Font("Consolas", 9F)
            };
            var logPanel = new Panel { Dock = DockStyle.Fill, Padding = new Padding(4, 4, 0, 0) };
            logPanel.Controls.Add(_logBox);
            logPanel.Controls.Add(new Label
            {
                Text = "协议 / 运动日志",
                Dock = DockStyle.Top,
                Height = 22
            });
            split.Panel2.Controls.Add(logPanel);
            root.Controls.Add(split, 0, 3);
        }

        private Control BuildToolbar()
        {
            var panel = new TableLayoutPanel
            {
                Dock = DockStyle.Top,
                AutoSize = true,
                ColumnCount = 8,
                RowCount = 2,
                Padding = new Padding(0, 0, 0, 6)
            };
            panel.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
            panel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100));
            panel.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
            panel.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
            panel.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
            panel.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
            panel.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
            panel.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));

            panel.Controls.Add(new Label { Text = "地图", AutoSize = true, Anchor = AnchorStyles.Left }, 0, 0);
            _mapPathBox = new TextBox { Dock = DockStyle.Fill, Width = 480 };
            panel.Controls.Add(_mapPathBox, 1, 0);

            var browse = new Button { Text = "浏览…", AutoSize = true };
            browse.Click += (_, __) => BrowseMap();
            panel.Controls.Add(browse, 2, 0);

            var load = new Button { Text = "加载地图", AutoSize = true };
            load.Click += (_, __) => TryLoadMap(_mapPathBox.Text, silent: false);
            panel.Controls.Add(load, 3, 0);

            _listenButton = new Button { Text = "启动监听", AutoSize = true };
            _listenButton.Click += (_, __) => StartListen();
            panel.Controls.Add(_listenButton, 4, 0);

            _loopButton = new Button { Text = "开始循环", AutoSize = true };
            _loopButton.Click += (_, __) => StartLoop();
            panel.Controls.Add(_loopButton, 5, 0);

            _stopButton = new Button { Text = "停止模拟", AutoSize = true, Enabled = false };
            _stopButton.Click += (_, __) => StopSim();
            panel.Controls.Add(_stopButton, 6, 0);

            _saveButton = new Button { Text = "保存配置", AutoSize = true };
            _saveButton.Click += (_, __) => SaveConfig();
            panel.Controls.Add(_saveButton, 7, 0);

            _useTagValueBox = new CheckBox { Text = "用 TagValue 作为节点号", AutoSize = true, Anchor = AnchorStyles.Left };
            panel.SetColumnSpan(_useTagValueBox, 2);
            panel.Controls.Add(_useTagValueBox, 0, 1);

            _mapInfoLabel = new Label
            {
                Text = "未加载地图",
                AutoSize = true,
                Anchor = AnchorStyles.Left,
                ForeColor = Color.DimGray
            };
            panel.SetColumnSpan(_mapInfoLabel, 6);
            panel.Controls.Add(_mapInfoLabel, 2, 1);
            return panel;
        }

        private Control BuildVehicleButtons()
        {
            var panel = new FlowLayoutPanel
            {
                Dock = DockStyle.Fill,
                AutoSize = true,
                WrapContents = false,
                Padding = new Padding(0, 4, 0, 4)
            };
            _addButton = new Button { Text = "添加车辆", AutoSize = true };
            _addButton.Click += (_, __) => AddVehicleRow();
            _removeButton = new Button { Text = "删除选中", AutoSize = true };
            _removeButton.Click += (_, __) => RemoveSelectedVehicle();
            _releaseButton = new Button { Text = "放行选中车", AutoSize = true };
            _releaseButton.Click += (_, __) => ReleaseSelected();
            panel.Controls.Add(_addButton);
            panel.Controls.Add(_removeButton);
            panel.Controls.Add(_releaseButton);
            panel.Controls.Add(new Label
            {
                Text = "普通站可叠车。停止点和交管点同时只允许一辆，后车停在上一站保持运行中。仅 Mag_NeedStop 停车等 0x01。",
                AutoSize = true,
                Padding = new Padding(12, 8, 0, 0),
                ForeColor = Color.DimGray
            });
            return panel;
        }

        private DataGridView BuildGrid()
        {
            var grid = new DataGridView
            {
                Dock = DockStyle.Fill,
                AllowUserToAddRows = false,
                AllowUserToDeleteRows = false,
                RowHeadersVisible = false,
                SelectionMode = DataGridViewSelectionMode.FullRowSelect,
                MultiSelect = false,
                AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill,
                BackgroundColor = Color.White
            };
            grid.Columns.Add(new DataGridViewTextBoxColumn { Name = "Name", HeaderText = "名称", FillWeight = 80 });
            grid.Columns.Add(new DataGridViewTextBoxColumn { Name = "Code", HeaderText = "车号", FillWeight = 50 });
            grid.Columns.Add(new DataGridViewTextBoxColumn { Name = "Port", HeaderText = "端口", FillWeight = 55 });
            grid.Columns.Add(new DataGridViewTextBoxColumn { Name = "Start", HeaderText = "起点", FillWeight = 50 });
            grid.Columns.Add(new DataGridViewTextBoxColumn { Name = "End", HeaderText = "终点", FillWeight = 50 });
            grid.Columns.Add(new DataGridViewTextBoxColumn { Name = "Interval", HeaderText = "间隔ms", FillWeight = 60 });
            grid.Columns.Add(new DataGridViewTextBoxColumn { Name = "Site", HeaderText = "当前站", ReadOnly = true, FillWeight = 55 });
            grid.Columns.Add(new DataGridViewTextBoxColumn { Name = "Node", HeaderText = "节点", ReadOnly = true, FillWeight = 50 });
            grid.Columns.Add(new DataGridViewTextBoxColumn { Name = "State", HeaderText = "状态", ReadOnly = true, FillWeight = 70 });
            grid.Columns.Add(new DataGridViewTextBoxColumn { Name = "Wait", HeaderText = "等待", ReadOnly = true, FillWeight = 55 });
            grid.Columns.Add(new DataGridViewTextBoxColumn { Name = "Clients", HeaderText = "连接", ReadOnly = true, FillWeight = 45 });
            grid.Columns.Add(new DataGridViewTextBoxColumn { Name = "Path", HeaderText = "循环路径", ReadOnly = true, FillWeight = 160 });
            return grid;
        }

        private void LoadConfigToUi()
        {
            _mapPathBox.Text = _config.MapPath ?? "";
            _useTagValueBox.Checked = _config.UseTagValueAsNode;
            _grid.Rows.Clear();
            foreach (var vehicle in _config.Vehicles)
            {
                _grid.Rows.Add(
                    vehicle.Name,
                    vehicle.VehicleCode,
                    vehicle.ListenPort,
                    vehicle.StartSiteId,
                    vehicle.EndSiteId,
                    vehicle.IntervalMs,
                    "",
                    "",
                    "",
                    "",
                    "",
                    "");
            }
        }

        private List<MagCarSimVehicleConfig> ReadVehiclesFromGrid()
        {
            var list = new List<MagCarSimVehicleConfig>();
            foreach (DataGridViewRow row in _grid.Rows)
            {
                if (row.IsNewRow)
                {
                    continue;
                }

                var code = ToUShort(row.Cells["Code"].Value, 1);
                list.Add(new MagCarSimVehicleConfig
                {
                    Name = Convert.ToString(row.Cells["Name"].Value),
                    VehicleCode = code,
                    ListenPort = ToInt(row.Cells["Port"].Value, 5001),
                    StartSiteId = ToInt(row.Cells["Start"].Value, 1),
                    EndSiteId = ToInt(row.Cells["End"].Value, 2),
                    IntervalMs = ToInt(row.Cells["Interval"].Value, _config.DefaultIntervalMs),
                    LoopSiteIds = PreserveLoop(code)
                });
            }

            return list;
        }

        private List<int> PreserveLoop(ushort vehicleCode)
        {
            var existing = _config.Vehicles?.Find(v => v.VehicleCode == vehicleCode);
            if (existing?.LoopSiteIds == null || existing.LoopSiteIds.Count == 0)
            {
                return null;
            }

            return new List<int>(existing.LoopSiteIds);
        }

        private void BrowseMap()
        {
            using var dialog = new OpenFileDialog
            {
                Filter = "SimpleLite 地图 (*.json)|*.json|所有文件 (*.*)|*.*",
                Title = "选择 SimpleLite 地图"
            };
            if (!string.IsNullOrWhiteSpace(_mapPathBox.Text) && File.Exists(_mapPathBox.Text))
            {
                dialog.InitialDirectory = Path.GetDirectoryName(_mapPathBox.Text);
                dialog.FileName = Path.GetFileName(_mapPathBox.Text);
            }

            if (dialog.ShowDialog(this) == DialogResult.OK)
            {
                _mapPathBox.Text = dialog.FileName;
                TryLoadMap(dialog.FileName, silent: false);
            }
        }

        private void TryLoadMap(string path, bool silent)
        {
            if (string.IsNullOrWhiteSpace(path))
            {
                if (!silent)
                {
                    MessageBox.Show(this, "请先选择 SimpleLite 地图文件。", "加载地图", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }

                return;
            }

            try
            {
                _config.UseTagValueAsNode = _useTagValueBox.Checked;
                var map = _host.LoadMap(path);
                _mapPathBox.Text = map.FilePath;
                RefreshSiteList(map);
                var stops = map.ListNeedStopSiteIds();
                _mapInfoLabel.Text = $"站点 {map.Sites.Count}，路径 {map.Tracks.Count}，停止点 {(stops.Count == 0 ? "无（循环将一直过站）" : string.Join(",", stops))}";
            }
            catch (Exception ex)
            {
                _mapInfoLabel.Text = "地图加载失败";
                if (!silent)
                {
                    MessageBox.Show(this, ex.Message, "加载地图失败", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                else
                {
                    AppendLog("地图未加载：" + ex.Message);
                }
            }
        }

        private void RefreshSiteList(SimpleLiteMap map)
        {
            _siteList.Items.Clear();
            foreach (var site in map.Sites.Values)
            {
                var tag = site.NeedStop ? "  [停止]" : "";
                var node = map.ResolveNode(site.Id);
                _siteList.Items.Add($"站 {site.Id}  node={node}{tag}");
            }
        }

        private void StartListen()
        {
            try
            {
                ApplyGridToHost();
                _host.StartListen();
                SetRunningUi(true, looping: false);
                AppendLog("TCP 监听已启动。请在 SimpleLite 中把 MagCar 的 address/Port/VehicleCode 配成与上表一致。");
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, ex.Message, "启动监听失败", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void StartLoop()
        {
            try
            {
                if (!_host.IsListening)
                {
                    ApplyGridToHost();
                }

                _host.StartLoops();
                SetRunningUi(true, looping: true);
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, ex.Message, "开始循环失败", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void StopSim()
        {
            _host.StopAll();
            SetRunningUi(false, looping: false);
            AppendLog("模拟已停止。");
            RefreshGridStatus();
        }

        private void ApplyGridToHost()
        {
            _config.MapPath = _mapPathBox.Text;
            _config.UseTagValueAsNode = _useTagValueBox.Checked;
            _config.Vehicles = ReadVehiclesFromGrid();
            if (!string.IsNullOrWhiteSpace(_config.MapPath))
            {
                TryLoadMap(_config.MapPath, silent: false);
            }

            _host.RebuildVehicles(_config.Vehicles);
        }

        private void AddVehicleRow()
        {
            if (_host.IsListening)
            {
                MessageBox.Show(this, "运行中不能改车辆列表，请先停止模拟。", "添加车辆", MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }

            var nextCode = _grid.Rows.Count + 1;
            _grid.Rows.Add($"AGV-{nextCode}", nextCode, 5000 + nextCode, 1, 6, _config.DefaultIntervalMs, "", "", "", "", "", "");
        }

        private void RemoveSelectedVehicle()
        {
            if (_host.IsListening)
            {
                MessageBox.Show(this, "运行中不能改车辆列表，请先停止模拟。", "删除车辆", MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }

            if (_grid.CurrentRow == null)
            {
                return;
            }

            _grid.Rows.Remove(_grid.CurrentRow);
        }

        private void ReleaseSelected()
        {
            if (_grid.CurrentRow == null)
            {
                MessageBox.Show(this, "请先选中一辆车。", "放行", MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }

            var code = ToUShort(_grid.CurrentRow.Cells["Code"].Value, 0);
            if (!_host.TryRelease(code))
            {
                MessageBox.Show(this, $"未找到车号 {code}，请先启动监听。", "放行", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }

        private void SaveConfig()
        {
            try
            {
                _config.MapPath = _mapPathBox.Text;
                _config.UseTagValueAsNode = _useTagValueBox.Checked;
                _config.Vehicles = ReadVehiclesFromGrid();
                _config.Save();
                AppendLog("配置已保存到 " + MagCarSimConfig.SettingsPath);
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, ex.Message, "保存失败", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void SetRunningUi(bool listening, bool looping)
        {
            _listenButton.Enabled = !listening;
            _loopButton.Enabled = !looping;
            _stopButton.Enabled = listening;
            _addButton.Enabled = !listening;
            _removeButton.Enabled = !listening;
            _grid.ReadOnly = listening;
            _useTagValueBox.Enabled = !listening;
        }

        private void RefreshGridStatus()
        {
            var snapshots = _host.Snapshots();
            if (snapshots.Count == 0)
            {
                return;
            }

            for (var i = 0; i < _grid.Rows.Count && i < snapshots.Count; i++)
            {
                var snap = snapshots[i];
                var row = _grid.Rows[i];
                row.Cells["Site"].Value = snap.CurrentSiteId;
                row.Cells["Node"].Value = snap.Node;
                row.Cells["State"].Value = snap.StateText;
                row.Cells["Wait"].Value = snap.WaitingRelease ? "等放行" : (snap.HoldingForStop ? "让行" : "");
                row.Cells["Clients"].Value = snap.ClientCount;
                row.Cells["Path"].Value = snap.PathText;
                row.DefaultCellStyle.BackColor = snap.WaitingRelease
                    ? Color.FromArgb(255, 236, 179)
                    : snap.HoldingForStop
                        ? Color.FromArgb(207, 232, 255)
                        : Color.White;
            }
        }

        private void OnLogMessage(string message)
        {
            lock (_logLock)
            {
                while (_pendingLogs.Count >= MaxPendingLogs)
                {
                    _pendingLogs.Dequeue();
                }

                _pendingLogs.Enqueue(message);
            }

            if (_logFlushScheduled || !IsHandleCreated)
            {
                return;
            }

            _logFlushScheduled = true;
            try
            {
                BeginInvoke(new Action(FlushLogs));
            }
            catch
            {
                _logFlushScheduled = false;
            }
        }

        private void FlushLogs()
        {
            _logFlushScheduled = false;
            List<string> batch;
            lock (_logLock)
            {
                if (_pendingLogs.Count == 0)
                {
                    return;
                }

                batch = new List<string>(_pendingLogs.Count);
                while (_pendingLogs.Count > 0)
                {
                    batch.Add(_pendingLogs.Dequeue());
                }
            }

            foreach (var line in batch)
            {
                _logLineCount++;
                _logBuffer.AppendLine(line);
            }

            while (_logLineCount > MaxLogLines)
            {
                var text = _logBuffer.ToString();
                var firstBreak = text.IndexOf('\n');
                if (firstBreak < 0)
                {
                    break;
                }

                _logBuffer.Remove(0, firstBreak + 1);
                _logLineCount--;
            }

            _logBox.Text = _logBuffer.ToString();
            _logBox.SelectionStart = _logBox.TextLength;
            _logBox.ScrollToCaret();
        }

        private void AppendLog(string message)
        {
            lock (_logLock)
            {
                while (_pendingLogs.Count >= MaxPendingLogs)
                {
                    _pendingLogs.Dequeue();
                }

                _pendingLogs.Enqueue(message);
            }

            if (IsHandleCreated)
            {
                if (!_logFlushScheduled)
                {
                    _logFlushScheduled = true;
                    BeginInvoke(new Action(FlushLogs));
                }
            }
            else
            {
                FlushLogs();
            }
        }

        private static int ToInt(object value, int fallback)
        {
            return int.TryParse(Convert.ToString(value), out var n) ? n : fallback;
        }

        private static ushort ToUShort(object value, ushort fallback)
        {
            return ushort.TryParse(Convert.ToString(value), out var n) ? n : fallback;
        }
    }
}
