import { Injectable, Logger } from "@nestjs/common";

import { GpsDeviceRepository, GpsPositionRepository } from "./gps.repository";
import { GpsDevice } from "./entities/gps-device.entity";
import { Gt06Gps, Gt06Status } from "./gt06/gt06.codec";

/**
 * Write path for GT06 ingestion: upserts device state and appends position
 * history. Mirrors the ingestion half of @edr/freight-api's GpsTrackingService
 * (the REST/query half stays in freight-api). Auto-registers unknown IMEIs on
 * first contact.
 */
@Injectable()
export class GpsIngestService {
  private readonly logger = new Logger(GpsIngestService.name);

  constructor(
    private readonly devices: GpsDeviceRepository,
    private readonly positions: GpsPositionRepository,
  ) {}

  /** Find the device for an IMEI, auto-registering it on first contact. */
  private async ensureDevice(imei: string): Promise<GpsDevice> {
    const existing = await this.devices.findByImei(imei);
    if (existing) return existing;
    this.logger.log(`Auto-registering new GPS tracker ${imei}`);
    return this.devices.create({ imei, status: "REGISTERED", lastSeenAt: new Date() });
  }

  async handleLogin(imei: string): Promise<void> {
    const device = await this.ensureDevice(imei);
    await this.devices.update(device.id, { lastSeenAt: new Date(), status: "ONLINE" });
  }

  async handleHeartbeat(imei: string, status: Gt06Status): Promise<void> {
    const device = await this.ensureDevice(imei);
    await this.devices.update(device.id, {
      lastSeenAt: new Date(),
      status: "ONLINE",
      voltageLevel: status.voltageLevel,
      gsmLevel: status.gsmLevel,
    });
  }

  async handleFix(imei: string, gps: Gt06Gps, alarm = 0, status?: Gt06Status): Promise<void> {
    const device = await this.ensureDevice(imei);
    const now = new Date();
    await this.devices.update(device.id, {
      lastSeenAt: now,
      status: "ONLINE",
      lastLat: gps.latitude,
      lastLng: gps.longitude,
      lastSpeed: gps.speed,
      lastCourse: gps.course,
      lastFixAt: new Date(gps.time),
      ...(status ? { voltageLevel: status.voltageLevel, gsmLevel: status.gsmLevel } : {}),
    });
    await this.positions.create({
      deviceId: device.id,
      imei,
      vehicleId: device.vehicleId ?? null,
      lat: gps.latitude,
      lng: gps.longitude,
      speed: gps.speed,
      course: gps.course,
      satellites: gps.satellites,
      positioned: gps.positioned,
      gpsTime: new Date(gps.time),
      alarm,
    });
  }
}
