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

exports.createPaymentRequest = async (req, res) => {
  try {
    const { subjectId } = req.body;

    const studentId = req.user?.id;
    if (!studentId) return res.status(401).json({ message: "Unauthorized" });

    if (!subjectId)
      return res.status(400).json({ message: "subjectId is required" });

    // 1️⃣ Subject
    const subject = await prisma.subject.findUnique({
      where: { id: Number(subjectId) },
    });
    if (!subject) return res.status(404).json({ message: "Subject not found" });

    // 2️⃣ Amount
    const amount = subject.price;

    // 3️⃣ Pending payment check
    let payment = await prisma.paymentRequest.findFirst({
      where: {
        studentId,
        subjectId: Number(subjectId),
        status: "pending",
      },
    });

    if (!payment) {
      const txnId = `ENR-${Date.now()}-${Math.floor(
        Math.random() * 9000 + 1000
      )}`;
      payment = await prisma.paymentRequest.create({
        data: {
          txnId,
          studentId,
          subjectId: Number(subjectId),
          amount,
          status: "pending",
        },
      });
    }

    // 4️⃣ REAL bank QR from backend
    const qrImage = `/bank-qr.png`;

    // 🔔 Notify Admins & Accountants
    const adminsAndAccountants = await prisma.user.findMany({
      where: {
        role: { in: ["admin", "accountant"] },
      },
      select: { id: true },
    });

    const student = await prisma.user.findUnique({
      where: { id: studentId },
      select: {
        firstName: true,
        lastName: true,
      },
    });

    const message = `New payment request created.
Student: ${student.firstName} ${student.lastName}
Subject: "${subject.title}"
Amount: Rs. ${amount}
Transaction ID: ${payment.txnId}`;

    if (adminsAndAccountants.length) {
      await Promise.all(
        adminsAndAccountants.map((u) => notifyUser(req, u.id, message, null))
      );
    }

    return res.json({
      qrImage,
      txnId: payment.txnId,
      amount: payment.amount,
    });
  } catch (err) {
    console.error(err);
    return res.status(500).json({ message: "Server error" });
  }
};

exports.uploadPaymentProof = async (req, res) => {
  try {
    const { txnId } = req.body;
    if (!txnId) return res.status(400).json({ message: "txnId is required" });

    const payment = await prisma.paymentRequest.findUnique({
      where: { txnId },
    });
    if (!payment)
      return res.status(404).json({ message: "Payment request not found" });

    if (payment.studentId !== req.user.id) {
      return res.status(403).json({ message: "Not allowed" });
    }

    if (!req.file) {
      return res.status(400).json({ message: "Proof file is required" });
    }

    // Save the Cloudinary URL
    const proofUrl = req.file.path; // <-- this is the Cloudinary URL

    const updated = await prisma.paymentRequest.update({
      where: { id: payment.id },
      data: { proofImage: proofUrl, status: "pending" },
    });

    return res.json({ message: "Proof uploaded", payment: updated });
  } catch (err) {
    console.error(err);
    return res.status(500).json({ message: "Server error" });
  }
};

// Admin: list pending
exports.listPendingPayments = async (req, res) => {
  try {
    const pending = await prisma.paymentRequest.findMany({
      where: { status: "pending" },
      include: { student: true, subject: true },
      orderBy: { createdAt: "desc" },
    });
    return res.json(pending);
  } catch (err) {
    console.error(err);
    return res.status(500).json({ message: "Server error" });
  }
};

// Admin: approve
exports.approvePayment = async (req, res) => {
  try {
    const { id } = req.params; // paymentRequest id
    const payment = await prisma.paymentRequest.findUnique({
      where: { id: Number(id) },
    });
    if (!payment) return res.status(404).json({ message: "Payment not found" });

    // check not already approved
    if (payment.status === "approved")
      return res.status(400).json({ message: "Already approved" });

    // Create enrollment depending on plan: here we create lifetime access
    // For monthly/subscription, you can set expiresAt accordingly
    const now = new Date();
    const expiresAt = null; // lifetime; or new Date(now.setMonth(now.getMonth() + 1))

    // create or upsert enrollment
    await prisma.enrollment.upsert({
      where: {
        studentId_subjectId: {
          studentId: payment.studentId,
          subjectId: payment.subjectId,
        },
      },
      update: {
        status: "active",
        startAt: new Date(),
        expiresAt: expiresAt,
      },
      create: {
        studentId: payment.studentId,
        subjectId: payment.subjectId,
        status: "active",
        startAt: new Date(),
        expiresAt: expiresAt,
      },
    });

    // update payment request
    const updated = await prisma.paymentRequest.update({
      where: { id: payment.id },
      data: {
        status: "approved",
        approvedAt: new Date(),
      },
    });

    // 🔔 Fetch subject for message
    const subject = await prisma.subject.findUnique({
      where: { id: payment.subjectId },
      select: { title: true },
    });

    // 🔔 Notify Student
    const message = `Payment approved successfully 🎉
You are now enrolled in "${subject.title}".
You can start learning immediately.`;

    await notifyUser(req, payment.studentId, message, payment.id);

    return res.json({
      message: "Payment approved and enrollment created",
      payment: updated,
    });
  } catch (err) {
    console.error(err);
    return res.status(500).json({ message: "Server error" });
  }
};

// Admin: reject
exports.rejectPayment = async (req, res) => {
  try {
    const { id } = req.params;
    const payment = await prisma.paymentRequest.findUnique({
      where: { id: Number(id) },
    });
    if (!payment) return res.status(404).json({ message: "Payment not found" });

    const updated = await prisma.paymentRequest.update({
      where: { id: payment.id },
      data: {
        status: "rejected",
      },
    });

    // 🔔 Fetch subject title
    const subject = await prisma.subject.findUnique({
      where: { id: payment.subjectId },
      select: { title: true },
    });

    // 🔔 Notify student
    const message = `Payment rejected ❌
Your payment request for "${subject.title}" was rejected.
Please contact administration or submit a new payment request.`;

    await notifyUser(req, payment.studentId, message, payment.id);

    return res.json({ message: "Payment rejected", payment: updated });
  } catch (err) {
    console.error(err);
    return res.status(500).json({ message: "Server error" });
  }
};

// Admin: list all payments with filtering, sorting, and pagination
exports.listPayments = async (req, res) => {
  try {
    let { page = 0, pageSize = 10, filter, sort } = req.query;

    page = Number(page);
    pageSize = Number(pageSize);

    // ========== PARSE FILTERS & SORT SAFELY ==========
    let filterModel = { items: [] };
    let sortModel = [];

    try {
      filterModel = filter ? JSON.parse(filter) : { items: [] };
    } catch {}

    try {
      sortModel = sort ? JSON.parse(sort) : [];
    } catch {}

    // ========== BUILD FILTERING ==========
    const AND = [];

    filterModel.items?.forEach((f) => {
      const { field, operator, value } = f;
      if (!value) return;

      switch (field) {
        case "txnId":
          if (operator === "contains") {
            AND.push({
              txnId: { contains: value, mode: "insensitive" },
            });
          }
          break;

        case "studentName":
          if (operator === "contains") {
            const parts = value.trim().split(/\s+/);
            const OR = parts.flatMap((part) => [
              {
                student: { firstName: { contains: part, mode: "insensitive" } },
              },
              {
                student: { lastName: { contains: part, mode: "insensitive" } },
              },
              { student: { email: { contains: part, mode: "insensitive" } } },
            ]);
            AND.push({ OR });
          }
          break;

        case "subjectTitle":
          if (operator === "contains") {
            AND.push({
              subject: { title: { contains: value, mode: "insensitive" } },
            });
          }
          break;

        case "amount":
          if (operator === "contains") {
            AND.push({
              amount: {
                equals: Number(value) || 0, // contains not possible for numbers, so treat as equals
              },
            });
          }
          break;

        case "status":
          if (operator === "equals") {
            AND.push({
              status: value,
            });
          }
          break;

        default:
          break;
      }
    });

    const where = AND.length > 0 ? { AND } : {};

    // ========== BUILD SORTING ==========
    let orderBy = [];

    sortModel.forEach(({ field, sort }) => {
      if (!sort) return;

      if (field === "sno") {
        orderBy.push({ id: sort.toLowerCase() });
        return;
      }

      if (["txnId", "amount", "status", "createdAt"].includes(field)) {
        orderBy.push({ [field]: sort.toLowerCase() });
      }
    });

    if (orderBy.length === 0) orderBy = [{ id: "desc" }];

    // ========== COUNT TOTAL ==========
    const total = await prisma.paymentRequest.count({ where });

    // ========== FETCH PAGINATED PAYMENTS ==========
    const payments = await prisma.paymentRequest.findMany({
      where,
      include: {
        student: true,
        subject: true,
      },
      orderBy,
      skip: page * pageSize,
      take: pageSize,
    });

    // ========== FORMAT RESPONSE ==========
    const formatted = payments.map((p, index) => ({
      ...p,
      sno: page * pageSize + index + 1,
      studentName: `${p.student.firstName} ${p.student.lastName}`.trim(),
      subjectTitle: p.subject?.title ?? "",
      createdAt: p.createdAt
        ? new Date(p.createdAt).toLocaleDateString("en-GB")
        : null,
    }));

    return res.json({
      rows: formatted,
      total,
    });
  } catch (err) {
    console.error("Payment List Error:", err);
    return res.status(500).json({ message: "Server error" });
  }
};

exports.getPaymentById = async (req, res) => {
  try {
    const id = Number(req.params.id);

    const payment = await prisma.paymentRequest.findUnique({
      where: { id },
      include: {
        student: {
          select: {
            id: true,
            firstName: true,
            lastName: true,
            email: true,
            phone: true,
          },
        },
        subject: {
          select: {
            id: true,
            title: true,
          },
        },
      },
    });

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

    // Prepare combined fields
    const formatted = {
      ...payment,
      studentName: `${payment.student.firstName} ${payment.student.lastName}`,
      subjectTitle: payment.subject.title,
    };

    res.json(formatted);
  } catch (err) {
    res.status(500).json({ message: err.message });
  }
};


// Student: payment history
exports.getMyPayments = async (req, res) => {
  try {
    const studentId = req.user.id;

    let { page = 1, pageSize = 7 } = req.query;
    page = Number(page);
    pageSize = Number(pageSize);

    const skip = (page - 1) * pageSize;

    const [payments, total] = await Promise.all([
      prisma.paymentRequest.findMany({
        where: { studentId },
        orderBy: { createdAt: "desc" },
        skip,
        take: pageSize,
        include: {
          subject: {
            select: { title: true },
          },
        },
      }),
      prisma.paymentRequest.count({
        where: { studentId },
      }),
    ]);

    const formatted = payments.map((p) => ({
      id: p.id,
      txnId: p.txnId,
      amount: p.amount,
      status: p.status,
      subjectTitle: p.subject?.title ?? "",
      createdAt: p.createdAt,
      approvedAt: p.approvedAt,
      proofImage: p.proofImage,
    }));

    return res.json({
      data: formatted,
      total,
      page,
      pageSize,
    });
  } catch (err) {
    console.error("Student payment history error:", err);
    return res.status(500).json({ message: "Server error" });
  }
};