using System;
using System.Collections.Generic;
using System.Text;
using Dapper;
using MySqlConnector;
using CncModels.Entity;
using log4net;

namespace CncCollector.Core
{
    /// <summary>
    /// 采集数据批量写入器。
    /// 负责写入采集结构化记录、原始JSON日志，更新机床和地址实时状态。
    /// </summary>
    public class CollectRecordWriter
    {
        private static readonly ILog _log = LogManager.GetLogger(typeof(CollectRecordWriter));

        /// <summary>
        /// 批量写入采集记录并更新相关状态
        /// </summary>
        /// <param name="businessConnStr">业务库连接字符串</param>
        /// <param name="logConnStr">日志库连接字符串</param>
        /// <param name="records">采集记录列表</param>
        /// <param name="rawJson">原始JSON字符串</param>
        /// <param name="collectAddressId">采集地址ID</param>
        /// <param name="requestTime">请求开始时间</param>
        /// <param name="responseDurationMs">响应耗时（毫秒）</param>
        /// <param name="isSuccess">是否采集成功</param>
        /// <param name="errorMessage">错误信息（失败时）</param>
        public static long WriteBatch(string businessConnStr, string logConnStr,
            List<CollectRecord> records, string rawJson, int collectAddressId,
            DateTime requestTime, long? responseDurationMs, bool isSuccess, string errorMessage, int? statusCode = null)
        {
            var now = DateTime.Now;
            long lastRawLogId = 0;

            // 1. 写入原始JSON到日志库
            try
            {
                using (var conn = new MySqlConnection(logConnStr))
                {
                    conn.Open();
                    conn.Execute(@"INSERT INTO log_collect_raw (collect_address_id, request_time, response_time, response_duration, is_success, status_code, raw_json, error_message, created_at)
                        VALUES (@CollectAddressId, @RequestTime, @ResponseTime, @ResponseDuration, @IsSuccess, @StatusCode, @RawJson, @ErrorMessage, @CreatedAt)",
                        new
                        {
                            CollectAddressId = collectAddressId,
                            RequestTime = requestTime,
                            ResponseTime = now,
                            ResponseDuration = responseDurationMs,
                            IsSuccess = isSuccess ? 1 : 0,
                            StatusCode = statusCode ?? (isSuccess ? (int?)200 : null),
                            RawJson = rawJson ?? "",
                            ErrorMessage = errorMessage ?? (string)null,
                            CreatedAt = now
                        });
                    // 记录刚插入的 raw_log 的自增ID
                    try
                    {
                        lastRawLogId = conn.ExecuteScalar<long>("SELECT LAST_INSERT_ID();");
                    }
                    catch { lastRawLogId = 0; }
                }
            }
            catch (Exception ex)
            {
                // 数据库不可用时，详细错误信息通过log4net写入本地日志文件，确保问题可追溯
                _log.Error($"写入原始JSON日志失败（地址ID={collectAddressId}, 成功={isSuccess}）: {errorMessage}", ex);
            }

            if (!isSuccess || records == null || records.Count == 0) return lastRawLogId;

            // 2. 批量写入采集结构化记录到业务库
            try
            {
                using (var conn = new MySqlConnection(businessConnStr))
                {
                    conn.Open();
                    using (var tran = conn.BeginTransaction())
                    {
                        try
                        {
                            foreach (var r in records)
                            {
                                conn.Execute(@"INSERT INTO cnc_collect_record (machine_id, collect_time, device_time, program_name, part_count, 
                                    device_status, run_status, operate_mode, spindle_speed_set, feed_speed_set, 
                                    spindle_speed_actual, feed_speed_actual, spindle_load, spindle_override, 
                                    power_on_time, run_time, cutting_time, cycle_time, machining_status, extra_data, created_at)
                                    VALUES (@MachineId, @CollectTime, @DeviceTime, @ProgramName, @PartCount, 
                                    @DeviceStatus, @RunStatus, @OperateMode, @SpindleSpeedSet, @FeedSpeedSet, 
                                    @SpindleSpeedActual, @FeedSpeedActual, @SpindleLoad, @SpindleOverride, 
                                    @PowerOnTime, @RunTime, @CuttingTime, @CycleTime, @MachiningStatus, @ExtraData, @CreatedAt)",
                                    new
                                    {
                                        r.MachineId,
                                        CollectTime = r.CollectTime,
                                        DeviceTime = r.DeviceTime,
                                        ProgramName = r.ProgramName ?? (string)null,
                                        PartCount = r.PartCount,
                                        DeviceStatus = r.DeviceStatus ?? (string)null,
                                        RunStatus = r.RunStatus ?? (string)null,
                                        OperateMode = r.OperateMode ?? (string)null,
                                        SpindleSpeedSet = r.SpindleSpeedSet,
                                        FeedSpeedSet = r.FeedSpeedSet,
                                        SpindleSpeedActual = r.SpindleSpeedActual,
                                        FeedSpeedActual = r.FeedSpeedActual,
                                        SpindleLoad = r.SpindleLoad,
                                        SpindleOverride = r.SpindleOverride,
                                        PowerOnTime = r.PowerOnTime,
                                        RunTime = r.RunTime,
                                        CuttingTime = r.CuttingTime,
                                        CycleTime = r.CycleTime,
                                        MachiningStatus = r.MachiningStatus ?? (string)null,
                                        ExtraData = r.ExtraData ?? (string)null,
                                        CreatedAt = now
                                    }, tran);
                            }
                            tran.Commit();
                        }
                        catch
                        {
                            tran.Rollback();
                            throw;
                        }
                    }

                    // 3. 更新每台机床的实时状态字段
                    foreach (var r in records)
                    {
                        try
                        {
                            conn.Execute(@"UPDATE cnc_machine SET last_collect_time = @CollectTime, 
                                last_device_status = @DeviceStatus, last_run_status = @RunStatus,
                                last_program_name = @ProgramName, last_part_count = @PartCount,
                                last_operate_mode = @OperateMode, last_machining_status = @MachiningStatus
                                WHERE id = @MachineId",
                                new
                                {
                                    r.MachineId,
                                    r.CollectTime,
                                    DeviceStatus = r.DeviceStatus ?? (string)null,
                                    RunStatus = r.RunStatus ?? (string)null,
                                    ProgramName = r.ProgramName ?? (string)null,
                                    r.PartCount,
                                    OperateMode = r.OperateMode ?? (string)null,
                                    MachiningStatus = r.MachiningStatus ?? (string)null
                                });
                        }
                        catch (Exception ex)
                        {
                            _log.Error($"更新机床实时状态失败（machine_id={r.MachineId}）", ex);
                        }
                    }

                    // 4. 更新采集地址状态
                    try
                    {
                        conn.Execute(@"UPDATE cnc_collect_address SET last_collect_time = @Time, last_collect_status = 'success', fail_count = 0, updated_at = NOW() 
                            WHERE id = @Id",
                            new { Time = now, Id = collectAddressId });
                    }
                    catch (Exception ex)
                    {
                        _log.Error($"更新采集地址状态失败（address_id={collectAddressId}）", ex);
                    }
                }
            }
            catch (Exception ex)
            {
                _log.Error($"批量写入采集记录失败（地址ID={collectAddressId}）", ex);
            }
            return lastRawLogId;
        }

        /// <summary>
        /// 记录采集失败：更新采集地址的失败计数和状态
        /// </summary>
        public static void RecordFailure(string businessConnStr, int collectAddressId, string errorMsg)
        {
            try
            {
                using (var conn = new MySqlConnection(businessConnStr))
                {
                    conn.Execute(@"UPDATE cnc_collect_address SET last_collect_status = 'fail', fail_count = fail_count + 1, updated_at = NOW() WHERE id = @Id",
                        new { Id = collectAddressId });
                }
            }
            catch (Exception ex)
            {
                _log.Error($"记录采集失败状态时出错（address_id={collectAddressId}）", ex);
            }
        }
    }
}
