/**
 * Component: User API Token Routes (self-service)
 * Documentation: documentation/backend/services/api-tokens.md
 */

import { NextRequest, NextResponse } from 'next/server';
import { requireAuth, AuthenticatedRequest } from '@/lib/middleware/auth';
import { prisma } from '@/lib/db';
import { RMABLogger } from '@/lib/utils/logger';
import { checkApiTokenCreateRateLimit } from '@/lib/utils/rateLimit';
import { MAX_TOKENS_PER_USER } from '@/lib/constants/api-tokens';
import { generateApiToken } from '@/lib/utils/api-token';
import { z } from 'zod';

const logger = RMABLogger.create('API.User.ApiTokens');

const CreateTokenSchema = z.object({
  name: z.string().min(1).max(100),
  expiresAt: z.string().datetime().nullable().optional(),
});

/**
 * GET /api/user/api-tokens
 * List the current user's own API tokens
 */
export async function GET(request: NextRequest) {
  return requireAuth(request, async (req: AuthenticatedRequest) => {
    try {
      const tokens = await prisma.apiToken.findMany({
        where: { userId: req.user!.id },
        orderBy: { createdAt: 'desc' },
      });

      const sanitized = tokens.map((t) => ({
        id: t.id,
        name: t.name,
        tokenPrefix: t.tokenPrefix,
        role: t.role,
        lastUsedAt: t.lastUsedAt,
        expiresAt: t.expiresAt,
        createdAt: t.createdAt,
      }));

      return NextResponse.json({ tokens: sanitized });
    } catch (error) {
      logger.error('Failed to list user API tokens', { error: error instanceof Error ? error.message : String(error) });
      return NextResponse.json({ error: 'Failed to list API tokens' }, { status: 500 });
    }
  });
}

/**
 * POST /api/user/api-tokens
 * Create a token for the current user with their own role. Returns full token ONCE.
 */
export async function POST(request: NextRequest) {
  return requireAuth(request, async (req: AuthenticatedRequest) => {
    try {
      const rateLimit = checkApiTokenCreateRateLimit(req.user!.id);
      if (!rateLimit.allowed) {
        return NextResponse.json(
          { error: 'Too many API token create attempts. Please try again later.' },
          {
            status: 429,
            headers: {
              'Retry-After': String(rateLimit.retryAfterSeconds),
            },
          }
        );
      }

      const body = await req.json();
      const { name, expiresAt } = CreateTokenSchema.parse(body);

      // Look up the user's actual role from the database
      const user = await prisma.user.findUnique({
        where: { id: req.user!.id },
        select: { role: true },
      });

      if (!user) {
        return NextResponse.json({ error: 'User not found' }, { status: 404 });
      }

      // Enforce per-user token cap (count only active, non-expired tokens)
      const activeTokenCount = await prisma.apiToken.count({
        where: {
          userId: req.user!.id,
          OR: [
            { expiresAt: null },
            { expiresAt: { gt: new Date() } },
          ],
        },
      });

      if (activeTokenCount >= MAX_TOKENS_PER_USER) {
        return NextResponse.json(
          { error: `Token limit reached. Users may have at most ${MAX_TOKENS_PER_USER} active API tokens.` },
          { status: 403 }
        );
      }

      // Generate the token
      const { fullToken, tokenHash, tokenPrefix } = generateApiToken();

      const apiToken = await prisma.apiToken.create({
        data: {
          name,
          tokenHash,
          tokenPrefix,
          role: user.role, // Always the user's own role
          createdById: req.user!.id,
          userId: req.user!.id, // Token acts as the current user
          expiresAt: expiresAt ? new Date(expiresAt) : null,
        },
      });

      logger.info('User API token created', { tokenId: apiToken.id, name, userId: req.user!.id });

      return NextResponse.json({
        token: {
          id: apiToken.id,
          name: apiToken.name,
          tokenPrefix: apiToken.tokenPrefix,
          role: apiToken.role,
          expiresAt: apiToken.expiresAt,
          createdAt: apiToken.createdAt,
        },
        fullToken,
      }, { status: 201 });
    } catch (error) {
      logger.error('Failed to create user API token', { error: error instanceof Error ? error.message : String(error) });

      if (error instanceof z.ZodError) {
        return NextResponse.json({ error: 'Validation error', details: error.errors }, { status: 400 });
      }

      return NextResponse.json({ error: 'Failed to create API token' }, { status: 500 });
    }
  });
}
