import { and, eq, isNull } from "drizzle-orm";
import { NextResponse } from "next/server";
import { z } from "zod";
import { preLancamentos, tokensApi } from "@/db/schema";
import { extractBearerToken, hashToken } from "@/lib/auth/api-token";
import { db } from "@/lib/db";
import { inboxBatchSchema } from "@/lib/schemas/inbox";

// Rate limiting simples em memória
const rateLimitMap = new Map<string, { count: number; resetAt: number }>();
const RATE_LIMIT = 20; // 20 batch requests
const RATE_WINDOW = 60 * 1000; // por minuto

function checkRateLimit(userId: string): boolean {
	const now = Date.now();
	const userLimit = rateLimitMap.get(userId);

	if (!userLimit || userLimit.resetAt < now) {
		rateLimitMap.set(userId, { count: 1, resetAt: now + RATE_WINDOW });
		return true;
	}

	if (userLimit.count >= RATE_LIMIT) {
		return false;
	}

	userLimit.count++;
	return true;
}

interface BatchResult {
	clientId?: string;
	serverId?: string;
	success: boolean;
	error?: string;
}

export async function POST(request: Request) {
	try {
		// Extrair token do header
		const authHeader = request.headers.get("Authorization");
		const token = extractBearerToken(authHeader);

		if (!token) {
			return NextResponse.json(
				{ error: "Token não fornecido" },
				{ status: 401 },
			);
		}

		// Validar token os_xxx via hash
		if (!token.startsWith("os_")) {
			return NextResponse.json(
				{ error: "Formato de token inválido" },
				{ status: 401 },
			);
		}

		const tokenHash = hashToken(token);

		// Buscar token no banco
		const tokenRecord = await db.query.tokensApi.findFirst({
			where: and(
				eq(tokensApi.tokenHash, tokenHash),
				isNull(tokensApi.revokedAt),
			),
		});

		if (!tokenRecord) {
			return NextResponse.json(
				{ error: "Token inválido ou revogado" },
				{ status: 401 },
			);
		}

		// Rate limiting
		if (!checkRateLimit(tokenRecord.userId)) {
			return NextResponse.json(
				{ error: "Limite de requisições excedido", retryAfter: 60 },
				{ status: 429 },
			);
		}

		// Validar body
		const body = await request.json();
		const { items } = inboxBatchSchema.parse(body);

		// Processar cada item
		const results: BatchResult[] = [];

		for (const item of items) {
			try {
				const [inserted] = await db
					.insert(preLancamentos)
					.values({
						userId: tokenRecord.userId,
						sourceApp: item.sourceApp,
						sourceAppName: item.sourceAppName,
						originalTitle: item.originalTitle,
						originalText: item.originalText,
						notificationTimestamp: item.notificationTimestamp,
						parsedName: item.parsedName,
						parsedAmount: item.parsedAmount?.toString(),
						status: "pending",
					})
					.returning({ id: preLancamentos.id });

				results.push({
					clientId: item.clientId,
					serverId: inserted.id,
					success: true,
				});
			} catch (error) {
				results.push({
					clientId: item.clientId,
					success: false,
					error: error instanceof Error ? error.message : "Erro desconhecido",
				});
			}
		}

		// Atualizar último uso do token
		const clientIp =
			request.headers.get("x-forwarded-for")?.split(",")[0]?.trim() ||
			request.headers.get("x-real-ip") ||
			null;

		await db
			.update(tokensApi)
			.set({
				lastUsedAt: new Date(),
				lastUsedIp: clientIp,
			})
			.where(eq(tokensApi.id, tokenRecord.id));

		const successCount = results.filter((r) => r.success).length;
		const failCount = results.filter((r) => !r.success).length;

		return NextResponse.json(
			{
				message: `${successCount} notificações processadas${failCount > 0 ? `, ${failCount} falharam` : ""}`,
				total: items.length,
				success: successCount,
				failed: failCount,
				results,
			},
			{ status: 201 },
		);
	} catch (error) {
		if (error instanceof z.ZodError) {
			return NextResponse.json(
				{ error: error.issues[0]?.message ?? "Dados inválidos" },
				{ status: 400 },
			);
		}

		console.error("[API] Error creating batch inbox items:", error);
		return NextResponse.json(
			{ error: "Erro ao processar notificações" },
			{ status: 500 },
		);
	}
}
