import { Router, Request, Response, NextFunction } from 'express';
import crypto from 'crypto';
import { z } from 'zod';
import { authenticate } from '../../middleware/auth.middleware';
import { requireNonTemp } from '../../middleware/rbac.middleware';
import { env } from '../../config/env';
import { logger } from '../../utils/logger';
import { prisma } from '../../config/database';
import { siteSettingsService } from '../settings/settings.service';
import { isServiceOnline } from '../../utils/health-check';
import { generateSlug, generateModeratorToken } from './jitsi.utils';
import { eventBus } from '../../services/event-bus.service';

const router = Router();

/** Check if meet is enabled (DB setting wins, env var is fallback for first boot) */
async function isMeetEnabled(): Promise<boolean> {
  try {
    const settings = await siteSettingsService.get();
    return settings.enableMeet;
  } catch {
    return env.ENABLE_MEET === 'true';
  }
}

const tokenSchema = z.object({
  room: z.string().min(1).max(200),
});

const createMeetingSchema = z.object({
  title: z.string().min(1).max(200),
  description: z.string().max(2000).optional(),
  startTime: z.string().datetime().optional(),
  endTime: z.string().datetime().optional(),
});

// GET /api/jitsi/status — health check (any authenticated user)
router.get(
  '/status',
  authenticate,
  async (_req: Request, res: Response, next: NextFunction) => {
    try {
      const enabled = await isMeetEnabled();
      const online = enabled ? await isServiceOnline(env.JITSI_URL) : false;
      res.json({ online, enabled });
    } catch (err) {
      logger.error('Jitsi status check failed:', err);
      next(err);
    }
  },
);

// GET /api/jitsi/config — return Jitsi URLs + enabled status
router.get(
  '/config',
  authenticate,
  async (_req: Request, res: Response, _next: NextFunction) => {
    const enabled = await isMeetEnabled();
    res.json({
      enabled,
      embedPort: env.JITSI_EMBED_PORT,
      subdomain: 'meet',
      domain: env.DOMAIN,
    });
  },
);

// POST /api/jitsi/token — generate JWT for a standalone meeting room
router.post(
  '/token',
  authenticate,
  requireNonTemp,
  async (req: Request, res: Response, next: NextFunction) => {
    try {
      const enabled = await isMeetEnabled();
      if (!enabled) {
        res.status(400).json({ error: 'Video meetings are not enabled' });
        return;
      }

      if (!env.JITSI_APP_SECRET) {
        res.status(500).json({ error: 'Jitsi JWT secret is not configured' });
        return;
      }

      const parsed = tokenSchema.safeParse(req.body);
      if (!parsed.success) {
        res.status(400).json({ error: 'Invalid room name (1-200 characters required)' });
        return;
      }

      const { room } = parsed.data;

      const user = await prisma.user.findUnique({
        where: { id: req.user!.id },
        select: { id: true, email: true, name: true },
      });

      if (!user) {
        res.status(401).json({ error: 'User not found' });
        return;
      }

      const token = generateModeratorToken(user, room);
      res.json({ token, room });
    } catch (err) {
      logger.error('Jitsi token generation failed:', err);
      next(err);
    }
  },
);

// ============================================================================
// MEETING CRUD
// ============================================================================

// GET /api/jitsi/meetings — list user's meetings (authenticated)
router.get(
  '/meetings',
  authenticate,
  async (req: Request, res: Response, next: NextFunction) => {
    try {
      const userId = req.user!.id;
      const userRole = req.user!.role;
      const isAdmin = ['SUPER_ADMIN', 'INFLUENCE_ADMIN', 'MAP_ADMIN'].includes(userRole);

      // Admins see all meetings, regular users see only their own
      const where = isAdmin ? {} : { createdByUserId: userId };

      const meetings = await prisma.meeting.findMany({
        where,
        orderBy: { createdAt: 'desc' },
      });

      res.json({ meetings });
    } catch (err) {
      logger.error('List meetings failed:', err);
      next(err);
    }
  },
);

// POST /api/jitsi/meetings — create a meeting (authenticated, non-TEMP)
router.post(
  '/meetings',
  authenticate,
  requireNonTemp,
  async (req: Request, res: Response, next: NextFunction) => {
    try {
      const enabled = await isMeetEnabled();
      if (!enabled) {
        res.status(400).json({ error: 'Video meetings are not enabled' });
        return;
      }

      const parsed = createMeetingSchema.safeParse(req.body);
      if (!parsed.success) {
        res.status(400).json({ error: 'Invalid meeting data', details: parsed.error.flatten().fieldErrors });
        return;
      }

      const { title, description, startTime, endTime } = parsed.data;

      const meeting = await prisma.meeting.create({
        data: {
          slug: generateSlug(title),
          title,
          description: description || null,
          jitsiRoom: crypto.randomUUID(),
          createdByUserId: req.user!.id,
          startTime: startTime ? new Date(startTime) : null,
          endTime: endTime ? new Date(endTime) : null,
        },
      });

      eventBus.publish('meeting.created', {
        meetingId: meeting.id,
        title: meeting.title,
        scheduledAt: meeting.startTime?.toISOString() ?? new Date().toISOString(),
        jitsiRoomName: meeting.jitsiRoom,
        createdByUserId: meeting.createdByUserId,
      });

      res.status(201).json(meeting);
    } catch (err) {
      logger.error('Create meeting failed:', err);
      next(err);
    }
  },
);

// GET /api/jitsi/meetings/:slug — get meeting details (public, no auth required)
router.get(
  '/meetings/:slug',
  async (req: Request, res: Response, next: NextFunction) => {
    try {
      const slug = req.params.slug as string;
      const meeting = await prisma.meeting.findUnique({
        where: { slug },
      });

      if (!meeting) {
        res.status(404).json({ error: 'Meeting not found' });
        return;
      }

      res.json(meeting);
    } catch (err) {
      logger.error('Get meeting failed:', err);
      next(err);
    }
  },
);

// DELETE /api/jitsi/meetings/:id — delete a meeting (owner or SUPER_ADMIN)
router.delete(
  '/meetings/:id',
  authenticate,
  async (req: Request, res: Response, next: NextFunction) => {
    try {
      const meetingId = req.params.id as string;
      const meeting = await prisma.meeting.findUnique({
        where: { id: meetingId },
      });

      if (!meeting) {
        res.status(404).json({ error: 'Meeting not found' });
        return;
      }

      // Only the creator or a SUPER_ADMIN can delete
      if (meeting.createdByUserId !== req.user!.id && req.user!.role !== 'SUPER_ADMIN') {
        res.status(403).json({ error: 'Not authorized to delete this meeting' });
        return;
      }

      await prisma.meeting.delete({ where: { id: meetingId } });

      eventBus.publish('meeting.deleted', {
        meetingId: meeting.id,
        title: meeting.title,
      });

      res.json({ success: true });
    } catch (err) {
      logger.error('Delete meeting failed:', err);
      next(err);
    }
  },
);

// POST /api/jitsi/meetings/:slug/token — generate moderator JWT for a meeting (authenticated, non-TEMP)
router.post(
  '/meetings/:slug/token',
  authenticate,
  requireNonTemp,
  async (req: Request, res: Response, next: NextFunction) => {
    try {
      const enabled = await isMeetEnabled();
      if (!enabled) {
        res.status(400).json({ error: 'Video meetings are not enabled' });
        return;
      }

      if (!env.JITSI_APP_SECRET) {
        res.status(500).json({ error: 'Jitsi JWT secret is not configured' });
        return;
      }

      const slug = req.params.slug as string;
      const meeting = await prisma.meeting.findUnique({
        where: { slug },
      });

      if (!meeting) {
        res.status(404).json({ error: 'Meeting not found' });
        return;
      }

      if (!meeting.isActive) {
        res.status(400).json({ error: 'Meeting is no longer active' });
        return;
      }

      const user = await prisma.user.findUnique({
        where: { id: req.user!.id },
        select: { id: true, email: true, name: true },
      });

      if (!user) {
        res.status(401).json({ error: 'User not found' });
        return;
      }

      const token = generateModeratorToken(user, meeting.jitsiRoom);
      res.json({ token, jitsiRoom: meeting.jitsiRoom, domain: `meet.${env.DOMAIN}` });
    } catch (err) {
      logger.error('Meeting token generation failed:', err);
      next(err);
    }
  },
);

// GET /api/jitsi/meetings/:slug/join — public info for guest join page (no auth)
router.get(
  '/meetings/:slug/join',
  async (req: Request, res: Response, next: NextFunction) => {
    try {
      const slug = req.params.slug as string;
      const meeting = await prisma.meeting.findUnique({
        where: { slug },
        select: {
          title: true,
          description: true,
          jitsiRoom: true,
          isActive: true,
          startTime: true,
          endTime: true,
        },
      });

      if (!meeting) {
        res.status(404).json({ error: 'Meeting not found' });
        return;
      }

      if (!meeting.isActive) {
        res.status(410).json({ error: 'This meeting has ended' });
        return;
      }

      res.json({
        title: meeting.title,
        description: meeting.description,
        jitsiRoom: meeting.jitsiRoom,
        domain: `meet.${env.DOMAIN}`,
        startTime: meeting.startTime,
        endTime: meeting.endTime,
      });
    } catch (err) {
      logger.error('Meeting join info failed:', err);
      next(err);
    }
  },
);

export const jitsiRouter = router;
