import {
  Injectable,
  BadRequestException,
  NotFoundException,
  Logger,
} from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { PrismaService } from '../../database/prisma.service';
import { v4 as uuidv4 } from 'uuid';
import * as QRCode from 'qrcode';
import { DeviceOS } from '@prisma/client';

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

  constructor(
    private readonly prisma: PrismaService,
    private readonly config: ConfigService,
  ) {}

  async generatePairingCode(childId: string, guardianUserId: string) {
    // Verificar que o guardião tem acesso ao filho
    const child = await this.prisma.child.findFirst({
      where: {
        id: childId,
        familyMember: {
          family: {
            members: { some: { userId: guardianUserId } },
          },
        },
      },
    });
    if (!child) throw new NotFoundException('Criança não encontrada');

    // Invalidar codes anteriores
    await this.prisma.devicePairing.updateMany({
      where: { childId, usedAt: null, expiresAt: { gt: new Date() } },
      data: { expiresAt: new Date() },
    });

    // Gerar código numérico de 6 dígitos
    const code = Math.floor(100000 + Math.random() * 900000).toString();
    const expiresAt = new Date();
    expiresAt.setMinutes(expiresAt.getMinutes() + 15);

    const qrPayload = JSON.stringify({
      childId,
      code,
      apiUrl: this.config.get('app.url'),
      v: 1,
    });

    const pairing = await this.prisma.devicePairing.create({
      data: { childId, code, qrPayload, expiresAt },
    });

    const qrCodeDataUrl = await QRCode.toDataURL(qrPayload, {
      errorCorrectionLevel: 'M',
      margin: 2,
      width: 300,
    });

    return {
      code,
      qrCodeDataUrl,
      expiresAt,
      expiresInMinutes: 15,
    };
  }

  async completePairing(
    code: string,
    deviceName: string,
    os: DeviceOS,
    osVersion?: string,
  ) {
    const pairing = await this.prisma.devicePairing.findUnique({
      where: { code },
      include: { child: true },
    });

    if (!pairing) throw new BadRequestException('Código inválido');
    if (pairing.usedAt) throw new BadRequestException('Código já utilizado');
    if (pairing.expiresAt < new Date()) throw new BadRequestException('Código expirado');

    // Gerar token único para o dispositivo
    const deviceToken = uuidv4();

    const device = await this.prisma.$transaction(async (tx) => {
      const newDevice = await tx.device.create({
        data: {
          childId: pairing.childId,
          name: deviceName,
          os,
          osVersion,
          deviceToken,
          isActive: true,
          lastSeenAt: new Date(),
        },
      });

      await tx.devicePairing.update({
        where: { id: pairing.id },
        data: { usedAt: new Date() },
      });

      return newDevice;
    });

    this.logger.log(`Dispositivo pareado: ${device.id} → Criança ${pairing.childId}`);

    return {
      deviceToken,
      deviceId: device.id,
      childId: pairing.childId,
      message: 'Dispositivo pareado com sucesso',
    };
  }
}
