import { NextRequest, NextResponse } from 'next/server';
import { PrismaClient } from '@prisma/client';
import { rateLimit } from '@/lib/rateLimit';

const prisma = new PrismaClient();

export async function POST(request: NextRequest) {
    // Rate limiting: 3 requests per minute
    const rateLimitError = rateLimit(request, { windowMs: 60000, maxRequests: 3 });
    if (rateLimitError) return rateLimitError;

    try {
        const { puzzleId, genreId, message, playerIdentifier, originalMessage } = await request.json();

        // Validate required fields
        if (!puzzleId || !message || !playerIdentifier) {
            return NextResponse.json(
                { error: 'puzzleId, message, and playerIdentifier are required' },
                { status: 400 }
            );
        }

        // Message validation: max 2000 characters, no empty message
        const trimmedMessage = message.trim();
        if (trimmedMessage.length === 0) {
            return NextResponse.json(
                { error: 'Message cannot be empty' },
                { status: 400 }
            );
        }
        if (trimmedMessage.length > 300) {
            return NextResponse.json(
                { error: 'Message too long. Maximum 300 characters allowed.' },
                { status: 400 }
            );
        }

        // PlayerIdentifier validation: Check if it exists in PlayerState
        const playerState = await prisma.playerState.findFirst({
            where: {
                identifier: playerIdentifier
            }
        });

        if (!playerState) {
            return NextResponse.json(
                { error: 'Invalid player identifier' },
                { status: 400 }
            );
        }

        // Puzzle validation: Check if puzzle exists and matches genreId
        const puzzle = await prisma.dailyPuzzle.findUnique({
            where: { id: Number(puzzleId) },
            include: {
                song: true
            }
        });

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

        // Validate genreId matches puzzle (if genreId is provided)
        if (genreId !== null && genreId !== undefined) {
            if (puzzle.genreId !== Number(genreId)) {
                return NextResponse.json(
                    { error: 'Puzzle does not match the provided genre' },
                    { status: 400 }
                );
            }
        } else {
            // If no genreId provided, use puzzle's genreId
            // For global puzzles, genreId is null
        }

        // Rate limit check: Check if comment already exists for this playerIdentifier + puzzleId
        const existingComment = await prisma.curatorComment.findUnique({
            where: {
                playerIdentifier_puzzleId: {
                    playerIdentifier: playerIdentifier,
                    puzzleId: Number(puzzleId)
                }
            }
        });

        if (existingComment) {
            return NextResponse.json(
                { error: 'You have already sent a comment for this puzzle' },
                { status: 429 }
            );
        }

        // Determine responsible curators
        const finalGenreId = genreId !== null && genreId !== undefined ? Number(genreId) : puzzle.genreId;
        const specialId = puzzle.specialId;

        let curatorIds: number[] = [];
        const allCuratorIds = new Set<number>();

        // Get all global curators (always included)
        const globalCurators = await prisma.curator.findMany({
            where: {
                isGlobalCurator: true
            },
            select: {
                id: true
            }
        });
        globalCurators.forEach(gc => allCuratorIds.add(gc.id));

        // Check for special puzzle first (takes precedence)
        if (specialId !== null) {
            // Special puzzle: Get curators for this special + all global curators
            const specialCurators = await prisma.curatorSpecial.findMany({
                where: {
                    specialId: specialId
                },
                select: {
                    curatorId: true
                }
            });
            specialCurators.forEach(cs => allCuratorIds.add(cs.curatorId));
        } else if (finalGenreId !== null) {
            // Genre puzzle: Get curators for this genre + all global curators
            const genreCurators = await prisma.curatorGenre.findMany({
                where: {
                    genreId: finalGenreId
                },
                select: {
                    curatorId: true
                }
            });
            genreCurators.forEach(cg => allCuratorIds.add(cg.curatorId));
        }
        // else: Global puzzle - only global curators (already added above)

        curatorIds = Array.from(allCuratorIds);

        if (curatorIds.length === 0) {
            return NextResponse.json(
                { error: 'No curators found for this puzzle' },
                { status: 500 }
            );
        }

        // Create comment and recipients in a transaction
        const result = await prisma.$transaction(async (tx) => {
            // Create the comment
            const comment = await tx.curatorComment.create({
                data: {
                    playerIdentifier: playerIdentifier,
                    puzzleId: Number(puzzleId),
                    genreId: finalGenreId,
                    message: trimmedMessage
                }
            });

            // Create recipients for all curators
            await tx.curatorCommentRecipient.createMany({
                data: curatorIds.map(curatorId => ({
                    commentId: comment.id,
                    curatorId: curatorId
                }))
            });

            return comment;
        });

        // Send Gotify notification (fire and forget)
        const { sendCommentNotification } = await import('@/app/actions');
        // originalMessage is already available from the initial request.json() call

        // Determine genre name for notification
        let genreName: string | null = null;
        if (finalGenreId) {
            const genreObj = await prisma.genre.findUnique({ where: { id: finalGenreId } });
            if (genreObj) genreName = genreObj.name as string;
        }

        sendCommentNotification(Number(puzzleId), trimmedMessage, originalMessage, genreName || null);

        return NextResponse.json({
            success: true,
            commentId: result.id
        });
    } catch (error) {
        console.error('Error creating curator comment:', error);

        // Handle unique constraint violation (shouldn't happen due to our check, but just in case)
        if (error instanceof Error && error.message.includes('Unique constraint')) {
            return NextResponse.json(
                { error: 'You have already sent a comment for this puzzle' },
                { status: 429 }
            );
        }

        return NextResponse.json(
            { error: 'Internal Server Error' },
            { status: 500 }
        );
    }
}

