import { NextRequest, NextResponse } from 'next/server';
import { stat } from 'fs/promises';
import { createReadStream } from 'fs';
import path from 'path';

export async function GET(
    request: NextRequest,
    { params }: { params: Promise<{ filename: string }> }
) {
    try {
        const { filename } = await params;

        // Security: Prevent path traversal attacks
        // Only allow alphanumeric, hyphens, underscores, and dots
        const safeFilenamePattern = /^[a-zA-Z0-9_\-\.]+\.mp3$/;
        if (!safeFilenamePattern.test(filename)) {
            return new NextResponse('Invalid filename', { status: 400 });
        }

        // Additional check: ensure no path separators
        if (filename.includes('/') || filename.includes('\\') || filename.includes('..')) {
            return new NextResponse('Invalid filename', { status: 400 });
        }

        const filePath = path.join(process.cwd(), 'public/uploads', filename);

        // Security: Verify the resolved path is still within uploads directory
        const uploadsDir = path.join(process.cwd(), 'public/uploads');
        const resolvedPath = path.resolve(filePath);
        if (!resolvedPath.startsWith(uploadsDir)) {
            return new NextResponse('Forbidden', { status: 403 });
        }

        const stats = await stat(filePath);
        const fileSize = stats.size;
        const range = request.headers.get('range');

        if (range) {
            const parts = range.replace(/bytes=/, "").split("-");
            const start = parseInt(parts[0], 10);
            const end = parts[1] ? parseInt(parts[1], 10) : fileSize - 1;
            const chunksize = (end - start) + 1;

            const stream = createReadStream(filePath, { start, end });

            // Convert Node stream to Web stream

            const readable = new ReadableStream({
                start(controller) {
                    let isClosed = false;

                    stream.on('data', (chunk: any) => {
                        if (isClosed) return;
                        try {
                            controller.enqueue(chunk);
                        } catch (e) {
                            isClosed = true;
                            stream.destroy();
                        }
                    });

                    stream.on('end', () => {
                        if (isClosed) return;
                        isClosed = true;
                        controller.close();
                    });

                    stream.on('error', (err: any) => {
                        if (isClosed) return;
                        isClosed = true;
                        controller.error(err);
                    });
                },
                cancel() {
                    stream.destroy();
                }
            });

            return new NextResponse(readable, {
                status: 206,
                headers: {
                    'Content-Range': `bytes ${start}-${end}/${fileSize}`,
                    'Accept-Ranges': 'bytes',
                    'Content-Length': chunksize.toString(),
                    'Content-Type': 'audio/mpeg',
                    'Cache-Control': 'public, max-age=3600, must-revalidate',
                },
            });
        } else {
            const stream = createReadStream(filePath);

            // Convert Node stream to Web stream
            const readable = new ReadableStream({
                start(controller) {
                    let isClosed = false;

                    stream.on('data', (chunk: any) => {
                        if (isClosed) return;
                        try {
                            controller.enqueue(chunk);
                        } catch (e) {
                            isClosed = true;
                            stream.destroy();
                        }
                    });

                    stream.on('end', () => {
                        if (isClosed) return;
                        isClosed = true;
                        controller.close();
                    });

                    stream.on('error', (err: any) => {
                        if (isClosed) return;
                        isClosed = true;
                        controller.error(err);
                    });
                },
                cancel() {
                    stream.destroy();
                }
            });

            return new NextResponse(readable, {
                status: 200,
                headers: {
                    'Content-Length': fileSize.toString(),
                    'Content-Type': 'audio/mpeg',
                    'Accept-Ranges': 'bytes',
                    'Cache-Control': 'public, max-age=3600, must-revalidate',
                },
            });
        }
    } catch (error) {
        console.error('Error serving audio file:', error);
        return new NextResponse('Internal Server Error', { status: 500 });
    }
}
