import { randomBytes } from 'crypto';
import { Injectable, NotFoundException } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import { API_KEY_PREFIX, hashApiKey } from '../auth/strategies/api-key.strategy';
import { CreateApiKeyDto } from './dto/api-keys.dto';

const KEY_SELECT = {
  id: true,
  name: true,
  keyPrefix: true,
  scopes: true,
  expiresAt: true,
  lastUsedAt: true,
  revokedAt: true,
  createdAt: true,
  createdBy: { select: { id: true, name: true, email: true } },
};

function generateKey(): string {
  // ulh_ + 40 chars base62
  const alphabet = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
  const bytes = randomBytes(40);
  let suffix = '';
  for (let i = 0; i < 40; i++) {
    suffix += alphabet[bytes[i] % alphabet.length];
  }
  return API_KEY_PREFIX + suffix;
}

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

  list(orgId: string) {
    return this.prisma.apiKey.findMany({
      where: { orgId },
      select: KEY_SELECT,
      orderBy: { createdAt: 'desc' },
    });
  }

  async create(orgId: string, dto: CreateApiKeyDto, createdById: string) {
    const key = generateKey();
    const record = await this.prisma.apiKey.create({
      data: {
        orgId,
        name: dto.name,
        keyPrefix: key.slice(0, 12),
        keyHash: hashApiKey(key),
        scopes: dto.scopes,
        expiresAt: dto.expiresAt ? new Date(dto.expiresAt) : undefined,
        createdById,
      },
      select: KEY_SELECT,
    });
    // The plaintext key is returned exactly once; only the hash is stored.
    return { ...record, key };
  }

  async revoke(orgId: string, keyId: string) {
    const record = await this.prisma.apiKey.findFirst({ where: { id: keyId, orgId } });
    if (!record) {
      throw new NotFoundException('API key not found');
    }
    await this.prisma.apiKey.update({
      where: { id: keyId },
      data: { revokedAt: record.revokedAt ?? new Date() },
    });
    return { ok: true };
  }
}
