import { Injectable } from '@nestjs/common';
import { SessionStatus } from '../generated/prisma/client';
import { PrismaService } from '../infra/prisma.service';

@Injectable()
export class SecurityService {
  constructor(private readonly prisma: PrismaService) {}

  async listActiveDevices(userId: string, exceptSessionId?: string) {
    let exceptDeviceId: string | undefined;
    if (exceptSessionId) {
      const currentSession = await this.prisma.session.findFirst({
        where: { id: exceptSessionId, userId },
        select: { deviceId: true }
      });
      exceptDeviceId = currentSession?.deviceId ?? undefined;
    }

    const devices = await this.prisma.device.findMany({
      where: {
        userId,
        ...(exceptDeviceId ? { id: { not: exceptDeviceId } } : {})
      },
      orderBy: { lastSeenAt: 'desc' },
      include: {
        sessions: {
          where: { status: { in: [SessionStatus.ACTIVE, SessionStatus.LOCKED] } },
          orderBy: { updatedAt: 'desc' }
        }
      }
    });

    return devices.filter((device) => device.sessions.length > 0);
  }

  async listActiveSessions(userId: string) {
    return this.prisma.session.findMany({
      where: { userId, status: { in: [SessionStatus.ACTIVE, SessionStatus.LOCKED] } },
      orderBy: { updatedAt: 'desc' },
      include: { device: true }
    });
  }

  async listSignInHistory(userId: string) {
    return this.prisma.signInEvent.findMany({
      where: { userId },
      orderBy: { createdAt: 'desc' },
      take: 100,
      include: { device: true }
    });
  }

  async revokeSession(userId: string, sessionId: string) {
    return this.prisma.session.update({
      where: { id: sessionId, userId },
      data: { status: SessionStatus.REVOKED }
    });
  }

  async lockSession(userId: string, sessionId: string) {
    return this.prisma.session.update({
      where: { id: sessionId, userId },
      data: { status: SessionStatus.LOCKED, pinVerified: false }
    });
  }

  async revokeDevice(userId: string, deviceId: string) {
    return this.prisma.session.updateMany({
      where: { userId, deviceId, status: { in: [SessionStatus.ACTIVE, SessionStatus.LOCKED] } },
      data: { status: SessionStatus.REVOKED }
    });
  }

  async revokeAllSessions(userId: string, exceptSessionId?: string) {
    return this.prisma.session.updateMany({
      where: {
        userId,
        status: { in: [SessionStatus.ACTIVE, SessionStatus.LOCKED] },
        ...(exceptSessionId ? { id: { not: exceptSessionId } } : {})
      },
      data: { status: SessionStatus.REVOKED }
    });
  }

  async connectSocialAccount(userId: string, data: { providerName: string; providerId: string; email?: string; displayName?: string; avatarUrl?: string }) {
    return this.prisma.linkedAccount.upsert({
      where: { providerName_providerId: { providerName: data.providerName, providerId: data.providerId } },
      create: { userId, ...data },
      update: { email: data.email, displayName: data.displayName, avatarUrl: data.avatarUrl }
    });
  }

  async disconnectSocialAccount(userId: string, providerName: string) {
    return this.prisma.linkedAccount.deleteMany({
      where: { userId, providerName }
    });
  }

  async listLinkedAccounts(userId: string) {
    return this.prisma.linkedAccount.findMany({
      where: { userId },
      orderBy: { providerName: 'asc' }
    });
  }
}
