import express from "express";

import { requireAuth } from "../../middleware/auth.js";
import { validate } from "../../shared/validate.js";
import { httpError } from "../../shared/errors.js";
import { Notification } from "./notification.model.js";
import { User } from "../users/user.model.js";
import {
  listNotificationsSchema,
  markNotificationReadSchema,
  registerPushTokenSchema,
} from "./notifications.schemas.js";

export const notificationsRouter = express.Router();
notificationsRouter.use(requireAuth);

notificationsRouter.get(
  "/",
  validate(listNotificationsSchema),
  async (req, res, next) => {
    try {
      const { limit } = req.validated.query;
      const items = await Notification.find({ userId: req.user._id })
        .sort({ createdAt: -1 })
        .limit(limit)
        .lean();
      res.json({ items });
    } catch (err) {
      next(err);
    }
  }
);

notificationsRouter.get("/unread-count", async (req, res, next) => {
  try {
    const count = await Notification.countDocuments({
      userId: req.user._id,
      isRead: false,
    });
    res.json({ count });
  } catch (err) {
    next(err);
  }
});

notificationsRouter.patch(
  "/:id/read",
  validate(markNotificationReadSchema),
  async (req, res, next) => {
    try {
      const { id } = req.validated.params;

      const updated = await Notification.findOneAndUpdate(
        { _id: id, userId: req.user._id },
        { $set: { isRead: true, readAt: new Date() } },
        { new: true }
      ).lean();

      if (!updated) throw httpError(404, "Notification not found");

      res.json({ notification: updated });
    } catch (err) {
      next(err);
    }
  }
);

notificationsRouter.patch("/read-all", async (req, res, next) => {
  try {
    await Notification.updateMany(
      { userId: req.user._id, isRead: false },
      { $set: { isRead: true, readAt: new Date() } }
    );
    res.json({ ok: true });
  } catch (err) {
    next(err);
  }
});

// Delete a single notification
notificationsRouter.delete("/:id", async (req, res, next) => {
  try {
    const { id } = req.params;
    const deleted = await Notification.findOneAndDelete({
      _id: id,
      userId: req.user._id,
    });
    if (!deleted) throw httpError(404, "Notification not found");
    res.json({ ok: true });
  } catch (err) {
    next(err);
  }
});

// Delete all read notifications
notificationsRouter.delete("/", async (req, res, next) => {
  try {
    await Notification.deleteMany({
      userId: req.user._id,
      isRead: true,
    });
    res.json({ ok: true });
  } catch (err) {
    next(err);
  }
});

// Register Expo push token for the logged-in user
notificationsRouter.post(
  "/push/register",
  validate(registerPushTokenSchema),
  async (req, res, next) => {
    try {
      const { expoPushToken } = req.validated.body;
      await User.findByIdAndUpdate(req.user._id, {
        $addToSet: { expoPushTokens: expoPushToken },
      });
      res.json({ ok: true });
    } catch (err) {
      next(err);
    }
  }
);
