import { PrismaClient, Genre, Special } from '@prisma/client';
import { getTodayISOString } from './dateUtils';

const prisma = new PrismaClient();

export async function getOrCreateDailyPuzzle(genre: Genre | null = null) {
    try {
        const today = getTodayISOString();
        let genreId: number | null = null;

        if (genre) {
            genreId = genre.id;
        }

        let dailyPuzzle = await prisma.dailyPuzzle.findFirst({
            where: {
                date: today,
                genreId: genreId
            },
            include: { song: true },
        });

        if (!dailyPuzzle) {
            // Get songs available for this genre
            const whereClause = genreId
                ? { genres: { some: { id: genreId } } }
                : { excludeFromGlobal: false }; // Global puzzle picks from ALL songs (except excluded)

            const allSongs = await prisma.song.findMany({
                where: whereClause,
                include: {
                    puzzles: true, // Load ALL puzzles, not just for this genre (to use total activations)
                },
            });

            if (allSongs.length === 0) {
                console.log(`[Daily Puzzle] No songs available for genre: ${genre ? JSON.stringify(genre.name) : 'Global'}`);
                return null;
            }

            // Find songs with the minimum number of activations (all puzzles, not just for this genre)
            // Only select from songs with the fewest activations to ensure fair distribution
            const songsWithActivations = allSongs.map(song => ({
                song,
                activations: song.puzzles.length,
            }));

            // Find minimum activations
            const minActivations = Math.min(...songsWithActivations.map(item => item.activations));

            // Filter to only songs with minimum activations
            const songsWithMinActivations = songsWithActivations
                .filter(item => item.activations === minActivations)
                .map(item => item.song);

            // Randomly select from songs with minimum activations
            const randomIndex = Math.floor(Math.random() * songsWithMinActivations.length);
            const selectedSong = songsWithMinActivations[randomIndex];

            // Create the daily puzzle
            try {
                dailyPuzzle = await prisma.dailyPuzzle.create({
                    data: {
                        date: today,
                        songId: selectedSong.id,
                        genreId: genreId
                    },
                    include: { song: true },
                });
                console.log(`[Daily Puzzle] Created new puzzle for ${today} (Genre: ${genre ? JSON.stringify(genre.name) : 'Global'}) with song: ${selectedSong.title}`);
            } catch (e) {
                // Handle race condition
                console.log('[Daily Puzzle] Creation failed, trying to fetch again (likely race condition)');
                dailyPuzzle = await prisma.dailyPuzzle.findFirst({
                    where: {
                        date: today,
                        genreId: genreId
                    },
                    include: { song: true },
                });
            }
        }

        if (!dailyPuzzle) return null;

        // Calculate puzzle number (sequential day count)
        const whereClause = genreId
            ? { genreId: genreId }
            : { genreId: null, specialId: null };

        const puzzleCount = await prisma.dailyPuzzle.count({
            where: {
                ...whereClause,
                date: {
                    lte: dailyPuzzle.date
                }
            }
        });

        return {
            id: dailyPuzzle.id,
            puzzleNumber: puzzleCount,
            audioUrl: `/api/audio/${dailyPuzzle.song.filename}`,
            songId: dailyPuzzle.songId,
            title: dailyPuzzle.song.title,
            artist: dailyPuzzle.song.artist,
            coverImage: dailyPuzzle.song.coverImage ? `/uploads/covers/${dailyPuzzle.song.coverImage}` : null,
            releaseYear: dailyPuzzle.song.releaseYear,
            genre: genre ? genre.name : null
        };

    } catch (error) {
        console.error('Error in getOrCreateDailyPuzzle:', error);
        return null;
    }
}

export async function getOrCreateSpecialPuzzle(special: Special) {
    try {
        const today = getTodayISOString();

        let dailyPuzzle = await prisma.dailyPuzzle.findFirst({
            where: {
                date: today,
                specialId: special.id
            },
            include: { song: true },
        });

        if (!dailyPuzzle) {
            // Get songs available for this special through SpecialSong
            const specialSongs = await prisma.specialSong.findMany({
                where: { specialId: special.id },
                include: {
                    song: {
                        include: {
                            puzzles: {
                                where: { specialId: special.id } // For specials, only count puzzles within this special
                            }
                        }
                    }
                }
            });

            if (specialSongs.length === 0) return null;

            // Find songs with the minimum number of activations within this special
            // Note: For specials, we only count puzzles within the special (not all puzzles),
            // since specials are curated, separate lists
            const songsWithActivations = specialSongs.map(specialSong => ({
                specialSong,
                activations: specialSong.song.puzzles.length,
            }));

            // Find minimum activations
            const minActivations = Math.min(...songsWithActivations.map(item => item.activations));

            // Filter to only songs with minimum activations
            const songsWithMinActivations = songsWithActivations
                .filter(item => item.activations === minActivations)
                .map(item => item.specialSong);

            // Randomly select from songs with minimum activations
            const randomIndex = Math.floor(Math.random() * songsWithMinActivations.length);
            const selectedSpecialSong = songsWithMinActivations[randomIndex];

            try {
                dailyPuzzle = await prisma.dailyPuzzle.create({
                    data: {
                        date: today,
                        songId: selectedSpecialSong.songId,
                        specialId: special.id
                    },
                    include: { song: true },
                });
            } catch (e) {
                dailyPuzzle = await prisma.dailyPuzzle.findFirst({
                    where: {
                        date: today,
                        specialId: special.id
                    },
                    include: { song: true },
                });
            }
        }

        if (!dailyPuzzle) return null;

        // Fetch the startTime from SpecialSong
        const specialSong = await prisma.specialSong.findUnique({
            where: {
                specialId_songId: {
                    specialId: special.id,
                    songId: dailyPuzzle.songId
                }
            }
        });

        // Calculate puzzle number
        const puzzleCount = await prisma.dailyPuzzle.count({
            where: {
                specialId: special.id,
                date: {
                    lte: dailyPuzzle.date
                }
            }
        });

        return {
            id: dailyPuzzle.id,
            puzzleNumber: puzzleCount,
            audioUrl: `/api/audio/${dailyPuzzle.song.filename}`,
            songId: dailyPuzzle.songId,
            title: dailyPuzzle.song.title,
            artist: dailyPuzzle.song.artist,
            coverImage: dailyPuzzle.song.coverImage ? `/uploads/covers/${dailyPuzzle.song.coverImage}` : null,
            releaseYear: dailyPuzzle.song.releaseYear,
            special: special.name,
            maxAttempts: special.maxAttempts,
            unlockSteps: JSON.parse(special.unlockSteps),
            startTime: specialSong?.startTime || 0
        };

    } catch (error) {
        console.error('Error in getOrCreateSpecialPuzzle:', error);
        return null;
    }
}
