import { createHash } from 'crypto';
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { Strategy } from 'passport-custom';
import type { Request } from 'express';
import { PrismaService } from '../../prisma/prisma.service';
import { ApiKeyPrincipal } from '../principal';

export const API_KEY_HEADER = 'x-api-key';
export const API_KEY_PREFIX = 'ulh_';

export function hashApiKey(key: string): string {
  return createHash('sha256').update(key).digest('hex');
}

@Injectable()
export class ApiKeyStrategy extends PassportStrategy(Strategy, 'api-key') {
  constructor(private readonly prisma: PrismaService) {
    super();
  }

  async validate(req: Request): Promise<ApiKeyPrincipal> {
    const key = req.headers[API_KEY_HEADER];
    if (typeof key !== 'string' || !key.startsWith(API_KEY_PREFIX)) {
      throw new UnauthorizedException('Missing or malformed API key');
    }

    const record = await this.prisma.apiKey.findUnique({ where: { keyHash: hashApiKey(key) } });
    if (!record || record.revokedAt || (record.expiresAt && record.expiresAt < new Date())) {
      throw new UnauthorizedException('Invalid API key');
    }

    // fire-and-forget usage stamp; never block the request on it
    this.prisma.apiKey
      .update({ where: { id: record.id }, data: { lastUsedAt: new Date() } })
      .catch(() => undefined);

    return { type: 'apiKey', apiKeyId: record.id, orgId: record.orgId, scopes: record.scopes };
  }
}
