import { Request, Response } from "express";
import Event from "../../models/event";
import { isValidObjectId } from "mongoose";
import { selectedProduct } from "../../types/types";
import { createNewNotification } from "../../service/notification";
import { updateScheduledEvent } from "../../service/scheduler";
import { resolveOccasion, occasionIdOf } from "../../utils/occasion";

const updateEvent = async (req: Request, res: Response) => {
  const { id } = req.params;
  const {
    title, //required: true
    date, //required: true
    time, //required: true
    note, //required: false
    recipientPhone, //required: false
    recurringEvent, //required: true
    gifts, //required: true
    occasion, //required: false (Occasion _id; null clears it)
  } = req.body;

  var parsedDate: Date | undefined = undefined;
  var parsedTime: Date | undefined = undefined;

  if (!isValidObjectId(id)) {
    return res.status(400).json({
      message: "Event ID is not valid",
    });
  }

  if (title && (title === "" || typeof title !== "string")) {
    return res.status(400).json({
      message: "title is not valid",
    });
  }

  if (date) {
    try {
      parsedDate = new Date(date);
      if (isNaN(parsedDate.getDate())) {
        throw new Error("date is not valid or missing");
      }
    } catch (err) {
      return res.status(400).json({
        message: "date is not valid or missing",
      });
    }
  }

  if (time) {
    try {
      parsedTime = new Date(time);
      if (isNaN(parsedTime.getTime())) {
        throw new Error("time is not valid or missing");
      }
    } catch (err) {
      return res.status(400).json({
        message: "time is not valid or missing",
      });
    }
  }

  if (recurringEvent !== undefined && typeof recurringEvent !== "boolean") {
    return res.status(400).json({
      message: "recurringEvent is not valid or missing",
    });
  }

  if (
    gifts &&
    (!Array.isArray(gifts) ||
      gifts.some((gift: selectedProduct) => !isValidObjectId(gift?.product)))
  ) {
    return res.status(400).json({
      message: "gifts should be array of valid gift ids",
    });
  }

  if (note && typeof note !== "string") {
    return res.status(400).json({
      message: "note is not valid ",
    });
  }

  if (recipientPhone && typeof recipientPhone !== "string") {
    return res.status(400).json({
      message: "recipientPhone is not valid ",
    });
  }

  try {
    const existing = await Event.findOne({ _id: id, isDeleted: { $ne: true } });
    if (!existing) {
      return res.status(404).json({ message: "Event not found" });
    }

    const occasionResult = await resolveOccasion(
      occasion,
      existing.occasion?._id?.toString() ?? null,
    );
    if (occasionResult.error) {
      return res.status(400).json({ message: occasionResult.error });
    }

    // Only set fields that were actually sent, so partial updates (e.g. just
    // the occasion) don't overwrite the date with NaN or clear other fields.
    const updateFields: Record<string, unknown> = {
      title,
      note,
      recipientPhone,
      recurringEvent,
      gifts,
    };
    if (parsedDate) {
      updateFields.fullDate = parsedDate;
      updateFields.date = parsedDate.getUTCDate();
      updateFields.month = parsedDate.getUTCMonth() + 1;
      updateFields.year = parsedDate.getUTCFullYear();
    }
    if (parsedTime) updateFields.time = parsedTime;
    if (occasionResult.id !== undefined) updateFields.occasion = occasionResult.id;

    const event = await Event.findOneAndUpdate(
      { _id: id, isDeleted: { $ne: true } },
      updateFields,
      { new: true },
    ).populate("occasion");

    if (!event) {
      return res.status(404).json({ message: "Event not found" });
    }

    try {
      createNewNotification(event.user, "event", {
        title: "Event Updated",
        description: "You updated an event " + event.title,
        sendPushNotification: true,
        event: event._id,
        occasion: occasionIdOf(event.occasion),
      });

      await updateScheduledEvent(event);
    } catch (err) {
      console.log(err);
    }
    res.status(200).json(event);
  } catch (err: any) {
    console.log(err);
    res.status(500).json({ message: err?.message || "Something went wrong" });
  }
};

export { updateEvent };
