using System;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.Linq;
using Dapper;
using MySqlConnector;
using Newtonsoft.Json.Linq;
using CncCollector.Core;
using CncModels.Entity;

namespace CncReplay
{
    /// <summary>
    /// 采集日志重放工具：按时间顺序重放 log_collect_raw 中的采集日志，
    /// 用新的产量跟踪逻辑重新计算产量。
    /// </summary>
    class Program
    {
        static void Main(string[] args)
        {
            Console.OutputEncoding = System.Text.Encoding.UTF8;
            Console.WriteLine("========== CNC采集日志重放工具 ==========");
            Console.WriteLine();

            // 1. 读取连接串
            var businessConnStr = ConfigurationManager.ConnectionStrings["BusinessConnection"]?.ConnectionString;
            var logConnStr = ConfigurationManager.ConnectionStrings["LogConnection"]?.ConnectionString;

            if (string.IsNullOrEmpty(businessConnStr) || string.IsNullOrEmpty(logConnStr))
            {
                Console.WriteLine("错误：未找到数据库连接串配置（BusinessConnection / LogConnection）。");
                Console.WriteLine("请检查 App.config 中的 connectionStrings 配置。");
                return;
            }

            // 2. 查询待重放日志（按时间顺序，取最近的N条成功记录）
            List<LogEntry> logs;
            using (var conn = new MySqlConnection(logConnStr))
            {
                conn.Open();
                logs = conn.Query<LogEntry>(
                    "SELECT id AS Id, request_time AS RequestTime, raw_json AS RawJson, collect_address_id AS CollectAddressId " +
                    "FROM log_collect_raw WHERE is_success = 1 ORDER BY request_time ASC").AsList();
            }

            if (logs.Count == 0)
            {
                Console.WriteLine("未找到待重放的采集日志（is_success=1 的记录）。");
                return;
            }

            Console.WriteLine($"找到 {logs.Count} 条待重放日志。");
            Console.WriteLine();

            // 3. 加载品牌配置 + 字段映射 + 机床列表
            Brand brand;
            List<BrandFieldMapping> mappings;
            List<Machine> machines;

            using (var conn = new MySqlConnection(businessConnStr))
            {
                conn.Open();

                // 加载 FANUC 品牌配置（id=1）
                brand = conn.QueryFirstOrDefault<Brand>(
                    "SELECT id AS Id, brand_name AS BrandName, device_field AS DeviceField, tags_path AS TagsPath, " +
                    "is_enabled AS IsEnabled, created_at AS CreatedAt, updated_at AS UpdatedAt " +
                    "FROM cnc_brand WHERE id = 1");

                if (brand == null)
                {
                    Console.WriteLine("错误：未找到品牌配置（cnc_brand.id=1），请先配置品牌。");
                    return;
                }

                // 加载品牌字段映射
                mappings = conn.Query<BrandFieldMapping>(
                    "SELECT id AS Id, brand_id AS BrandId, standard_field AS StandardField, field_name AS FieldName, " +
                    "match_by AS MatchBy, data_type AS DataType, is_required AS IsRequired, is_enabled AS IsEnabled, " +
                    "created_at AS CreatedAt FROM cnc_brand_field_mapping WHERE brand_id = @BrandId",
                    new { BrandId = brand.Id }).AsList();

                if (mappings == null || mappings.Count == 0)
                {
                    Console.WriteLine("警告：未找到品牌字段映射，解析将无法提取数据。");
                    mappings = new List<BrandFieldMapping>();
                }

                // 加载所有启用的机床
                machines = conn.Query<Machine>(
                    "SELECT id AS Id, device_code AS DeviceCode, name AS Name, workshop_id AS WorkshopId, " +
                    "collect_address_id AS CollectAddressId, ip_address AS IpAddress, brand_id AS BrandId, " +
                    "is_enabled AS IsEnabled, last_ping_time AS LastPingTime, last_collect_time AS LastCollectTime, " +
                    "last_device_status AS LastDeviceStatus, last_run_status AS LastRunStatus, " +
                    "last_program_name AS LastProgramName, last_part_count AS LastPartCount, " +
                    "last_operate_mode AS LastOperateMode, last_machining_status AS LastMachiningStatus, " +
                    "created_at AS CreatedAt, updated_at AS UpdatedAt " +
                    "FROM cnc_machine WHERE is_enabled = 1").AsList();

                if (machines == null || machines.Count == 0)
                {
                    Console.WriteLine("警告：未找到启用的机床配置。");
                    machines = new List<Machine>();
                }
            }

            Console.WriteLine($"品牌: {brand.BrandName}，字段映射: {mappings.Count}条，机床: {machines.Count}台");
            Console.WriteLine();

            // 构建 device_code → machine 的查找字典
            var machineDict = machines
                .Where(m => !string.IsNullOrEmpty(m.DeviceCode))
                .ToDictionary(m => m.DeviceCode, StringComparer.OrdinalIgnoreCase);

            // 4. 创建产量跟踪器
            using (var tracker = new ProductionTracker(businessConnStr))
            {
                var swTotal = Stopwatch.StartNew();
                int processed = 0;

                // 5. 逐条重放
                foreach (var log in logs)
                {
                    var startTime = DateTime.Now;
                    var analysisLogs = new List<string>();
                    analysisLogs.Add("========== CNC采集产量分析日志(重放) ==========");
                    analysisLogs.Add("原始采集时间：" + log.RequestTime.ToString("yyyy-MM-dd HH:mm:ss"));

                    JArray devices;
                    try
                    {
                        devices = JArray.Parse(log.RawJson);
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine($"  [警告] 日志 #{log.Id} JSON解析失败: {ex.Message}，跳过。");
                        continue;
                    }

                    var records = new List<CollectRecord>();

                    foreach (var deviceToken in devices)
                    {
                        var deviceObj = deviceToken as JObject;
                        if (deviceObj == null) continue;

                        // 提取 device 字段值
                        string deviceCode = DataParser.ExtractDeviceCode(deviceObj, brand.DeviceField ?? "device");
                        if (string.IsNullOrEmpty(deviceCode)) continue;

                        // 匹配机床
                        Machine machine;
                        if (!machineDict.TryGetValue(deviceCode, out machine))
                        {
                            analysisLogs.Add($"---未知设备: device={deviceCode}---");
                            continue;
                        }

                        // 解析字段
                        var parsed = DataParser.ParseDevice(deviceObj, brand, mappings);

                        var programName = GetStringValue(parsed, "program_name");
                        var partCount = GetDecimalValue(parsed, "part_count");
                        var totalPartCount = GetDecimalValue(parsed, "total_part_count");

                        // 跳过无效数据（断电设备）
                        if (string.IsNullOrEmpty(programName) && !partCount.HasValue)
                            continue;

                        var record = new CollectRecord
                        {
                            MachineId = machine.Id,
                            CollectTime = log.RequestTime,
                            ProgramName = programName,
                            PartCount = partCount,
                            TotalPartCount = totalPartCount,
                            DeviceStatus = GetStringValue(parsed, "device_status"),
                            RunStatus = GetStringValue(parsed, "run_status"),
                            OperateMode = GetStringValue(parsed, "operate_mode"),
                            PowerOnTime = GetDecimalValue(parsed, "power_on_time"),
                            RunTime = GetDecimalValue(parsed, "run_time")
                        };
                        records.Add(record);

                        // 调用产量跟踪
                        var (logText, changed, todayTotal) = tracker.Track(
                            machine.Id, programName, totalPartCount, log.RequestTime);
                        analysisLogs.Add("---机床：" + machine.Name + "---");
                        analysisLogs.Add("程序名=" + (programName ?? "空") + "，加工零件总数=" + (totalPartCount?.ToString() ?? "空"));
                        analysisLogs.Add("结果：" + logText + "，当日产量=" + todayTotal.ToString("F0"));
                    }

                    // 写入采集记录 + 更新分析日志
                    analysisLogs.Add("==========================================");
                    CollectRecordWriter.WriteBatchReplay(businessConnStr, logConnStr,
                        records, log.Id, log.CollectAddressId, log.RequestTime,
                        string.Join("\n", analysisLogs));

                    processed++;
                    Console.WriteLine($"[{processed}/{logs.Count}] {log.RequestTime:yyyy-MM-dd HH:mm:ss} → " +
                        $"{records.Count}台设备，耗时{(DateTime.Now - startTime).TotalMilliseconds:F0}ms");
                }

                swTotal.Stop();
                Console.WriteLine();
                Console.WriteLine($"重放完成：{processed}条日志，总耗时{swTotal.Elapsed.TotalSeconds:F0}秒");
            }
        }

        /// <summary>
        /// 从解析结果中获取字段的字符串值
        /// </summary>
        static string GetStringValue(Dictionary<string, DataParser.ParsedField> parsed, string field)
        {
            DataParser.ParsedField pf;
            return parsed.TryGetValue(field, out pf) ? pf.StringValue : null;
        }

        /// <summary>
        /// 从解析结果中获取字段的数值
        /// </summary>
        static decimal? GetDecimalValue(Dictionary<string, DataParser.ParsedField> parsed, string field)
        {
            DataParser.ParsedField pf;
            return parsed.TryGetValue(field, out pf) ? pf.NumericValue : null;
        }
    }

    /// <summary>
    /// log_collect_raw 表的查询结果映射
    /// </summary>
    class LogEntry
    {
        public long Id { get; set; }
        public DateTime RequestTime { get; set; }
        public string RawJson { get; set; }
        public int CollectAddressId { get; set; }
    }
}
