import models from "$models/index.js";
import {
  accessGrantHelpers,
  identityHelpers,
  paymentCardHelpers,
} from "$helpers/index.js";

const isOwner = (itemUser, requestUser) => {
  const itemUserId = itemUser?._id || itemUser;
  return itemUserId?.toString() === requestUser?._id?.toString();
};

export const ALL = async (req, res) => {
  try {
    const pageSize = req.query.pageSize ? parseInt(req.query.pageSize) : 20;
    const currentPage = req.query.page ? parseInt(req.query.page) : 1;
    const skip = pageSize * currentPage - pageSize;
    const query = {
      usageContext: "distribution",
    };
    const canAccessAllBatches = accessGrantHelpers.hasAllResourceAccess(
      req.user,
      "paymentBatchCards",
    );

    if (!canAccessAllBatches) {
      query.user = req.user._id;
    }

    const batches = await models.paymentBatchCard
      .find(query)
      .limit(pageSize)
      .skip(skip)
      .populate("user", identityHelpers.USER_IDENTITY_PROJECTION)
      .sort({ createdAt: -1 })
      .lean();

    const batchIds = batches.map((batch) => batch._id);
    const stats = batchIds.length
      ? await models.paymentCard.aggregate([
          {
            $match: {
              batchId: { $in: batchIds },
            },
          },
          {
            $group: {
              _id: "$batchId",
              activeCount: {
                $sum: {
                  $cond: [{ $eq: ["$status", "active"] }, 1, 0],
                },
              },
              usedCount: {
                $sum: {
                  $cond: [{ $eq: ["$status", "used"] }, 1, 0],
                },
              },
              cancelledCount: {
                $sum: {
                  $cond: [{ $eq: ["$status", "cancelled"] }, 1, 0],
                },
              },
            },
          },
        ])
      : [];

    const statsMap = new Map(stats.map((item) => [String(item._id), item]));
    const enrichedBatches = batches.map((batch) => ({
      ...batch,
      stats: statsMap.get(String(batch._id)) || {
        activeCount: 0,
        usedCount: 0,
        cancelledCount: 0,
      },
    }));

    const totalData = await models.paymentBatchCard.countDocuments(query);
    const totalPage = pageSize ? Math.ceil(totalData / pageSize) : 0;

    res.status(200).send({
      paymentBatchCards: enrichedBatches,
      totalData,
      currentPage,
      totalPage,
    });
  } catch (error) {
    const status = error.status || 500;
    const message = error.message || "خطا در دریافت بسته‌های کارت";
    return res.status(status).send({ message });
  }
};

export const SINGLE = async (req, res) => {
  try {
    const { id } = req.params;
    const batch = await models.paymentBatchCard
      .findById(id)
      .populate("user", identityHelpers.USER_IDENTITY_PROJECTION);

    if (!batch) {
      return res.status(404).send({ message: "یافت نشد" });
    }

    if (
      !accessGrantHelpers.hasAllResourceAccess(req.user, "paymentBatchCards") &&
      !isOwner(batch.user, req.user)
    ) {
      return res.status(403).send({ message: "دسترسی محدود" });
    }

    const cards = await models.paymentCard
      .find({ batchId: batch._id })
      .sort({ createdAt: -1 })
      .lean();

    return res.status(200).send({
      ...batch.toObject(),
      cards,
    });
  } catch (error) {
    const status = error.status || 500;
    const message = error.message || "خطا در دریافت بسته کارت";
    return res.status(status).send({ message });
  }
};

export const CREATE = async (req, res) => {
  try {
    const createMode = String(req.body.createMode || "single").trim();
    const quantity =
      createMode === "batch" ? Number(req.body.quantity || 0) : 1;
    const amount = Number(req.body.amount || 0);
    const expiresAt = req.body.expiresAt ? new Date(req.body.expiresAt) : null;
    const fundSeoRegisterNo = String(req.body.fundSeoRegisterNo || "").trim();
    const fundName = String(req.body.fundName || "").trim();

    if (!["single", "batch"].includes(createMode)) {
      return res.status(422).send({ message: "نوع ایجاد نامعتبر است" });
    }

    if (!Number.isInteger(quantity) || quantity <= 0) {
      return res.status(422).send({ message: "تعداد کارت نامعتبر است" });
    }

    if (!Number.isSafeInteger(amount) || amount <= 0) {
      return res.status(422).send({ message: "مبلغ کارت نامعتبر است" });
    }

    if (!expiresAt || Number.isNaN(expiresAt.getTime())) {
      return res.status(422).send({ message: "تاریخ انقضا نامعتبر است" });
    }

    if (expiresAt.getTime() <= Date.now()) {
      return res.status(422).send({ message: "تاریخ انقضا باید در آینده باشد" });
    }

    if (!fundSeoRegisterNo) {
      return res.status(422).send({ message: "صندوق کارت الزامی است" });
    }

    if (!fundName) {
      return res.status(422).send({ message: "نام صندوق کارت الزامی است" });
    }

    const title =
      String(req.body.title || "").trim() ||
      (createMode === "single" ? "کارت هدیه" : "بسته کارت هدیه");
    const description = String(req.body.description || "").trim();
    const totalAmount = amount * quantity;

    const batch = await models.paymentBatchCard.create({
      title,
      description,
      createMode,
      usageContext: "distribution",
      quantity,
      amount,
      fundSeoRegisterNo,
      fundName,
      totalAmount,
      status: "active",
      user: req.user._id,
      expiresAt,
    });

    const cardNumbers =
      await paymentCardHelpers.generateUniqueCardNumbers(quantity);
    const cards = await models.paymentCard.insertMany(
      cardNumbers.map((cardNumber) => ({
        batchId: batch._id,
        cardNumber,
        amount,
        fundSeoRegisterNo,
        fundName,
        status: "active",
        expiresAt,
      })),
    );

    return res.status(201).send({
      message: "بسته کارت با موفقیت ایجاد شد",
      data: {
        batch,
        cards,
      },
    });
  } catch (error) {
    const status = error.status || 500;
    const message = error.message || "خطا در ایجاد بسته کارت";
    return res.status(status).send({ message });
  }
};

export const DELETE = async (req, res) => {
  try {
    const { id } = req.params;
    const batch = await models.paymentBatchCard.findById(id);

    if (!batch) {
      return res.status(404).send({ message: "یافت نشد" });
    }

    if (batch.usageContext === "club_reward") {
      return res
        .status(422)
        .send({ message: "این رکورد از بخش جوایز باشگاه مدیریت می‌شود" });
    }

    if (
      !accessGrantHelpers.hasAllResourceAccess(req.user, "paymentBatchCards") &&
      !isOwner(batch.user, req.user)
    ) {
      return res.status(403).send({ message: "دسترسی محدود" });
    }

    const activeCards = await models.paymentCard.countDocuments({
      batchId: batch._id,
      status: "active",
    });

    await models.paymentCard.updateMany(
      {
        batchId: batch._id,
        status: "active",
      },
      {
        $set: {
          status: "cancelled",
          cancelledAt: new Date(),
        },
      },
    );

    await paymentCardHelpers.syncPaymentBatchStatus(batch._id);

    return res.status(200).send({
      message:
        activeCards > 0
          ? "همه کارت‌های فعال این بسته لغو شدند"
          : "کارت فعالی برای لغو در این بسته وجود نداشت",
    });
  } catch (error) {
    const status = error.status || 500;
    const message = error.message || "خطا در لغو بسته کارت";
    return res.status(status).send({ message });
  }
};

export const EXPORT = async (req, res) => {
  try {
    const { id } = req.params;
    const batch = await models.paymentBatchCard.findById(id);

    if (!batch) {
      return res.status(404).send({ message: "یافت نشد" });
    }

    if (
      !accessGrantHelpers.hasAllResourceAccess(req.user, "paymentBatchCards") &&
      !isOwner(batch.user, req.user)
    ) {
      return res.status(403).send({ message: "دسترسی محدود" });
    }

    const cards = await models.paymentCard
      .find({ batchId: batch._id })
      .sort({ createdAt: 1 })
      .lean();

    const csvContent = paymentCardHelpers.buildBatchExportCsv({ batch, cards });
    const safeTitle = String(batch.title || "payment-cards")
      .replace(/[^\w\u0600-\u06FF-]+/g, "-")
      .replace(/-+/g, "-");

    res.setHeader("Content-Type", "text/csv; charset=utf-8");
    res.setHeader(
      "Content-Disposition",
      `attachment; filename="payment-batch-${safeTitle || batch._id}.csv"`,
    );

    return res.status(200).send(csvContent);
  } catch (error) {
    const status = error.status || 500;
    const message = error.message || "خطا در خروجی اکسل بسته کارت";
    return res.status(status).send({ message });
  }
};
