"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.videosRoutes = videosRoutes;
const database_1 = require("../../../config/database");
const auth_1 = require("../middleware/auth");
const zod_1 = require("zod");
const promises_1 = require("fs/promises");
const thumbnail_service_1 = require("../services/thumbnail.service");
const logger_1 = require("../../../utils/logger");
async function videosRoutes(fastify) {
    // List videos (admin only)
    fastify.get('/', {
        preHandler: auth_1.requireAdminRole,
    }, async (request, reply) => {
        const limit = parseInt(request.query.limit || '50');
        const offset = parseInt(request.query.offset || '0');
        const search = request.query.search;
        const orientation = request.query.orientation;
        const producers = request.query.producers?.split(',').filter(Boolean);
        const isShort = request.query.isShort;
        // Build Prisma WHERE clause
        const where = {};
        if (isShort !== undefined) {
            where.isShort = isShort === 'true';
        }
        if (search) {
            where.title = {
                contains: search,
                mode: 'insensitive',
            };
        }
        if (orientation) {
            where.orientation = orientation;
        }
        if (producers && producers.length > 0) {
            where.producer = {
                in: producers,
            };
        }
        const videos = await database_1.prisma.video.findMany({
            where,
            select: {
                id: true,
                title: true,
                filename: true,
                durationSeconds: true,
                fileSize: true,
                width: true,
                height: true,
                orientation: true,
                producer: true,
                thumbnailPath: true,
                createdAt: true,
                isPublished: true,
                publishedAt: true,
                scheduledPublishAt: true,
                scheduledUnpublishAt: true,
                category: true,
                isShort: true,
                accessLevel: true,
            },
            orderBy: {
                createdAt: 'desc',
            },
            take: limit,
            skip: offset,
        });
        // Get total count
        const total = await database_1.prisma.video.count({ where });
        // Map videos to include thumbnailUrl
        const videosWithThumbnails = videos.map((video) => ({
            ...video,
            duration: video.durationSeconds ?? 0, // Add duration alias for frontend
            thumbnailUrl: video.thumbnailPath ? `/media/videos/${video.id}/thumbnail` : null,
        }));
        return {
            videos: videosWithThumbnails,
            total,
            limit,
            offset,
        };
    });
    // Get single video (admin only for now)
    fastify.get('/:id', {
        preHandler: auth_1.requireAdminRole,
    }, async (request, reply) => {
        const videoId = parseInt(request.params.id);
        const video = await database_1.prisma.video.findUnique({
            where: { id: videoId },
        });
        if (!video) {
            return reply.code(404).send({ message: 'Video not found' });
        }
        return {
            video: {
                ...video,
                duration: video.durationSeconds ?? 0,
                thumbnailUrl: video.thumbnailPath ? `/media/videos/${video.id}/thumbnail` : null,
            },
        };
    });
    // Get list of producers (admin only)
    fastify.get('/producers', {
        preHandler: auth_1.requireAdminRole,
    }, async (request, reply) => {
        const videos = await database_1.prisma.video.findMany({
            where: {
                producer: { not: null },
            },
            select: {
                producer: true,
            },
            distinct: ['producer'],
        });
        return videos.map((v) => v.producer).filter(Boolean);
    });
    // Health check for videos routes
    fastify.get('/health', async (request, reply) => {
        // Test database connection by counting videos
        const count = await database_1.prisma.video.count();
        return {
            status: 'ok',
            videosCount: count,
        };
    });
    // ========================================================================
    // PUBLISHING ROUTES (replaces copy-to-public)
    // ========================================================================
    // Zod schemas for publishing
    const PublishSchema = zod_1.z.object({
        category: zod_1.z.enum(['videos', 'curated', 'compilations', 'playback', 'highlights']),
    });
    const BulkPublishSchema = zod_1.z.object({
        videoIds: zod_1.z.array(zod_1.z.number().int().positive()).min(1).max(100),
        category: zod_1.z.enum(['videos', 'curated', 'compilations', 'playback', 'highlights']),
    });
    const BulkUnpublishSchema = zod_1.z.object({
        videoIds: zod_1.z.array(zod_1.z.number().int().positive()).min(1).max(100),
    });
    // POST /videos/:id/publish - Publish single video
    fastify.post('/:id/publish', { preHandler: auth_1.requireAdminRole }, async (request, reply) => {
        const videoId = parseInt(request.params.id);
        const parseResult = PublishSchema.safeParse(request.body);
        if (!parseResult.success) {
            return reply.code(400).send({ message: 'Invalid category', errors: parseResult.error.errors });
        }
        const { category } = parseResult.data;
        try {
            const video = await database_1.prisma.video.update({
                where: { id: videoId },
                data: {
                    isPublished: true,
                    publishedAt: new Date(),
                    category,
                },
            });
            logger_1.logger.info(`Video ${videoId} published to ${category}`);
            return { success: true, video };
        }
        catch (error) {
            logger_1.logger.error(`Error publishing video ${videoId}:`, error);
            return reply.code(500).send({ message: 'Failed to publish video', error: error.message });
        }
    });
    // POST /videos/:id/unpublish - Unpublish single video
    fastify.post('/:id/unpublish', { preHandler: auth_1.requireAdminRole }, async (request, reply) => {
        const videoId = parseInt(request.params.id);
        try {
            const video = await database_1.prisma.video.update({
                where: { id: videoId },
                data: {
                    isPublished: false,
                    publishedAt: null,
                    // Keep category for re-publishing
                },
            });
            logger_1.logger.info(`Video ${videoId} unpublished`);
            return { success: true, video };
        }
        catch (error) {
            logger_1.logger.error(`Error unpublishing video ${videoId}:`, error);
            return reply.code(500).send({ message: 'Failed to unpublish video', error: error.message });
        }
    });
    // POST /videos/bulk-publish - Publish multiple videos
    fastify.post('/bulk-publish', { preHandler: auth_1.requireAdminRole }, async (request, reply) => {
        const parseResult = BulkPublishSchema.safeParse(request.body);
        if (!parseResult.success) {
            return reply.code(400).send({ message: 'Invalid request', errors: parseResult.error.errors });
        }
        const { videoIds, category } = parseResult.data;
        try {
            const result = await database_1.prisma.video.updateMany({
                where: { id: { in: videoIds } },
                data: {
                    isPublished: true,
                    publishedAt: new Date(),
                    category,
                },
            });
            logger_1.logger.info(`Bulk published ${result.count} videos to ${category}`);
            return { success: true, count: result.count };
        }
        catch (error) {
            logger_1.logger.error(`Error bulk publishing videos:`, error);
            return reply.code(500).send({ message: 'Failed to publish videos', error: error.message });
        }
    });
    // POST /videos/bulk-unpublish - Unpublish multiple videos
    fastify.post('/bulk-unpublish', { preHandler: auth_1.requireAdminRole }, async (request, reply) => {
        const parseResult = BulkUnpublishSchema.safeParse(request.body);
        if (!parseResult.success) {
            return reply.code(400).send({ message: 'Invalid request', errors: parseResult.error.errors });
        }
        const { videoIds } = parseResult.data;
        try {
            const result = await database_1.prisma.video.updateMany({
                where: { id: { in: videoIds } },
                data: {
                    isPublished: false,
                    publishedAt: null,
                },
            });
            logger_1.logger.info(`Bulk unpublished ${result.count} videos`);
            return { success: true, count: result.count };
        }
        catch (error) {
            logger_1.logger.error(`Error bulk unpublishing videos:`, error);
            return reply.code(500).send({ message: 'Failed to unpublish videos', error: error.message });
        }
    });
    // POST /videos/:id/lock - Lock published video
    fastify.post('/:id/lock', { preHandler: auth_1.requireAdminRole }, async (request, reply) => {
        const videoId = parseInt(request.params.id);
        const userId = request.user?.id;
        try {
            const video = await database_1.prisma.video.update({
                where: { id: videoId },
                data: {
                    isLocked: true,
                    lockedAt: new Date(),
                    lockedById: userId,
                },
            });
            logger_1.logger.info(`Video ${videoId} locked by user ${userId}`);
            return { success: true, video };
        }
        catch (error) {
            logger_1.logger.error(`Error locking video ${videoId}:`, error);
            return reply.code(500).send({ message: 'Failed to lock video', error: error.message });
        }
    });
    // POST /videos/:id/unlock - Unlock published video
    fastify.post('/:id/unlock', { preHandler: auth_1.requireAdminRole }, async (request, reply) => {
        const videoId = parseInt(request.params.id);
        try {
            const video = await database_1.prisma.video.update({
                where: { id: videoId },
                data: {
                    isLocked: false,
                    lockedAt: null,
                    lockedById: null,
                },
            });
            logger_1.logger.info(`Video ${videoId} unlocked`);
            return { success: true, video };
        }
        catch (error) {
            logger_1.logger.error(`Error unlocking video ${videoId}:`, error);
            return reply.code(500).send({ message: 'Failed to unlock video', error: error.message });
        }
    });
    // ========================================================================
    // THUMBNAIL GENERATION ROUTES
    // ========================================================================
    // POST /videos/:id/generate-thumbnail - Generate thumbnail for single video
    fastify.post('/:id/generate-thumbnail', { preHandler: auth_1.requireAdminRole }, async (request, reply) => {
        const videoId = parseInt(request.params.id);
        try {
            const video = await database_1.prisma.video.findUnique({
                where: { id: videoId },
            });
            if (!video) {
                return reply.code(404).send({ message: 'Video not found' });
            }
            // Check if video file exists
            try {
                await (0, promises_1.access)(video.path);
            }
            catch {
                return reply.code(400).send({ message: 'Video file not found on disk' });
            }
            // Generate thumbnail
            const thumbnailPath = await thumbnail_service_1.ThumbnailService.generateThumbnail({
                videoPath: video.path,
                videoId: video.id,
                duration: video.durationSeconds ?? 0,
                orientation: video.orientation ?? '',
            });
            // Update video with thumbnail path
            const updatedVideo = await database_1.prisma.video.update({
                where: { id: videoId },
                data: { thumbnailPath },
            });
            logger_1.logger.info(`Thumbnail generated for video ${videoId}`);
            return { success: true, video: updatedVideo };
        }
        catch (error) {
            logger_1.logger.error(`Error generating thumbnail for video ${videoId}:`, error);
            return reply.code(500).send({ message: 'Failed to generate thumbnail', error: error.message });
        }
    });
    // POST /videos/bulk-generate-thumbnails - Generate thumbnails for all videos without them
    fastify.post('/bulk-generate-thumbnails', { preHandler: auth_1.requireAdminRole }, async (request, reply) => {
        try {
            // Find all videos without thumbnails
            const videos = await database_1.prisma.video.findMany({
                where: {
                    thumbnailPath: null,
                    isValid: true,
                },
                select: {
                    id: true,
                    path: true,
                    durationSeconds: true,
                    orientation: true,
                },
            });
            logger_1.logger.info(`Found ${videos.length} videos without thumbnails`);
            const results = {
                total: videos.length,
                succeeded: 0,
                failed: 0,
                errors: [],
            };
            for (const video of videos) {
                try {
                    // Check if video file exists
                    await (0, promises_1.access)(video.path);
                    // Generate thumbnail
                    const thumbnailPath = await thumbnail_service_1.ThumbnailService.generateThumbnail({
                        videoPath: video.path,
                        videoId: video.id,
                        duration: video.durationSeconds ?? 0,
                        orientation: video.orientation ?? '',
                    });
                    // Update video with thumbnail path
                    await database_1.prisma.video.update({
                        where: { id: video.id },
                        data: { thumbnailPath },
                    });
                    results.succeeded++;
                    logger_1.logger.info(`Thumbnail generated for video ${video.id}`);
                }
                catch (error) {
                    results.failed++;
                    results.errors.push({
                        videoId: video.id,
                        error: error.message,
                    });
                    logger_1.logger.error(`Failed to generate thumbnail for video ${video.id}:`, error);
                }
            }
            return {
                success: true,
                results,
            };
        }
        catch (error) {
            logger_1.logger.error('Error bulk generating thumbnails:', error);
            return reply.code(500).send({ message: 'Failed to bulk generate thumbnails', error: error.message });
        }
    });
}
//# sourceMappingURL=videos.routes.js.map