import { Injectable, Logger, OnModuleInit } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import { JobsIngestService } from './jobs-ingest.service';
import { LogIngestService } from './log-ingest.service';
import { MqttClientService } from './mqtt-client.service';
import { PointsIngestService } from './points-ingest.service';

@Injectable()
export class IngestRouterService implements OnModuleInit {
  private readonly logger = new Logger(IngestRouterService.name);

  constructor(
    private readonly prisma: PrismaService,
    private readonly mqttClient: MqttClientService,
    private readonly pointsIngest: PointsIngestService,
    private readonly jobsIngest: JobsIngestService,
    private readonly logIngest: LogIngestService,
  ) {}

  onModuleInit() {
    this.mqttClient.onMessage((topic, payload) => {
      this.route(topic, payload.toString()).catch((err) =>
        this.logger.error(`Failed to process ${topic}: ${err.message}`),
      );
    });
  }

  private async route(topic: string, payload: string) {
    // Raw log captures every message on devices/#, matched or not (audit/debug trail)
    await this.prisma.deviceEvent.create({ data: { topic, payload } });

    const [root, idSegment, ...rest] = topic.split('/');
    const subtopic = rest.join('/');
    if (root !== 'devices' || !idSegment || subtopic === 'jobs/ack') {
      return; // not device traffic, or our own ack echoed back
    }

    // devices/<serial>/log identifies the locator by serial in the topic
    // itself (job in the payload supplies org) — no publisher device lookup.
    if (subtopic === 'log') {
      await this.logIngest.handle(idSegment, payload);
      return;
    }

    const device = await this.prisma.device.findUnique({ where: { mqttUsername: idSegment } });
    if (!device) {
      this.logger.warn(`Message from unregistered device username "${idSegment}" (raw-logged only)`);
      return;
    }
    if (!device.isActive) {
      this.logger.warn(`Message from deactivated device "${idSegment}" ignored`);
      return;
    }

    this.prisma.device
      .update({ where: { id: device.id }, data: { lastSeenAt: new Date() } })
      .catch(() => undefined);

    switch (subtopic) {
      case 'points':
        await this.pointsIngest.handle(device, payload);
        break;
      case 'jobs':
        await this.jobsIngest.handle(device, payload);
        break;
      case 'status':
        break; // lastSeenAt already stamped above
      default:
        this.logger.debug(`Unhandled subtopic "${subtopic}" from ${idSegment}`);
    }
  }
}
