import { InjectClient, Provide, Inject } from '@midwayjs/core';
import { BaseService } from '@cool-midway/core';
import { InjectEntityModel } from '@midwayjs/typeorm';
import { Repository } from 'typeorm';
import { PushWeightEntity } from '../entity/weight';
import { PushSiteweightEntity } from '../entity/siteweight';
import { PushAuditlogEntity } from '../entity/auditlog';
import { PushCameraGpsEntity } from '../entity/cameragps';
import { PushVehicleGpsEntity } from '../entity/vehiclegps';
import { PushDeviceOnoffEntity } from '../entity/deviceonoff';
import { PushDevicealarmEntity } from '../entity/devicealarm';
import { PushIsapiRawEntity } from '../entity/isapientity';
import { IsapiEventType } from '../entity/isapieventtype';
import { PluginService } from '../../plugin/service/info';
import { CachingFactory, MidwayCache } from '@midwayjs/cache-manager';

/**
 * 开放接口业务逻辑服务
 */
@Provide()
export class PushOpenService extends BaseService {
  @InjectEntityModel(PushWeightEntity)
  pushWeightEntity: Repository<PushWeightEntity>;

  @InjectEntityModel(PushSiteweightEntity)
  pushSiteweightEntity: Repository<PushSiteweightEntity>;

  @InjectEntityModel(PushCameraGpsEntity)
  pushCameraGpsEntity: Repository<PushCameraGpsEntity>;

  @InjectEntityModel(PushVehicleGpsEntity)
  pushVehicleGpsEntity: Repository<PushVehicleGpsEntity>;

  @InjectEntityModel(PushDeviceOnoffEntity)
  pushDeviceOnoffEntity: Repository<PushDeviceOnoffEntity>;

  @InjectEntityModel(PushDevicealarmEntity)
  pushDevicealarmEntity: Repository<PushDevicealarmEntity>;

  @InjectEntityModel(PushAuditlogEntity)
  pushAuditlogEntity: Repository<PushAuditlogEntity>;

  @InjectEntityModel(PushIsapiRawEntity)
  pushIsapiRawEntity: Repository<PushIsapiRawEntity>;

  @Inject()
  pluginService: PluginService;

  @InjectClient(CachingFactory, 'default')
  midwayCache: MidwayCache;

  /**
   * 上报称重数据核心业务
   */
  async reportWeight(data: any) {
    const logTime = new Date();

    try {
      // 1. 保存原始称重数据
      const rawWeight = new PushWeightEntity();
      const rawWeightValue = data.garbageWeight || 0;
      const processedWeight = this.calcProcessedWeight(data.garbageType, rawWeightValue);
      rawWeight.deviceNo = data.deviceNo;
      // rawWeight.uploadTime = data.uploadTime ? new Date(data.uploadTime) : new Date();
      rawWeight.uploadTime = new Date();
      rawWeight.garbageType = data.garbageType;
      rawWeight.weight = rawWeightValue;
      rawWeight.extraData =
        typeof data.extraData === 'object'
          ? JSON.stringify(data.extraData)
          : data.extraData;
      await this.pushWeightEntity.save(rawWeight);

      // 2. 模拟关联基础数据模块查询获取商户信息并写入业务称重表
      const siteWeight = new PushSiteweightEntity();
      siteWeight.deviceNo = data.deviceNo;
      siteWeight.uploadTime = rawWeight.uploadTime;
      siteWeight.garbageType = data.garbageType;
      siteWeight.weight = processedWeight;
      siteWeight.extraData = rawWeight.extraData;

      // 动态查询设备基础数据关联信息
      const iotDevices = await this.nativeQuery(
        'SELECT businessId, departmentId FROM t_basicdata_iot WHERE iotCode = ? LIMIT 1',
        [data.deviceNo],
      );

      if (iotDevices && iotDevices.length > 0) {
        siteWeight.businessId = iotDevices[0].businessId;
        siteWeight.departmentId = iotDevices[0].departmentId;
        await this.pushSiteweightEntity.save(siteWeight);
      } else {
        siteWeight.businessId = 'UNKNOWN';
        siteWeight.departmentId = -1;
        await this.writePushAuditLog("weight", { "deviceNo": data.deviceNo, "requestContent": data, "errorMessage": "电子秤还未分配到垃圾收集点." });
      }

    } catch (err) {
      await this.writePushAuditLog("weight", { "deviceNo": data.deviceNo || "UNKNOW", "requestContent": data, "errorMessage": err });
    }

  }

  /**
   * 接收萤石云 消息并缓存
   */
  async saveYingshiyunMessage(body: any) {
    const messageId = body?.header?.messageId || Math.random().toString(36).substring(2);
    // await this.midwayCache.set(`push:yingshiyun:queue:${messageId}`, JSON.stringify(body), 24 * 3600);
    await this.midwayCache.set(`push:yingshiyun:queue:${messageId}`, JSON.stringify(body), 24 * 3600 * 1000);
    this.processYingshiyunAsync(messageId).catch(err => {
      console.error('异步处理GPS消息失败:', err);
    });
    return messageId;
  }

  /**
   * 异步解析萤石云消息，按照消息类型 入库
   */
  async processYingshiyunAsync(messageId: string) {
    const dataStr = await this.midwayCache.get(`push:yingshiyun:queue:${messageId}`) as string | null;
    if (!dataStr) return;
    const body = JSON.parse(dataStr);
    const type = body?.header?.type;
    console.log(`---------------------------------${type}`);
    try {
      switch (type) {
        // 设备上下线
        case 'ys.onoffline': {
          const onoffData: any = {
            deviceId: body.header.deviceId,
            channelNo: Number(body.header.channelNo) || 0,
            messageId: body.header.messageId,
            messageTime: new Date(Number(body.header.messageTime)),
            msgType: body.body.msgType,
            devType: body.body.devType || '',
            deviceName: body.body.deviceName || '',
            subSerial: body.body.subSerial || '',
            dasId: body.body.dasId || '',
            natIp: body.body.natIp || '',
            occurTime: body.body.occurTime ? new Date(body.body.occurTime.replace(' ', 'T')) : null,
            regTime: body.body.regTime ? new Date(body.body.regTime.replace(' ', 'T')) : null,
          };
          await this.pushDeviceOnoffEntity.save(onoffData);
          break;
        }

        // 萤石告警
        case 'ys.alarm': {
          const alarmData: any = {
            devSerial: body.body.devSerial,
            alarmId: body.body.alarmId,
            alarmTime: body.body.alarmTime ? new Date(body.body.alarmTime.replace('T', ' ')) : new Date(),
            alarmType: body.body.alarmType,
            channelName: body.body.channelName,
            channelType: Number(body.body.channelType) || 1,
            customInfo: body.body.customInfo || '',
            customType: body.body.customType || '',
            describe: body.body.describe || '',
            location: body.body.location || '',
            relationId: body.body.relationId || '',
            status: Number(body.body.status) || 1,
            channelNo: String(body.body.channel ?? body.body.channelNo ?? ''),
          };
          if (body.body.checksum) alarmData.checksum = body.body.checksum;
          if (body.body.crypt !== undefined) alarmData.crypt = Number(body.body.crypt);
          // 图片处理（有则处理，无则跳过）
          const localUrls: Record<string, string>[] = [];
          if (body.body.pictureList?.length) {
            try {
              const filePlugin = await this.pluginService.getInstance('upload');
              for (const item of body.body.pictureList) {
                try {
                  const result = await filePlugin.downAndUpload(item.url);
                  localUrls.push({ url: result, id: item.id });
                } catch (err) {
                  console.error(`图片下载失败: ${item.url}`, err);
                }
              }
            } catch (err) {
              console.error('filePlugin init failed:', err);
            }
          }
          alarmData.pictureList = localUrls;
          await this.pushDevicealarmEntity.save(alarmData);
          break;
        }
        //海康 ISAPI
        case 'ys.open.isapi': {
          const header = body.header;
          const payloadStr = body.body?.payload;
          if (!payloadStr) {
            console.warn('ISAPI payload missing');
            break;
          }
          let parsed: any;
          try {
            parsed = JSON.parse(payloadStr);
          } catch (e) {
            console.error('ISAPI payload parse error', e);
            break;
          }

          // 按 eventType 分发
          const eventType = parsed.eventType || parsed.ISAPI?.Intelligent?.ActiveSafety?.EventType || '';
          switch (eventType) {
            case 'VehicleGPS':
              await this.processCameraGpsFromIsapi(parsed, header);
              break;
            case 'ActiveSafety':
            case 'intelligentDetection':
              await this.processActiveSafetyFromIsapi(parsed, header);
              break;
            case 'violentDriving':
            case 'harshAcceleration':
            case 'harshBraking':
            case 'sharpTurn':
              await this.processGsensorFromIsapi(parsed, header);
              break;
            default:
              // 设备状态等未知类型，存 raw（你原来的逻辑）
              const mappedType = Object.values(IsapiEventType).includes(eventType)
                ? eventType
                : IsapiEventType.UNKNOWN;
              await this.pushIsapiRawEntity.save({
                messageId: header.messageId,
                deviceId: header.deviceId,
                channelNo: header.channelNo ?? 0,
                eventType: mappedType,
                eventState: parsed.eventState,
                rawPayload: payloadStr,
                parsed,
                eventTime: parsed.dateTime
                  ? new Date(parsed.dateTime)
                  : new Date(Number(header.messageTime)),
              });
          }
          break;
        }
        default:
          console.warn('Unknown yingshi webhook type:', type);
      }
    } catch (err) {
      await this.writePushAuditLog(type || 'unknown', {
        deviceNo: body?.sn || 'UNKNOWN',
        requestContent: body,
        errorMessage: err,
      });
    }
    // 不管成功与否，删除缓存中的任务队列
    await this.midwayCache.del(`push:yingshiyun:queue:${messageId}`);
  }



  /**
   * 异步解析车载监控的GPS数据，存储并添加业务表
   */
  async processCameraGpsAsync(body: any) {
    try {
      let vehicleNo = '';
      if (body.sn) {

        const gpsData = body.data || {};
        const statusVal = gpsData.status === 'A' ? 'A' : 'B';

        await this.pushCameraGpsEntity.save({
          sn: body.sn,
          msgSeq: body.msgSeq,
          createDate: body.createDate && !isNaN(Number(body.createDate))
            ? new Date(Number(body.createDate))
            : new Date(),
          gpsTime: gpsData.gpsTime
            ? new Date(gpsData.gpsTime.replace(' ', 'T'))
            : new Date(),
          longitude: gpsData.longitude,
          latitude: gpsData.latitude,
          speed: gpsData.speed,
          direction: gpsData.direction,
          elevation: gpsData.elevation,
          status: statusVal,
        });

        const iotDevice: any[] = await this.nativeQuery(
          'SELECT businessId FROM t_basicdata_iot WHERE iotCode = ? LIMIT 1',
          [body.sn]
        );
        if (iotDevice && iotDevice.length > 0 && iotDevice[0].businessId) {
          vehicleNo = `vehicle_${iotDevice[0].businessId}`;

          await this.pushVehicleGpsEntity.save({
            sn: body.sn,
            msgSeq: body.msgSeq,
            createDate: body.createDate && !isNaN(Number(body.createDate))
              ? new Date(Number(body.createDate))
              : new Date(),
            vehicleNo,
            gpsTime: gpsData.gpsTime
              ? new Date(gpsData.gpsTime.replace(' ', 'T'))
              : new Date(),
            longitude: gpsData.longitude,
            latitude: gpsData.latitude,
            speed: gpsData.speed,
            direction: gpsData.direction,
            elevation: gpsData.elevation,
            status: statusVal,
          });

        } else {
          await this.writePushAuditLog("camera_gps", { "deviceNo": body.sn, "requestContent": body, "errorMessage": "车载监控还未分配到车辆" });
        }
      } else {
        await this.writePushAuditLog("camera_gps", { "deviceNo": "UNKOWN", "requestContent": body, "errorMessage": "未包含设备号SN" });
      }

    } catch (err: any) {

      await this.writePushAuditLog("camera_gps", { "deviceNo": body.sn || "UNKNOW", "requestContent": body, "errorMessage": err });

    }
  }

  async writePushAuditLog(pushType: string, data: any) {
    let isSuccess = true;
    let errorMsg = '';
    try {
      const auditLog = new PushAuditlogEntity();
      auditLog.logTime = new Date();
      auditLog.pushType = pushType;
      auditLog.deviceNo = data.deviceNo || data.deviceSn || data.sn || 'unknown-device';
      auditLog.requestContent = typeof data.requestContent === 'string' ? data.requestContent : JSON.stringify(data.requestContent);
      auditLog.errorMessage = data.errorMessage || 'unknown-erroe';
      await this.pushAuditlogEntity.save(auditLog);
    } catch (err) {
      isSuccess = false;
    }

  }

  /**
   * 保存摄像头主动上报告警事件
   * @param alarmData
   */
  async saveCameraAlarmEvent(alarmData: any) {
    const { eventType, targetType, ipAddress, dateTime } = alarmData;
    if (eventType === 'VMD') {
      console.log(`【移动侦测告警】设备${ipAddress}，时间：${dateTime},目标类型:${targetType}`);
      // TODO: 完成摄像机侦测数据保存
    } else {
      console.log(`【未知摄像头事件类型】type:${eventType}`);
    }
    return Date.now();
  }

  /**
   * 从 ISAPI VehicleGPS 解析并写入车载GPS表
   */
  async processCameraGpsFromIsapi(parsed: any, header: any) {
    try {
      const gps = parsed.GPS || parsed.ISAPI?.VehicleGPS?.GPS || {};
      if (!gps.Longitude || !gps.Latitude) {
        console.warn('VehicleGPS payload missing coordinates, skip');
        return;
      }

      const gpsTime = gps.PositionTime || parsed.dateTime;
      await this.pushCameraGpsEntity.save({
        sn: header.deviceId,           // 萤石 deviceId = 设备序列号
        msgSeq: header.messageId || '',
        createDate: new Date(Number(header.messageTime) || Date.now()),
        gpsTime: gpsTime ? new Date(gpsTime.replace(' ', 'T')) : new Date(),
        longitude: Number(gps.Longitude),
        latitude: Number(gps.Latitude),
        speed: gps.Speed != null ? Number(gps.Speed) : 0,
        direction: gps.Direction != null ? Number(gps.Direction) : 0,
        elevation: gps.Altitude != null ? Number(gps.Altitude) : 0,
        status: gps.Status?.GPSFixed === false ? 'B' : 'A',
      });

      // 同步写业务车辆GPS表（复用你已有的逻辑）
      const iotDevice: any[] = await this.nativeQuery(
        'SELECT businessId FROM t_basicdata_iot WHERE iotCode = ? LIMIT 1',
        [header.deviceId]
      );
      if (iotDevice?.length > 0 && iotDevice[0].businessId) {
        const vehicleNo = `vehicle_${iotDevice[0].businessId}`;
        await this.pushVehicleGpsEntity.save({
          sn: header.deviceId,
          msgSeq: header.messageId || '',
          createDate: new Date(Number(header.messageTime) || Date.now()),
          vehicleNo,
          gpsTime: gpsTime ? new Date(gpsTime.replace(' ', 'T')) : new Date(),
          longitude: Number(gps.Longitude),
          latitude: Number(gps.Latitude),
          speed: gps.Speed != null ? Number(gps.Speed) : 0,
          direction: gps.Direction != null ? Number(gps.Direction) : 0,
          elevation: gps.Altitude != null ? Number(gps.Altitude) : 0,
          status: gps.Status?.GPSFixed === false ? 'B' : 'A',
        });
      }
    } catch (err) {
      console.error('processCameraGpsFromIsapi error:', err);
      await this.writePushAuditLog('isapi_vehicle_gps', {
        deviceNo: header.deviceId,
        requestContent: { parsed, header },
        errorMessage: String(err),
      });
    }
  }

  /**
   * 从 ISAPI ActiveSafety 解析并写入设备告警表
   */
  async processActiveSafetyFromIsapi(parsed: any, header: any) {
    try {
      const safety = parsed.ISAPI?.Intelligent?.ActiveSafety || parsed;
      const eventType = safety.EventType || safety.eventType || 'UNKNOWN';
      const gps = safety.GPS || {};
      const snapshot = safety.Snapshot || {};
      const eventStateRaw = safety.EventState || safety.eventState || 'Start';
      const eventState = eventStateRaw === 'End' ? 1 : 0;

      // ✅ 补 triggerTime
      const triggerTime = safety.TriggerTime || parsed.dateTime
        ? new Date((safety.TriggerTime || parsed.dateTime).replace(' ', 'T'))
        : new Date();

      // 判断算法大类
      const adasTypes = ['FCW', 'LDW', 'PCW', 'TSR', 'HMW', 'FCL', 'TLD', 'CLD', 'CAW'];
      const dsmTypes = ['Fatigue', 'Distraction', 'Phone', 'Smoking', 'NoSeatbelt', 'CameraBlocked', 'FaceRecognition'];
      let algorithmType = 'UNKNOWN';
      if (adasTypes.includes(eventType)) algorithmType = 'ADAS';
      else if (dsmTypes.includes(eventType)) algorithmType = 'DSM';
      else if (eventType.toLowerCase().includes('fatigue') || eventType.toLowerCase().includes('distraction')) algorithmType = 'DSM';
      else if (eventType.toLowerCase().includes('fcw') || eventType.toLowerCase().includes('ldw')) algorithmType = 'ADAS';

      // 图片处理
      const pictureList: Array<{ url: string; id: string }> = [];
      if (snapshot.URL || snapshot.url) {
        const imgUrl = snapshot.URL || snapshot.url;
        const crypt = snapshot.Crypt || snapshot.crypt || 0;
        if (crypt == 0) {
          try {
            const filePlugin = await this.pluginService.getInstance('upload');
            const localUrl = await filePlugin.downAndUpload(imgUrl);
            pictureList.push({ url: localUrl, id: header.messageId });
          } catch (e) {
            console.error('ActiveSafety image download failed:', e);
            pictureList.push({ url: imgUrl, id: header.messageId });
          }
        } else {
          pictureList.push({ url: imgUrl, id: header.messageId });
        }
      }

      // 组装位置信息字符串
      let locationStr = '';
      if (gps.Longitude && gps.Latitude) {
        locationStr = `${gps.Longitude},${gps.Latitude}`;
        if (gps.Speed != null) locationStr += `,speed:${gps.Speed}`;
      }

      const customInfo = JSON.stringify({
        algorithmType,
        alarmLevel: safety.AlarmLevel || safety.alarmLevel || 0,
        confidence: safety.Confidence || safety.confidence || 0,
        eventState: eventStateRaw,
        gpsSnapshot: gps,
        rawEventType: eventType,
      });

      // ✅ alarmTime 转 string 对齐 Entity 定义
      const alarmTimeStr = triggerTime.toISOString().slice(0, 19).replace('T', ' ');

      await this.pushDevicealarmEntity.save({
        devSerial: header.deviceId,
        channelNo: String(safety.ChannelID || safety.channelNo || header.channelNo || ''),
        alarmId: header.messageId,
        alarmTime: alarmTimeStr,
        alarmType: eventType,
        channelName: algorithmType === 'ADAS' ? '前视通道' : '司机通道',
        channelType: 0,
        checksum: undefined,
        crypt: 0,
        customInfo,
        customType: '',
        describe: `${algorithmType} ${eventType} alarm`,
        location: locationStr,
        relationId: safety.RelationID || safety.relationId || '',
        status: eventState,
        pictureList: pictureList.length > 0 ? pictureList : undefined,

        // 新增字段
        algorithmType,
        alarmLevel: Number(safety.AlarmLevel || 0),
        confidence: Number(safety.Confidence || 0),
        eventState,
        longitude: Number(gps.Longitude || 0),
        latitude: Number(gps.Latitude || 0),
        speedAtEvent: Number(gps.Speed || 0),
        direction: Number(gps.Direction || 0),
      });
    } catch (err) {
      console.error('processActiveSafetyFromIsapi error:', err);
      await this.writePushAuditLog('isapi_active_safety', {
        deviceNo: header.deviceId,
        requestContent: { parsed, header },
        errorMessage: String(err),
      });
    }
  }

  /**
   * 从 ISAPI violentDriving 解析并写入设备告警表（G-Sensor）
   */
  async processGsensorFromIsapi(parsed: any, header: any) {
    try {
      const driving = parsed.ISAPI?.ViolentDriving || parsed;
      const gps = driving.GPS || {};
      const eventStateRaw = driving.EventState || driving.eventState || 'Start';
      const eventState = eventStateRaw === 'End' ? 1 : 0;

      // ✅ 补 triggerTime
      const triggerTime = driving.TriggerTime || parsed.dateTime
        ? new Date((driving.TriggerTime || parsed.dateTime).replace(' ', 'T'))
        : new Date();
      const alarmTimeStr = triggerTime.toISOString().slice(0, 19).replace('T', ' ');

      let locationStr = '';
      if (gps.Longitude && gps.Latitude) {
        locationStr = `${gps.Longitude},${gps.Latitude}`;
      }

      const customInfo = JSON.stringify({
        algorithmType: 'GSensor',
        alarmLevel: driving.AlarmLevel || 0,
        eventState: eventStateRaw,
        gpsSnapshot: gps,
        extraData: {
          acceleration: driving.Acceleration || driving.acceleration,
          deceleration: driving.Deceleration || driving.deceleration,
          turnAngle: driving.TurnAngle || driving.turnAngle,
        },
      });

      const finalAlarmType = driving.EventType || parsed.eventType || 'violentDriving';

      await this.pushDevicealarmEntity.save({
        devSerial: header.deviceId,
        channelNo: String(header.channelNo || '0'),
        alarmId: header.messageId,
        alarmTime: alarmTimeStr,
        alarmType: finalAlarmType,
        channelName: '车载G-Sensor',
        channelType: 0,
        checksum: undefined,
        crypt: 0,
        customInfo,
        customType: '',
        describe: `G-Sensor ${finalAlarmType}`,
        location: locationStr,
        relationId: driving.RelationID || driving.relationId || '',
        status: eventState,
        pictureList: undefined,

        // ✅ 新增字段
        algorithmType: 'GSensor',
        alarmLevel: Number(driving.AlarmLevel || 0),
        confidence: 0,
        eventState,
        longitude: Number(gps.Longitude || 0),
        latitude: Number(gps.Latitude || 0),
        speedAtEvent: Number(gps.Speed || 0),
        direction: Number(gps.Direction || 0),
      });
    } catch (err) {
      console.error('processGsensorFromIsapi error:', err);
      await this.writePushAuditLog('isapi_gsensor', {
        deviceNo: header.deviceId,
        requestContent: { parsed, header },
        errorMessage: String(err),
      });
    }
  }

  /**
   * 计算处理后的重量
   * 规则：
   * 1. 去皮重：干垃圾/可回收物 -1kg，湿垃圾 -10kg，其它类型同干垃圾（-1kg）
   * 2. 去皮后重量 × 1/10
   * 3. 结果不小于 0
   * SW60     有毒有害
   * SW61     湿垃圾
   * SW62001  可回收-废纸张
   * SW62002  可回收-废塑料
   * SW62003  可回收-废金属
   * SW62004  可回收-废玻璃
   * SW62005  可回收-废织物
   * SW62006  可回收-废旧电子产品
   * SW62007  可回收-废旧电源电池
   * SW63     大件垃圾
   * SW64     干垃圾
   */
  private calcProcessedWeight(garbageType: string, weight: number): number {
    const TARE_MAP: Record<string, number> = { SW61: 10 };
    const tareWeight = TARE_MAP[garbageType] ?? 1;
    return Math.max((weight - tareWeight) / 3, 0);
  }

}