const { TrainingVideo, TrainingEnrollment, Users } = require("../models");
const { createTrainingAssignmentNotification } = require("../utils/notificationHelper");
const { v4: uuidv4 } = require("uuid");
const { logActivity, getIpAddress, getUserAgent } = require("../utils/activityLogger");
const {
  saveTrainingVideo,
  deleteTrainingVideoFile,
} = require("../utils/uploadTrainingVideo");

const PASS_SCORE = 80;
const WATCH_UNLOCK_PCT = 80;

function parseQuizzes(raw) {
  if (raw == null || raw === "") return [];
  if (Array.isArray(raw)) return raw;
  try {
    const p = typeof raw === "string" ? JSON.parse(raw) : raw;
    return Array.isArray(p) ? p : [];
  } catch {
    return [];
  }
}

// GET all videos with enrollment for current user
const getTrainingVideos = async (req, res) => {
  try {
    const videos = await TrainingVideo.findAll({
      order: [["order", "ASC"]],
    });

    const enrollments = await TrainingEnrollment.findAll({
      where: { UserId: req.user.id },
    });

    const enrollmentMap = {};
    enrollments.forEach((e) => {
      enrollmentMap[e.TrainingVideoId] = {
        status: e.status,
        score: e.score,
        certificateId: e.certificateId,
        completedAt: e.completedAt,
        watchProgressPercent: e.watchProgressPercent ?? 0,
      };
    });

    const response = videos.map((v) => {
      const quizzes = v.quizzes || [];
      console.log(`🔍 Video "${v.title}" has ${quizzes.length} quizzes:`, quizzes);
      
      return {
        id: v.id,
        title: v.title,
        description: v.description,
        youtubeId: v.youtubeId,
        videoFileName: v.videoFileName,
        category: v.category,
        order: v.order,
        quizzes: quizzes,
        enrollment: enrollmentMap[v.id] || null,
      };
    });

    console.log("📚 Returning training videos:", response.map(v => ({ title: v.title, quizCount: v.quizzes.length })));
    res.json(response);
  } catch (err) {
    console.error("❌ Error fetching training videos:", err);
    res.status(500).json({ message: "Failed to fetch videos" });
  }
};

// POST watch progress (HTML5 video)
const saveProgress = async (req, res) => {
  const { id } = req.params;
  let { watchProgressPercent } = req.body;
  try {
    const video = await TrainingVideo.findByPk(id);
    if (!video) return res.status(404).json({ message: "Video not found" });

    const pct = Math.min(100, Math.max(0, Number(watchProgressPercent) || 0));

    let enrollment = await TrainingEnrollment.findOne({
      where: { UserId: req.user.id, TrainingVideoId: id },
    });

    if (!enrollment) {
      enrollment = await TrainingEnrollment.create({
        UserId: req.user.id,
        TrainingVideoId: id,
        status: "not-started",
        watchProgressPercent: 0,
      });
    }

    if (enrollment.status === "completed") {
      const newWatchProgress = Math.max(enrollment.watchProgressPercent || 0, pct);
      await TrainingEnrollment.update(
        { watchProgressPercent: newWatchProgress },
        { where: { id: enrollment.id } }
      );
      
      return res.json({
        watchProgressPercent: newWatchProgress,
        status: "completed",
      });
    }

    if (enrollment.status === "failed") {
      const newWatchProgress = Math.max(enrollment.watchProgressPercent || 0, pct);
      await TrainingEnrollment.update(
        { watchProgressPercent: newWatchProgress },
        { where: { id: enrollment.id } }
      );
      
      return res.json({
        watchProgressPercent: newWatchProgress,
        status: "failed",
      });
    }

    let nextStatus = enrollment.status;
    if (nextStatus === "not-started" && pct >= WATCH_UNLOCK_PCT) {
      nextStatus = "in-progress";
    }

    const nextWatch = Math.max(enrollment.watchProgressPercent || 0, pct);

    await TrainingEnrollment.update(
      {
        watchProgressPercent: nextWatch,
        status: nextStatus,
      },
      { where: { id: enrollment.id } }
    );

    res.json({
      watchProgressPercent: nextWatch,
      status: nextStatus,
    });
  } catch (err) {
    console.error("Error in saveProgress:", err);
    res.status(500).json({ message: "Failed to save progress" });
  }
};

// POST complete quiz / module
const completeVideo = async (req, res) => {
  const { id } = req.params;
  const { score = 0, answers } = req.body;

  try {
    const video = await TrainingVideo.findByPk(id);
    if (!video) return res.status(404).json({ message: "Video not found" });

    const hasQuiz = Array.isArray(video.quizzes) && video.quizzes.length > 0;

    let enrollment = await TrainingEnrollment.findOne({
      where: { UserId: req.user.id, TrainingVideoId: id },
    });

    const wp = enrollment?.watchProgressPercent ?? 0;

    if (wp < WATCH_UNLOCK_PCT) {
      return res.status(400).json({
        message: "Watch at least 80% of the video before completing this module",
      });
    }

    if (hasQuiz && Number(score) < PASS_SCORE) {
      if (!enrollment) {
        enrollment = await TrainingEnrollment.create({
          UserId: req.user.id,
          TrainingVideoId: id,
          status: "failed",
          score: Number(score),
          quizAnswers: answers || null,
          watchProgressPercent: wp,
        });
      } else {
        await TrainingEnrollment.update(
          {
            status: "failed",
            score: Number(score),
            quizAnswers: answers || null,
            watchProgressPercent: wp,
          },
          { where: { id: enrollment.id } }
        );
      }
      return res.json({ status: "failed", score: Number(score), certificateId: null });
    }

    const finalScore = hasQuiz ? Number(score) : 100;
    const newCertId = `CERT-${uuidv4().slice(0, 8).toUpperCase()}`;

    if (!enrollment) {
      enrollment = await TrainingEnrollment.create({
        UserId: req.user.id,
        TrainingVideoId: id,
        status: "completed",
        score: finalScore,
        quizAnswers: answers || null,
        certificateId: newCertId,
        completedAt: new Date(),
        watchProgressPercent: 100,
      });
    } else {
      const certId = enrollment.certificateId || newCertId;
      await TrainingEnrollment.update(
        {
          status: "completed",
          score: finalScore,
          quizAnswers: answers || null,
          certificateId: certId,
          completedAt: new Date(),
          watchProgressPercent: 100,
        },
        { where: { id: enrollment.id } }
      );
      
      // Update the enrollment object with the new certificate ID for the response
      enrollment.certificateId = certId;
    }

    await logActivity({
      userId: req.user.id,
      companyId: req.user.companyId,
      action: "create",
      entityType: "Training",
      entityId: id,
      description: `Training module completed: ${video.title}`,
      metadata: { score: finalScore, certificateId: enrollment.certificateId },
      ipAddress: getIpAddress(req),
      userAgent: getUserAgent(req),
    });

    res.json({
      status: "completed",
      score: finalScore,
      certificateId: enrollment.certificateId,
    });
  } catch (err) {
    console.error("Error in completeVideo:", err);
    res.status(500).json({ message: "Failed to update enrollment" });
  }
};

// --- Admin ---

const getAllVideosAdmin = async (req, res) => {
  try {
    const videos = await TrainingVideo.findAll({ order: [["order", "ASC"]] });
    res.json(videos);
  } catch (err) {
    res.status(500).json({ message: "Failed to fetch" });
  }
};

const createVideo = async (req, res) => {
  try {
    const {
      title,
      description,
      category,
      order,
      quizzes,
      youtubeId,
    } = req.body;

    if (!title || String(title).trim() === "") {
      return res.status(400).json({ message: "Title is required" });
    }

    console.log("🔍 Raw quizzes data:", quizzes);
    console.log("🔍 Type of quizzes:", typeof quizzes);
    
    const quizzesParsed = parseQuizzes(quizzes);
    console.log("🔍 Parsed quizzes:", quizzesParsed);
    console.log("🔍 Parsed quizzes length:", quizzesParsed.length);

    let videoFileName = null;
    if (req.files && req.files.video) {
      videoFileName = await saveTrainingVideo(req.files.video);
    }

    if (!videoFileName && (!youtubeId || String(youtubeId).trim() === "")) {
      return res.status(400).json({
        message: "Upload a video file (MP4/WebM) or provide a legacy youtubeId",
      });
    }

    const video = await TrainingVideo.create({
      title: String(title).trim(),
      description: description || null,
      category: category || "general",
      order: parseInt(order, 10) || 0,
      quizzes: quizzesParsed,
      videoFileName,
      youtubeId: youtubeId ? String(youtubeId).trim() : null,
    });
    
    console.log("✅ Video created with quizzes:", video.quizzes?.length || 0);
    res.status(201).json(video);
  } catch (err) {
    console.error("❌ Error creating video:", err);
    res.status(500).json({ message: err.message || "Failed to create" });
  }
};

const updateVideo = async (req, res) => {
  const { id } = req.params;
  try {
    const existing = await TrainingVideo.findByPk(id);
    if (!existing) return res.status(404).json({ message: "Not found" });

    const payload = {};
    if (req.body.title != null) payload.title = req.body.title;
    if (req.body.description != null) payload.description = req.body.description;
    if (req.body.category != null) payload.category = req.body.category;
    if (req.body.order != null) payload.order = parseInt(req.body.order, 10);
    if (req.body.quizzes != null) payload.quizzes = parseQuizzes(req.body.quizzes);
    if (req.body.youtubeId !== undefined) {
      payload.youtubeId = req.body.youtubeId ? String(req.body.youtubeId).trim() : null;
    }

    if (req.files && req.files.video) {
      deleteTrainingVideoFile(existing.videoFileName);
      payload.videoFileName = await saveTrainingVideo(req.files.video);
    }

    await TrainingVideo.update(payload, { where: { id } });
    const updated = await TrainingVideo.findByPk(id);
    res.json(updated);
  } catch (err) {
    console.error(err);
    res.status(500).json({ message: err.message || "Failed to update" });
  }
};

const deleteVideo = async (req, res) => {
  const { id } = req.params;
  try {
    const existing = await TrainingVideo.findByPk(id);
    if (!existing) return res.status(404).json({ message: "Not found" });
    deleteTrainingVideoFile(existing.videoFileName);
    await TrainingVideo.destroy({ where: { id } });
    await TrainingEnrollment.destroy({ where: { TrainingVideoId: id } });
    res.json({ message: "Deleted" });
  } catch (err) {
    res.status(500).json({ message: "Failed to delete" });
  }
};

const getMyCertificates = async (req, res) => {
  try {
    const enrollments = await TrainingEnrollment.findAll({
      where: { UserId: req.user.id, status: "completed" },
      include: [{ model: TrainingVideo, required: false }],
    });
    const certs = enrollments.map((e) => ({
      certificateId: e.certificateId,
      completedAt: e.completedAt,
      score: e.score,
      videoTitle: e.TrainingVideo?.title,
      category: e.TrainingVideo?.category,
      trainingVideoId: e.TrainingVideoId,
    }));
    res.json(certs);
  } catch (err) {
    console.error(err);
    res.status(500).json({ message: "Failed to fetch certificates" });
  }
};

const getTrainingReport = async (req, res) => {
  const { companyId } = req.user;
  try {
    const users = await Users.findAll({ where: { CompanyId: companyId } });
    const userIds = users.map((u) => u.id);

    const enrollments = await TrainingEnrollment.findAll({
      where: { UserId: userIds },
      include: [TrainingVideo],
    });

    res.json({
      totalUsers: users.length,
      completedEnrollments: enrollments.filter((e) => e.status === "completed").length,
      failedEnrollments: enrollments.filter((e) => e.status === "failed").length,
      byUser: users.map((user) => ({
        userId: user.id,
        name: user.fullname,
        completed: enrollments.filter((e) => e.UserId === user.id && e.status === "completed")
          .length,
        total: enrollments.filter((e) => e.UserId === user.id).length,
      })),
    });
  } catch (err) {
    console.error(err);
    res.status(500).json({ message: "Failed to generate report" });
  }
};

const enrollUserInTraining = async (req, res) => {
  const { userId, videoId } = req.body;
  if (!userId || !videoId) {
    return res.status(400).json({ message: "userId and videoId are required" });
  }
  try {
    const assigner = await Users.findByPk(req.user.id);
    const target = await Users.findOne({
      where: { id: userId, CompanyId: req.user.companyId },
    });
    if (!target) return res.status(404).json({ message: "User not found in your company" });

    const video = await TrainingVideo.findByPk(videoId);
    if (!video) return res.status(404).json({ message: "Training video not found" });

    await TrainingEnrollment.findOrCreate({
      where: { UserId: userId, TrainingVideoId: videoId },
      defaults: {
        UserId: userId,
        TrainingVideoId: videoId,
        status: "not-started",
        watchProgressPercent: 0,
      },
    });

    await createTrainingAssignmentNotification({
      userId,
      assignedBy: req.user.id,
      assignedByName: assigner?.fullname || "Administrator",
      companyId: req.user.companyId,
      videoId,
      videoTitle: video.title,
    });

    res.json({ message: "User assigned to training course" });
  } catch (err) {
    console.error(err);
    res.status(500).json({ message: "Failed to assign training" });
  }
};

module.exports = {
  getTrainingVideos,
  saveProgress,
  completeVideo,
  getAllVideosAdmin,
  createVideo,
  updateVideo,
  deleteVideo,
  getMyCertificates,
  getTrainingReport,
  enrollUserInTraining,
};
