import { NextResponse } from 'next/server';
import fs from 'fs-extra';
import path from 'path';
import { execFile } from 'child_process';
import util from 'util';
import { getSpectrogramsPath, ensureSpectrogramsDir } from '@/lib/utils/paths';
import { AnalysisTrack, SpectrogramResponse } from '@/types';

const execFileAsync = util.promisify(execFile);

export async function POST(request: Request) {
    try {
        const { albumPath, tracks, upc } = await request.json();

        if (!albumPath || !tracks || !Array.isArray(tracks)) {
            return NextResponse.json({ error: 'Invalid request' }, { status: 400 });
        }

        const specRoot = await ensureSpectrogramsDir();
        // Use UPC if available, otherwise fallback to album directory name
        const albumId = upc || path.basename(albumPath);
        const albumSpecDir = path.join(specRoot, albumId);

        await fs.ensureDir(albumSpecDir);

        const results: Record<string, { exists: boolean, url?: string }> = {};

        // Process tracks
        // We use Promise.all to process in parallel. 
        // If this causes performance issues with sox, we might need to limit concurrency.
        await Promise.all(tracks.map(async (track: AnalysisTrack) => {
            if ('error' in track) return;

            const trackNo = track.common?.track?.no;
            if (trackNo === undefined || trackNo === null) return;

            const outputFilename = `${trackNo}.png`;
            const outputPath = path.join(albumSpecDir, outputFilename);
            const relativePath = path.join(albumId, outputFilename);
            const publicUrl = `/api/spectrogram?path=${encodeURIComponent(relativePath)}`;

            const exists = await fs.pathExists(outputPath);

            if (!exists) {
                // Generate
                const title = `${trackNo} - ${track.common?.title || track.filename}`;

                const args = [
                    track.path,
                    '-n',
                ];

                if (process.env.GENERATE_MONO_SPECTROGRAMS) {
                    args.push('remix', '1');
                }

                args.push(
                    'spectrogram',
                    '-t', title,
                    '-o', outputPath
                );

                try {
                    await execFileAsync('sox', args);
                    results[track.filename] = { exists: true, url: publicUrl };
                } catch (e) {
                    console.error(`Failed to generate spectrogram for ${track.filename}:`, e);
                    results[track.filename] = { exists: false };
                }
            } else {
                results[track.filename] = { exists: true, url: publicUrl };
            }
        }));

        return NextResponse.json({ results });

    } catch (error) {
        console.error('Error generating spectrograms:', error);
        return NextResponse.json({ error: 'Failed to generate spectrograms' }, { status: 500 });
    }
}

export async function DELETE() {
    try {
        const specPath = getSpectrogramsPath();
        await fs.remove(specPath);
        await fs.ensureDir(specPath);
        return NextResponse.json({ success: true });
    } catch (error) {
        console.error('Error purging spectrograms:', error);
        return NextResponse.json({ error: 'Failed to purge spectrograms' }, { status: 500 });
    }
}

export async function GET(request: Request) {
    const { searchParams } = new URL(request.url);
    const relativePath = searchParams.get('path');

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

    const specRoot = getSpectrogramsPath();
    const fullPath = path.join(specRoot, relativePath);

    // Security check: ensure fullPath is within specRoot (prevent directory traversal)
    const resolvedPath = path.resolve(fullPath);
    const resolvedRoot = path.resolve(specRoot);

    if (!resolvedPath.startsWith(resolvedRoot)) {
        return NextResponse.json({ error: 'Access denied' }, { status: 403 });
    }

    if (!await fs.pathExists(resolvedPath)) {
        return NextResponse.json({ error: 'File not found' }, { status: 404 });
    }

    const fileBuffer = await fs.readFile(resolvedPath);

    return new NextResponse(fileBuffer, {
        headers: {
            'Content-Type': 'image/png',
            'Cache-Control': 'public, max-age=31536000, immutable',
        },
    });
}
