import { Router, Response } from "express";
import { notificationService } from "../services/notificationService";
import { AuthenticatedRequest, requireAuth } from "../middleware/auth";
import { prisma } from "../utils/db";

const router = Router();

/**
 * GET /notifications
 * Get all uncleared notifications for the current user
 */
router.get(
    "/",
    requireAuth,
    async (req: AuthenticatedRequest, res: Response) => {
        try {
            console.log(
                `[Notifications] Fetching notifications for user ${
                    req.user!.id
                }`
            );
            const notifications = await notificationService.getForUser(
                req.user!.id
            );
            console.log(
                `[Notifications] Found ${notifications.length} notifications`
            );
            res.json(notifications);
        } catch (error: any) {
            console.error("Error fetching notifications:", error);
            res.status(500).json({ error: "Failed to fetch notifications" });
        }
    }
);

/**
 * GET /notifications/unread-count
 * Get count of unread notifications
 */
router.get(
    "/unread-count",
    requireAuth,
    async (req: AuthenticatedRequest, res: Response) => {
        try {
            const count = await notificationService.getUnreadCount(
                req.user!.id
            );
            res.json({ count });
        } catch (error: any) {
            console.error("Error fetching unread count:", error);
            res.status(500).json({ error: "Failed to fetch unread count" });
        }
    }
);

/**
 * POST /notifications/:id/read
 * Mark a notification as read
 */
router.post(
    "/:id/read",
    requireAuth,
    async (req: AuthenticatedRequest, res: Response) => {
        try {
            await notificationService.markAsRead(req.params.id, req.user!.id);
            res.json({ success: true });
        } catch (error: any) {
            console.error("Error marking notification as read:", error);
            res.status(500).json({
                error: "Failed to mark notification as read",
            });
        }
    }
);

/**
 * POST /notifications/read-all
 * Mark all notifications as read
 */
router.post(
    "/read-all",
    requireAuth,
    async (req: AuthenticatedRequest, res: Response) => {
        try {
            await notificationService.markAllAsRead(req.user!.id);
            res.json({ success: true });
        } catch (error: any) {
            console.error("Error marking all notifications as read:", error);
            res.status(500).json({
                error: "Failed to mark all notifications as read",
            });
        }
    }
);

/**
 * POST /notifications/:id/clear
 * Clear (dismiss) a notification
 */
router.post(
    "/:id/clear",
    requireAuth,
    async (req: AuthenticatedRequest, res: Response) => {
        try {
            await notificationService.clear(req.params.id, req.user!.id);
            res.json({ success: true });
        } catch (error: any) {
            console.error("Error clearing notification:", error);
            res.status(500).json({ error: "Failed to clear notification" });
        }
    }
);

/**
 * POST /notifications/clear-all
 * Clear all notifications
 */
router.post(
    "/clear-all",
    requireAuth,
    async (req: AuthenticatedRequest, res: Response) => {
        try {
            await notificationService.clearAll(req.user!.id);
            res.json({ success: true });
        } catch (error: any) {
            console.error("Error clearing all notifications:", error);
            res.status(500).json({
                error: "Failed to clear all notifications",
            });
        }
    }
);

// ============================================
// Download History Endpoints
// ============================================

/**
 * GET /notifications/downloads/history
 * Get completed/failed downloads that haven't been cleared
 */
router.get(
    "/downloads/history",
    requireAuth,
    async (req: AuthenticatedRequest, res: Response) => {
        try {
            const downloads = await prisma.downloadJob.findMany({
                where: {
                    userId: req.user!.id,
                    status: { in: ["completed", "failed", "exhausted"] },
                    cleared: false,
                },
                orderBy: { updatedAt: "desc" },
                take: 50,
            });
            res.json(downloads);
        } catch (error: any) {
            console.error("Error fetching download history:", error);
            res.status(500).json({ error: "Failed to fetch download history" });
        }
    }
);

/**
 * GET /notifications/downloads/active
 * Get active downloads (pending/processing)
 */
router.get(
    "/downloads/active",
    requireAuth,
    async (req: AuthenticatedRequest, res: Response) => {
        try {
            const downloads = await prisma.downloadJob.findMany({
                where: {
                    userId: req.user!.id,
                    status: { in: ["pending", "processing"] },
                },
                orderBy: { createdAt: "desc" },
            });
            res.json(downloads);
        } catch (error: any) {
            console.error("Error fetching active downloads:", error);
            res.status(500).json({ error: "Failed to fetch active downloads" });
        }
    }
);

/**
 * POST /notifications/downloads/:id/clear
 * Clear a download from history
 */
router.post(
    "/downloads/:id/clear",
    requireAuth,
    async (req: AuthenticatedRequest, res: Response) => {
        try {
            await prisma.downloadJob.updateMany({
                where: {
                    id: req.params.id,
                    userId: req.user!.id,
                },
                data: { cleared: true },
            });
            res.json({ success: true });
        } catch (error: any) {
            console.error("Error clearing download:", error);
            res.status(500).json({ error: "Failed to clear download" });
        }
    }
);

/**
 * POST /notifications/downloads/clear-all
 * Clear all completed/failed downloads from history
 */
router.post(
    "/downloads/clear-all",
    requireAuth,
    async (req: AuthenticatedRequest, res: Response) => {
        try {
            await prisma.downloadJob.updateMany({
                where: {
                    userId: req.user!.id,
                    status: { in: ["completed", "failed", "exhausted"] },
                    cleared: false,
                },
                data: { cleared: true },
            });
            res.json({ success: true });
        } catch (error: any) {
            console.error("Error clearing all downloads:", error);
            res.status(500).json({ error: "Failed to clear all downloads" });
        }
    }
);

/**
 * POST /notifications/downloads/:id/retry
 * Retry a failed download
 */
router.post(
    "/downloads/:id/retry",
    requireAuth,
    async (req: AuthenticatedRequest, res: Response) => {
        try {
            // Get the failed download
            const failedJob = await prisma.downloadJob.findFirst({
                where: {
                    id: req.params.id,
                    userId: req.user!.id,
                    status: { in: ["failed", "exhausted"] },
                },
            });

            if (!failedJob) {
                return res
                    .status(404)
                    .json({ error: "Download not found or not failed" });
            }

            // If this was a pending-track retry job, re-run the pending-track retry flow
            const metadata = failedJob.metadata as Record<
                string,
                unknown
            > | null;
            if (metadata?.downloadType === "pending-track-retry") {
                const playlistId = metadata.playlistId as string | undefined;
                const pendingTrackId = metadata.pendingTrackId as
                    | string
                    | undefined;

                if (!playlistId || !pendingTrackId) {
                    return res.status(400).json({
                        error: "Cannot retry: missing playlistId or pendingTrackId",
                    });
                }

                // Mark old job as cleared
                await prisma.downloadJob.update({
                    where: { id: failedJob.id },
                    data: { cleared: true },
                });

                // Validate playlist ownership and pending track exists
                const playlist = await prisma.playlist.findUnique({
                    where: { id: playlistId },
                });
                if (!playlist || playlist.userId !== req.user!.id) {
                    return res
                        .status(404)
                        .json({ error: "Playlist not found" });
                }

                const pendingTrack =
                    await prisma.playlistPendingTrack.findUnique({
                        where: { id: pendingTrackId },
                    });
                if (!pendingTrack) {
                    return res
                        .status(404)
                        .json({ error: "Pending track not found" });
                }

                const retryTargetId =
                    pendingTrack.albumMbid ||
                    pendingTrack.artistMbid ||
                    `pendingTrack:${pendingTrack.id}`;

                const newJobRecord = await prisma.downloadJob.create({
                    data: {
                        userId: req.user!.id,
                        subject: `${pendingTrack.spotifyArtist} - ${pendingTrack.spotifyTitle}`,
                        type: "track",
                        targetMbid: retryTargetId,
                        artistMbid: pendingTrack.artistMbid,
                        status: "processing",
                        attempts: 1,
                        startedAt: new Date(),
                        metadata: {
                            downloadType: "pending-track-retry",
                            source: "soulseek",
                            playlistId,
                            pendingTrackId,
                            spotifyArtist: pendingTrack.spotifyArtist,
                            spotifyTitle: pendingTrack.spotifyTitle,
                            spotifyAlbum: pendingTrack.spotifyAlbum,
                            albumMbid: pendingTrack.albumMbid,
                        },
                    },
                });

                const { soulseekService } = await import(
                    "../services/soulseek"
                );
                const { getSystemSettings } = await import(
                    "../utils/systemSettings"
                );

                const settings = await getSystemSettings();
                if (!settings?.musicPath) {
                    await prisma.downloadJob.update({
                        where: { id: newJobRecord.id },
                        data: {
                            status: "failed",
                            error: "Music path not configured",
                            completedAt: new Date(),
                        },
                    });
                    return res.json({
                        success: false,
                        newJobId: newJobRecord.id,
                        error: "Music path not configured",
                    });
                }

                if (
                    !settings?.soulseekUsername ||
                    !settings?.soulseekPassword
                ) {
                    await prisma.downloadJob.update({
                        where: { id: newJobRecord.id },
                        data: {
                            status: "failed",
                            error: "Soulseek credentials not configured",
                            completedAt: new Date(),
                        },
                    });
                    return res.json({
                        success: false,
                        newJobId: newJobRecord.id,
                        error: "Soulseek credentials not configured",
                    });
                }

                const albumName =
                    pendingTrack.spotifyAlbum !== "Unknown Album"
                        ? pendingTrack.spotifyAlbum
                        : pendingTrack.spotifyArtist;

                const searchResult = await soulseekService.searchTrack(
                    pendingTrack.spotifyArtist,
                    pendingTrack.spotifyTitle
                );

                if (
                    !searchResult.found ||
                    searchResult.allMatches.length === 0
                ) {
                    await prisma.downloadJob.update({
                        where: { id: newJobRecord.id },
                        data: {
                            status: "failed",
                            error: "No matching files found",
                            completedAt: new Date(),
                        },
                    });
                    return res.json({
                        success: false,
                        newJobId: newJobRecord.id,
                        error: "No matching files found",
                    });
                }

                // Start download in background (don't await)
                soulseekService
                    .downloadBestMatch(
                        pendingTrack.spotifyArtist,
                        pendingTrack.spotifyTitle,
                        albumName,
                        searchResult.allMatches,
                        settings.musicPath
                    )
                    .then(async (result) => {
                        if (result.success) {
                            await prisma.downloadJob.update({
                                where: { id: newJobRecord.id },
                                data: {
                                    status: "completed",
                                    completedAt: new Date(),
                                    metadata: {
                                        ...(newJobRecord.metadata as any),
                                        filePath: result.filePath,
                                    },
                                },
                            });

                            try {
                                const { scanQueue } = await import(
                                    "../workers/queues"
                                );
                                await scanQueue.add(
                                    "scan",
                                    {
                                        userId: req.user!.id,
                                        source: "retry-pending-track",
                                        albumMbid:
                                            pendingTrack.albumMbid || undefined,
                                        artistMbid:
                                            pendingTrack.artistMbid ||
                                            undefined,
                                    },
                                    {
                                        priority: 1,
                                        removeOnComplete: true,
                                    }
                                );
                            } catch {
                                // Best-effort; job status already reflects download
                            }
                        } else {
                            await prisma.downloadJob.update({
                                where: { id: newJobRecord.id },
                                data: {
                                    status: "failed",
                                    error: result.error || "Download failed",
                                    completedAt: new Date(),
                                },
                            });
                        }
                    })
                    .catch(async (error) => {
                        await prisma.downloadJob.update({
                            where: { id: newJobRecord.id },
                            data: {
                                status: "failed",
                                error: error?.message || "Download exception",
                                completedAt: new Date(),
                            },
                        });
                    });

                return res.json({ success: true, newJobId: newJobRecord.id });
            }

            // If this was a spotify_import job, retry with Soulseek first
            if (metadata?.downloadType === "spotify_import") {
                const artistName = metadata.artistName as string;
                const albumTitle = metadata.albumTitle as string;

                if (!artistName || !albumTitle) {
                    return res
                        .status(400)
                        .json({
                            error: "Cannot retry: missing artist/album info",
                        });
                }

                // Mark old job as cleared
                await prisma.downloadJob.update({
                    where: { id: failedJob.id },
                    data: { cleared: true },
                });

                // Create a NEW download job record for the retry
                const newJobRecord = await prisma.downloadJob.create({
                    data: {
                        userId: req.user!.id,
                        type: "album",
                        targetMbid:
                            failedJob.targetMbid || `retry_${Date.now()}`,
                        artistMbid: failedJob.artistMbid,
                        subject: `${artistName} - ${albumTitle}`,
                        status: "processing",
                        attempts: 1,
                        startedAt: new Date(),
                        metadata: {
                            ...metadata,
                            retryAttempt: true,
                        },
                    },
                });

                // Try Soulseek first (async)
                const { soulseekService } = await import(
                    "../services/soulseek"
                );
                const { getSystemSettings } = await import(
                    "../utils/systemSettings"
                );

                const settings = await getSystemSettings();
                const musicPath = settings?.musicPath;

                if (!musicPath) {
                    await prisma.downloadJob.update({
                        where: { id: newJobRecord.id },
                        data: {
                            status: "failed",
                            error: "Music path not configured",
                            completedAt: new Date(),
                        },
                    });
                    return res.json({
                        success: false,
                        newJobId: newJobRecord.id,
                        error: "Music path not configured",
                    });
                }

                // Build track from album info (single track search using album as title)
                const tracks = [
                    {
                        artist: artistName,
                        title: albumTitle,
                        album: albumTitle,
                    },
                ];

                console.log(
                    `[Retry] Trying Soulseek for ${artistName} - ${albumTitle}`
                );

                // Run Soulseek search async
                soulseekService
                    .searchAndDownloadBatch(tracks, musicPath, 4)
                    .then(async (result) => {
                        if (result.successful > 0) {
                            await prisma.downloadJob.update({
                                where: { id: newJobRecord.id },
                                data: {
                                    status: "completed",
                                    completedAt: new Date(),
                                    error: null,
                                    metadata: {
                                        ...metadata,
                                        source: "soulseek",
                                        tracksDownloaded: result.successful,
                                        files: result.files,
                                    },
                                },
                            });
                            console.log(
                                `[Retry] ✓ Soulseek downloaded ${result.successful} tracks for ${artistName} - ${albumTitle}`
                            );

                            // Trigger library scan
                            const { scanQueue } = await import(
                                "../workers/queues"
                            );
                            await scanQueue.add("scan", {
                                paths: [],
                                fullScan: false,
                                userId: req.user!.id,
                                source: "retry-spotify-import",
                            });
                        } else {
                            // Soulseek failed, try Lidarr if we have an MBID
                            console.log(
                                `[Retry] Soulseek failed, trying Lidarr for ${artistName} - ${albumTitle}`
                            );

                            if (
                                failedJob.targetMbid &&
                                !failedJob.targetMbid.startsWith("retry_")
                            ) {
                                const { simpleDownloadManager } = await import(
                                    "../services/simpleDownloadManager"
                                );
                                const lidarrResult =
                                    await simpleDownloadManager.startDownload(
                                        newJobRecord.id,
                                        artistName,
                                        albumTitle,
                                        failedJob.targetMbid,
                                        req.user!.id,
                                        false
                                    );

                                if (!lidarrResult.success) {
                                    await prisma.downloadJob.update({
                                        where: { id: newJobRecord.id },
                                        data: {
                                            status: "failed",
                                            error:
                                                lidarrResult.error ||
                                                "Both Soulseek and Lidarr failed",
                                            completedAt: new Date(),
                                        },
                                    });
                                }
                            } else {
                                await prisma.downloadJob.update({
                                    where: { id: newJobRecord.id },
                                    data: {
                                        status: "failed",
                                        error: "No tracks found on Soulseek, no MBID for Lidarr fallback",
                                        completedAt: new Date(),
                                    },
                                });
                            }
                        }
                    })
                    .catch(async (error) => {
                        console.error(`[Retry] Soulseek error:`, error);
                        await prisma.downloadJob.update({
                            where: { id: newJobRecord.id },
                            data: {
                                status: "failed",
                                error: error?.message || "Soulseek error",
                                completedAt: new Date(),
                            },
                        });
                    });

                return res.json({ success: true, newJobId: newJobRecord.id });
            }

            // Validate that we have the required MBIDs
            if (!failedJob.targetMbid) {
                return res
                    .status(400)
                    .json({ error: "Cannot retry: missing album MBID" });
            }

            // Mark old job as cleared
            await prisma.downloadJob.update({
                where: { id: failedJob.id },
                data: { cleared: true },
            });

            // Extract parameters from the failed job
            // Subject is typically "Artist - Album" format
            const subjectParts = failedJob.subject.split(" - ");
            const artistName = subjectParts[0] || failedJob.subject;
            const albumTitle =
                (metadata?.albumTitle as string) ||
                subjectParts[1] ||
                failedJob.subject;

            // Create a NEW download job record for the retry
            const newJobRecord = await prisma.downloadJob.create({
                data: {
                    userId: req.user!.id,
                    type: failedJob.type as "artist" | "album",
                    targetMbid: failedJob.targetMbid,
                    artistMbid: failedJob.artistMbid,
                    subject: failedJob.subject,
                    status: "pending",
                    metadata: metadata || {},
                },
            });

            // Import the download manager dynamically to avoid circular deps
            const { simpleDownloadManager } = await import(
                "../services/simpleDownloadManager"
            );

            // Start download with the correct positional arguments
            // startDownload(jobId, artistName, albumTitle, albumMbid, userId, isDiscovery)
            const result = await simpleDownloadManager.startDownload(
                newJobRecord.id,
                artistName,
                albumTitle,
                failedJob.targetMbid,
                req.user!.id,
                false // isDiscovery
            );

            res.json({
                success: result.success,
                newJobId: newJobRecord.id,
                error: result.error,
            });
        } catch (error: any) {
            console.error("Error retrying download:", error);
            res.status(500).json({ error: "Failed to retry download" });
        }
    }
);

export default router;
