import * as admin from "firebase-admin";
import * as functions from "firebase-functions";
import { getUserByDoctorId, getUserTokenById } from "./user-service";
import { timeSlotCol } from "./collections";
import { Message } from "firebase-admin/lib/messaging/messaging-api";

/**
 * this function get called by doctor,
 * send notification to user when appointment is start by the doctor
 */

export const notificationStartAppointment = functions.https.onCall(
  async (request, response) => {
    console.log("Start appointment notification send");
    const { doctorName, roomName, token, timeSlotId } = request;
    let userId = request.userId;
    let userToken = await getUserTokenById(userId); //await userService.getUserTokenById(userId);
    console.log("token user : " + userToken);
    await sendVideoCallNotification(
      roomName,
      doctorName,
      token,
      userId,
      timeSlotId
    );
    await sendNotification(
      userToken,
      `Hi. ${doctorName} has started the consultation session`,
      "Please join the room, to start the consultation session"
    );
  }
);
/**
 * notification for doctor that their timeslot is get ordered
 * @param {string} doctorId doctor id which has the timeslot that get ordered
 */
export async function orderedTimeslotNotification(doctorId: string) {
  try {
    let doctorUser = await getUserByDoctorId(doctorId);
    await sendNotification(
      doctorUser.token,
      "Timeslot has been ordered!",
      "one of your timeslots has been ordered!"
    );
  } catch (error) {
    throw error;
  }
}
/**
 * notification for client that their payment is succefully
 * @param {string} clientId client id that will be sent the notification message
 */
export async function paymentSuccessNotification(
  userId: string,
  orderId: string
) {
  try {
    let userToken = await getUserTokenById(userId);
    console.log("Success payment notification user token : " + userToken);
    console.log("Success payment notification user id : " + userId);
    await sendNotification(
      userToken,
      "Payment Successful!",
      `Thank you, your payment has been successfully received! with order id ${orderId}`
    );
  } catch (error) {
    throw error;
  }
}

/**
 * send notification to doctor, when timeslot is reschedule
 * @param doctorId the doctor id
 */
export async function rescheduleTimeslotNotification(doctorId: string) {
  try {
    let doctorUser = await getUserByDoctorId(doctorId);
    await sendNotification(
      doctorUser.token,
      "Reschedule Appointment",
      "one of your timeslots has been rescheduled"
    );
  } catch (error) {
    console.log(error);
  }
}

/**
sending the notification
 * @param  {string} token user token you wanto send the notification
 * @param  {string} title notification title
 * @param  {string} message notification message to send
 */
export async function sendNotification(
  token: string | string[],
  title: string,
  message: string,
  data?: any
) {
  try {
    // Convert single token to array format for consistency
    const tokenArray = Array.isArray(token) ? token : [token];
    const responses: string[] = [];

    // Loop through each token and send notification
    for (const singleToken of tokenArray) {
      const notifMessage: Message = {
        token: singleToken,
        notification: {
          title: title,
          body: message,
        },
        data: data,
      };

      try {
        const response = await admin.messaging().send(notifMessage);
        responses.push(response);
        console.log(
          `Successfully sent notification to token ${singleToken}: `,
          response
        );
      } catch (err) {
        console.log(
          `Error sending notification to token ${singleToken}: `,
          err
        );
      }
    }

    return responses;
  } catch (error) {
    console.log("Error in sendNotification: ", error);
    throw error;
  }
}

/**
send video call notification to user
 * @param  {string} roomName
 * @param  {string} fromName
 * @param  {string} agoraToken agora.io token room
 * @param  {string} userId
 * @param  {string} timeSlotId
 */
export async function sendVideoCallNotification(
  roomName: string,
  fromName: string,
  agoraToken: string,
  userId: string,
  timeSlotId: string
) {
  try {
    let title = `${fromName} have started the meeting`;
    let body = `please join the meeting, ${fromName} already waiting for you`;
    const payload = {
      notification: {
        title: title,
        body: body,
      },
      data: {
        personSent: fromName,
        type: "call",
        roomName: roomName,
        fromName: fromName,
        token: agoraToken,
        timeSlotId: timeSlotId,
      },
    };
    console.log("user id : " + userId);
    let userToken = await getUserTokenById(userId);
    console.log("user token : " + userToken);
    console.log("payload : " + JSON.stringify(payload));
    admin
      .messaging()
      .sendToDevice(userToken, payload)
      .then(function (response) {
        console.log("Successfully send notification: ", response);
      })
      .catch(function (error) {
        console.log("Error send notification :", error);
      });
  } catch (error) {
    throw error;
  }
}

export const startVideoCallNotification = async (
  fromName: string,
  agoraToken: string,
  doctorId: string,
  userId: string
) => {
  try {
    let title = "Call";
    let body = `${fromName} Calling`;
    const payload = {
      notification: {
        title: title,
        body: body,
      },
      data: {
        type: "call",
        fromName: fromName,
        token: agoraToken,
        userId: userId,
      },
    };
    let doctorUser = await getUserByDoctorId(doctorId);
    let doctorToken = await getUserTokenById(doctorUser.uid);
    await admin.messaging().sendToDevice(doctorToken, payload);
  } catch (error) {
    throw error;
  }
};

/** this function will listen room video call that get create  by doctor, and send notification to the user
 * this notification video call feature
 */
export const notificationVideoCallListen = functions.firestore
  .document("RoomVideoCall/{roomVideoCallId}")
  .onCreate(async (snapshot, context) => {
    const roomVideoCall = snapshot.data();
    const timeSlotId = context.params.roomVideoCallId;
    const timeSlotData = (await timeSlotCol.doc(timeSlotId).get()).data();
    console.log("timeslot data : " + JSON.stringify(timeSlotData));
    if (timeSlotData?.bookByWho?.userId) {
      const userToken = await getUserTokenById(timeSlotData?.bookByWho.userId);
      console.log("user token : " + userToken);
      console.log("room video call data : " + JSON.stringify(roomVideoCall));
      const doctorName = timeSlotData.doctor?.doctorName;
      await sendNotification(
        userToken,
        `${doctorName} have started the meeting`,
        `please join the meeting, ${doctorName} already waiting for you`
      );
    } else {
      throw Error(
        "user id in timeslot data is null, cannot get the user token to send the video call notification"
      );
    }
  });
