const prisma = require("../lib/prisma");
const {
  notifyUser,
  notifyManyUsers,
} = require("../services/notification.service");

/* ------------------- Helpers ------------------- */

const authorizeTeacherOrAdmin = (user, liveClass) => {
  const isAdminOrAccountant =
    user.role === "admin" || user.role === "accountant";
  const isTeacher = user.id === liveClass.subject.teacherId;
  return isAdminOrAccountant || isTeacher;
};

const validateMeetingUrl = (url) => {
  if (!url) return true;
  return /^https?:\/\/\S+$/i.test(url);
};

/* ------------------- Controller ------------------- */

// CREATE LIVE CLASS
exports.createLiveClass = async (req, res) => {
  try {
    const { startTime, subjectId, meetingUrl, teacherId } = req.body;

    if (!startTime || !subjectId) {
      return res.status(400).json({
        message: "Start time and subject id are required",
      });
    }

    if (isNaN(Date.parse(startTime))) {
      return res.status(400).json({ message: "Invalid start time format" });
    }

    if (!validateMeetingUrl(meetingUrl)) {
      return res.status(400).json({ message: "Invalid meeting URL" });
    }

    const start = new Date(startTime);
    const now = new Date();

    if (start < now) {
      return res
        .status(400)
        .json({ message: "Start time must be in the future" });
    }

    const subject = await prisma.subject.findUnique({
      where: { id: Number(subjectId) },
    });

    if (!subject) {
      return res.status(404).json({ message: "Subject not found" });
    }

    // ✅ Decide teacher correctly
    let finalTeacherId;

    if (req.user.role === "admin" || req.user.role === "accountant") {
      if (!teacherId) {
        return res.status(400).json({ message: "Teacher is required" });
      }
      finalTeacherId = Number(teacherId);
    } else if (req.user.role === "teacher") {
      finalTeacherId = req.user.id;
    } else {
      return res.status(403).json({ message: "Not allowed" });
    }

    // Prevent duplicate class
    const exists = await prisma.liveClass.findFirst({
      where: {
        subjectId: Number(subjectId),
        startTime: start,
      },
    });

    if (exists) {
      return res.status(400).json({
        message: "A class already exists at this time for this subject",
      });
    }

    const liveClass = await prisma.liveClass.create({
      data: {
        startTime: start,
        meetingUrl,
        subjectId: Number(subjectId),
        teacherId: finalTeacherId,
      },
    });

    // Bulk create attendance
    const students = await prisma.enrollment.findMany({
      where: { subjectId: Number(subjectId) },
      select: { studentId: true },
    });

    if (students.length) {
      await prisma.attendance.createMany({
        data: students.map((s) => ({
          studentId: s.studentId,
          classId: liveClass.id,
          status: "absent",
        })),
        skipDuplicates: true,
      });
    }

    const createdClass = await prisma.liveClass.findUnique({
      where: { id: liveClass.id },
      include: { subject: true, teacher: true },
    });

    // 🔔 Notify assigned teacher
    const teacherMessage = `A live class has been scheduled for "${
      createdClass.subject.title
    }" on ${start.toLocaleString()}.`;
    await notifyUser(req, createdClass.teacherId, teacherMessage, null);

    // 🔔 Notify enrolled students of this subject
    const enrolledStudents = await prisma.enrollment.findMany({
      where: {
        subjectId: Number(subjectId),
      },
      select: {
        studentId: true,
      },
    });

    if (enrolledStudents.length) {
      const studentMessage = `A new live class for "${
        createdClass.subject.title
      }" is scheduled on ${start.toLocaleString()}.`;

      await Promise.all(
        enrolledStudents.map((e) =>
          notifyUser(req, e.studentId, studentMessage, null),
        ),
      );
    }

    return res.status(201).json({
      message: "Live class created successfully",
      liveClass: createdClass,
    });
  } catch (err) {
    console.error(err);
    return res.status(500).json({ message: "Server error" });
  }
};

// GET ALL LIVE CLASSES
exports.getAllLiveClasses = async (req, res) => {
  try {
    const user = req.user; // comes from authMiddleware
    let liveClasses;

    if (user.role === "admin" || user.role === "accountant") {
      liveClasses = await prisma.liveClass.findMany({
        include: { subject: true },
      });
    } else if (user.role === "teacher") {
      liveClasses = await prisma.liveClass.findMany({
        where: { teacherId: user.id },
        include: { subject: true },
      });
    } else if (user.role === "student") {
      const enrollments = await prisma.enrollment.findMany({
        where: { studentId: user.id },
        select: { subjectId: true },
      });

      const enrolledSubjectIds = enrollments.map((e) => e.subjectId);

      liveClasses = await prisma.liveClass.findMany({
        where: { subjectId: { in: enrolledSubjectIds } },
        include: { subject: true },
      });
    } else {
      return res.status(403).json({ message: "Unauthorized" });
    }

    return res.json(liveClasses);
  } catch (err) {
    console.error(err);
    return res.status(500).json({ message: "Server Error" });
  }
};

// GET CLASSES BY SUBJECT
exports.getClassesBySubject = async (req, res) => {
  try {
    const subjectId = Number(req.params.subjectId);
    if (!subjectId)
      return res.status(400).json({ message: "Invalid subject ID" });

    const classes = await prisma.liveClass.findMany({
      where: { subjectId },
      include: { subject: true, teacher: true },
      orderBy: { startTime: "asc" },
    });

    return res.json(Array.isArray(classes) ? classes : []);
  } catch (err) {
    console.error(err);
    return res.status(500).json({ message: "Server error" });
  }
};

// END CLASS
exports.endLiveClass = async (req, res) => {
  try {
    const classId = Number(req.params.id);
    if (!classId) return res.status(400).json({ message: "Invalid class ID" });

    const liveClass = await prisma.liveClass.findUnique({
      where: { id: classId },
      include: { subject: true },
    });
    if (!liveClass)
      return res.status(404).json({ message: "Live class not found" });

    if (!authorizeTeacherOrAdmin(req.user, liveClass)) {
      return res.status(403).json({ message: "Not allowed" });
    }

    if (liveClass.endTime)
      return res.status(400).json({ message: "Class already ended" });

    const updated = await prisma.liveClass.update({
      where: { id: classId },
      data: { endTime: new Date() },
    });
    return res.json({ message: "Class ended successfully", updated });
  } catch (err) {
    console.error(err);
    return res.status(500).json({ message: "Server error" });
  }
};

// DELETE CLASS
exports.deleteLiveClass = async (req, res) => {
  try {
    const classId = Number(req.params.id);
    if (!classId) return res.status(400).json({ message: "Invalid class ID" });

    const liveClass = await prisma.liveClass.findUnique({
      where: { id: classId },
      include: { subject: true },
    });
    if (!liveClass)
      return res.status(404).json({ message: "Live class not found" });

    if (!authorizeTeacherOrAdmin(req.user, liveClass)) {
      return res.status(403).json({ message: "Not allowed" });
    }

    const now = new Date();
    if (new Date(liveClass.startTime) <= now) {
      return res
        .status(400)
        .json({ message: "Cannot delete a class that has started" });
    }

    await prisma.liveClass.delete({ where: { id: classId } });
    return res.json({ message: "Live class deleted successfully" });
  } catch (err) {
    console.error(err);
    return res.status(500).json({ message: "Server error" });
  }
};

exports.getLiveClassesForTeacher = async (req, res) => {
  try {
    const teacherId = req.user.id;

    const classes = await prisma.liveClass.findMany({
      where: { teacherId },
      include: {
        subject: true,
        teacher: true,
      },
      orderBy: { startTime: "asc" },
    });

    res.json(classes);
  } catch (err) {
    console.error(err);
    res.status(500).json({ message: "Server error" });
  }
};
