import { NextRequest, NextResponse } from 'next/server';
export const dynamic = 'force-dynamic';
import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
import { DynamoDBDocumentClient, BatchWriteCommand, QueryCommand } from '@aws-sdk/lib-dynamodb';
import { revalidatePath } from 'next/cache';
import { logger } from '@claw/core/lib/logger';
import { getTraceTableName } from '@claw/core/lib/utils/ddb-client';
import { getUserId } from '@/lib/auth-utils';
import { HTTP_STATUS } from '@claw/core/lib/constants';

/**
 * Handles trace deletion (single or all) with robust throttling management and multi-tenant isolation.
 *
 * @param req - The incoming DELETE request with traceId query parameter.
 */
export async function DELETE(req: NextRequest): Promise<NextResponse> {
  try {
    const userId = getUserId(req);
    const { searchParams } = new URL(req.url);
    const traceId = searchParams.get('traceId');
    const workspaceId =
      searchParams.get('workspaceId') || req.headers.get('x-workspace-id') || 'default';

    if (!traceId) {
      return NextResponse.json({ error: 'Missing traceId' }, { status: 400 });
    }

    const { getIdentityManager, Permission } = await import('@claw/core/lib/session/identity');
    const identityManager = await getIdentityManager();

    // Verify delete permission
    const hasPermission = await identityManager.hasPermission(
      userId,
      Permission.AGENT_DELETE,
      workspaceId
    );
    if (!hasPermission) {
      return NextResponse.json(
        { error: 'Unauthorized to delete traces' },
        { status: HTTP_STATUS.FORBIDDEN }
      );
    }

    const tableName = getTraceTableName();
    if (!tableName) {
      logger.error('[Trace API] TraceTable not found in resources');
      return NextResponse.json({ error: 'TraceTable not found' }, { status: 500 });
    }

    const client = new DynamoDBClient({});
    const docClient = DynamoDBDocumentClient.from(client, {
      marshallOptions: {
        removeUndefinedValues: true,
      },
    });

    if (traceId === 'all') {
      logger.info(
        `[Trace API] Purging all traces for workspace ${workspaceId} from table: ${tableName}`
      );
      let deletedCount = 0;
      let lastKey: Record<string, unknown> | undefined;

      try {
        do {
          const scanRes = await docClient.send(
            new QueryCommand({
              TableName: tableName,
              IndexName: 'WorkspaceSummaryIndex',
              ExclusiveStartKey: lastKey,
              KeyConditionExpression: 'workspaceId = :ws',
              ExpressionAttributeValues: {
                ':ws': workspaceId,
              },
              Limit: 50,
            })
          );

          if (scanRes.Items && scanRes.Items.length > 0) {
            logger.info(`[Trace API] Processing ${scanRes.Items.length} trace nodes for deletion`);

            // Group into batches of 25 (DynamoDB limit for BatchWrite)
            for (let i = 0; i < scanRes.Items.length; i += 25) {
              const batch = scanRes.Items.slice(i, i + 25);
              let requestItems: import('@claw/core/lib/types/common').DynamoDBBatchWriteRequest = {
                [tableName]: batch.map((item) => ({
                  DeleteRequest: {
                    Key: { traceId: item.traceId, nodeId: item.nodeId },
                  },
                })),
              };

              // Retry loop for Throttling or UnprocessedItems
              let retries = 0;
              const maxRetries = 5;

              while (requestItems[tableName].length > 0 && retries < maxRetries) {
                try {
                  const result = await docClient.send(
                    new BatchWriteCommand({
                      RequestItems: requestItems,
                    })
                  );

                  // Update deletedCount for what actually worked
                  const attemptedCount = requestItems[tableName].length;
                  const unprocessedCount = result.UnprocessedItems?.[tableName]?.length ?? 0;
                  deletedCount += attemptedCount - unprocessedCount;

                  // Set unprocessed items for the next retry attempt
                  if (unprocessedCount > 0) {
                    logger.warn(`[Trace API] Retrying ${unprocessedCount} unprocessed items...`);
                    requestItems =
                      (result.UnprocessedItems as import('@claw/core/lib/types/common').DynamoDBBatchWriteRequest) ??
                      {};
                    retries++;
                    await new Promise((r) => setTimeout(r, Math.pow(2, retries) * 100)); // Exponential backoff
                  } else {
                    requestItems[tableName] = []; // All done
                  }
                } catch (err: unknown) {
                  const errorMsg = err instanceof Error ? err.name : String(err);
                  if (
                    errorMsg === 'ThrottlingException' ||
                    (err as { __type?: string }).__type?.includes('ThrottlingException')
                  ) {
                    logger.warn(`[Trace API] Throttled. Retrying attempt ${retries + 1}...`);
                    retries++;
                    await new Promise((r) => setTimeout(r, Math.pow(2, retries) * 200)); // More aggressive backoff
                  } else {
                    throw err; // Real error
                  }
                }
              }

              if (retries >= maxRetries && requestItems[tableName].length > 0) {
                logger.error(
                  '[Trace API] Max retries reached for batch. Skipping remaining items in this chunk.'
                );
              }

              // Constant delay between batches to keep throughput smooth
              await new Promise((resolve) => setTimeout(resolve, 250));
            }
          }
          lastKey = scanRes.LastEvaluatedKey;
        } while (lastKey);

        logger.info(
          `[Trace API] Successfully purged ${deletedCount} trace nodes for workspace ${workspaceId}`
        );
        revalidatePath('/trace');
        return NextResponse.json({ success: true, count: deletedCount });
      } catch (scanError: unknown) {
        logger.error('[Trace API] Error during scan/delete loop:', scanError);
        throw scanError;
      }
    }

    logger.info(`[Trace API] Deleting all nodes for trace: ${traceId} in workspace ${workspaceId}`);

    // 1. Query all nodes for this traceId and verify workspaceId
    const { Items } = await docClient.send(
      new QueryCommand({
        TableName: tableName,
        KeyConditionExpression: 'traceId = :tid',
        FilterExpression: 'workspaceId = :ws',
        ExpressionAttributeValues: { ':tid': traceId, ':ws': workspaceId },
        ProjectionExpression: 'traceId, nodeId',
      })
    );

    if (Items && Items.length > 0) {
      // 2. Delete all found nodes
      for (let i = 0; i < Items.length; i += 25) {
        const batch = Items.slice(i, i + 25);
        await docClient.send(
          new BatchWriteCommand({
            RequestItems: {
              [tableName]: batch.map((item) => ({
                DeleteRequest: {
                  Key: { traceId: item.traceId, nodeId: item.nodeId },
                },
              })),
            },
          })
        );
      }
      logger.info(`[Trace API] Successfully deleted ${Items.length} nodes for trace ${traceId}`);
    } else {
      logger.warn(`[Trace API] No nodes found for traceId ${traceId} in workspace ${workspaceId}`);
      // If no nodes found with the filter, double check if it exists at all to provide better error
      const { Count } = await docClient.send(
        new QueryCommand({
          TableName: tableName,
          KeyConditionExpression: 'traceId = :tid',
          ExpressionAttributeValues: { ':tid': traceId },
          Select: 'COUNT',
        })
      );
      if (Count && Count > 0) {
        return NextResponse.json(
          { error: 'Trace belongs to another workspace' },
          { status: HTTP_STATUS.FORBIDDEN }
        );
      }
    }

    revalidatePath('/trace');
    return NextResponse.json({ success: true });
  } catch (error: unknown) {
    logger.error('[Trace API] Critical failure:', error);
    const message = error instanceof Error ? error.message : String(error);
    return NextResponse.json(
      {
        error: message,
        details: error instanceof Error ? error.stack : undefined,
      },
      { status: 500 }
    );
  }
}
