import { Injectable, NotFoundException, UnauthorizedException, Logger } from '@nestjs/common';
import { PrismaService } from '../../database/prisma.service';

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

  constructor(private readonly prisma: PrismaService) {}

  /** Autenticar dispositivo via token (chamado pelo app do filho) */
  async authenticateDevice(deviceToken: string) {
    const device = await this.prisma.device.findUnique({
      where: { deviceToken },
      include: {
        child: {
          include: {
            familyMember: { include: { user: true } },
            policy: {
              include: { appLimits: true, catLimits: true, schedules: true, routineRules: true },
            },
            timeWallet: true,
          },
        },
      },
    });

    if (!device || !device.isActive) {
      throw new UnauthorizedException('Dispositivo não reconhecido');
    }

    await this.prisma.device.update({
      where: { id: device.id },
      data: { lastSeenAt: new Date() },
    });

    return {
      deviceId: device.id,
      childId: device.childId,
      childName: device.child.familyMember.user.name,
      policy: device.child.policy,
      wallet: device.child.timeWallet,
    };
  }

  /** Sync: device informa versão atual e recebe delta se necessário */
  async syncDevice(deviceId: string, currentPolicyVersion: number) {
    const device = await this.prisma.device.findUnique({
      where: { id: deviceId },
      include: {
        child: {
          include: {
            policy: {
              include: { appLimits: true, catLimits: true, schedules: true, routineRules: true },
            },
            timeWallet: true,
          },
        },
      },
    });

    if (!device) throw new NotFoundException('Dispositivo não encontrado');

    const serverVersion = device.child.policy?.version ?? 0;
    const needsUpdate = serverVersion > currentPolicyVersion;

    await this.prisma.device.update({
      where: { id: deviceId },
      data: { lastSyncAt: new Date(), policyVersion: serverVersion },
    });

    return {
      deviceId,
      serverTime: new Date().toISOString(),
      policyVersion: serverVersion,
      needsUpdate,
      policy: needsUpdate ? device.child.policy : null,
      wallet: device.child.timeWallet,
    };
  }

  /** Registrar apps instalados no dispositivo */
  async reportInstalledApps(
    deviceId: string,
    apps: Array<{ packageName: string; appName: string; isSystem?: boolean }>,
  ) {
    for (const app of apps) {
      await this.prisma.installedApp.upsert({
        where: { deviceId_packageName: { deviceId, packageName: app.packageName } },
        create: { deviceId, ...app },
        update: { appName: app.appName },
      });
    }
    return { synced: apps.length };
  }

  /** Registrar evento de sync (offline → online) */
  async pushSyncEvents(
    deviceId: string,
    events: Array<{ eventType: string; payload: any; occurredAt: string }>,
  ) {
    await this.prisma.syncEvent.createMany({
      data: events.map((e) => ({
        deviceId,
        eventType: e.eventType,
        payload: e.payload,
      })),
    });
    return { received: events.length };
  }

  async getDevicesForChild(childId: string) {
    return this.prisma.device.findMany({
      where: { childId },
      select: {
        id: true, name: true, os: true, osVersion: true,
        appVersion: true, isActive: true, lastSeenAt: true, lastSyncAt: true,
      },
    });
  }

  async deactivateDevice(deviceId: string) {
    return this.prisma.device.update({
      where: { id: deviceId },
      data: { isActive: false },
    });
  }

  async updateFcmToken(deviceId: string, fcmToken: string) {
    return this.prisma.device.update({
      where: { id: deviceId },
      data: { fcmToken },
    });
  }
}
