import { Response } from "express";
import clientDB from "../models/client.model";
import log from "../config/log";
import CONSTANTS from "../config/constants";
import propertyDB from "../models/property.model";
import CustomRequest from "../types/requestType";
import staffDB from "../models/staff.model";
import { isUserPartner } from "../utils/isUserPartner";
import facilityDB from "../models/facility.model";
import { isPrivilegedStaff } from "../utils/isPrivilegedStaff";
import propertiesTypes from "../schemas/property.schema";
import tenantDB from "../models/tenant.model";
import occupancyDB from "../models/occupancy.model";
import sendNotification from "../utils/sendNotification";
import notificationDB from "../models/notification.model";
import moment from "moment";
import moveOutDB from "../models/moveOut.model";
import flatDB from "../models/flat.model";

const facility: any = {};

facility.Add = async (req: CustomRequest, res: Response) => {
  const C = "Facility Controller";
  const F = "Add";
  try {
    let {
      propIds,
      type,
      maxConcurrentCap,
      name,
      openingTime,
      closingTime,
      maxBookingHours,
      repeatBookingCooldown,
    } = req.body;

    if (propIds && typeof propIds === "string") {
      propIds = propIds.split(",").map(v => v.trim()).filter(Boolean);
    }

    log.info(
      `[${C}], [${F}], Property Id [${propIds}], Type [${type}], Max Concurrent Cap [${maxConcurrentCap}], Name [${name}], Opening Time [${openingTime}], Closing Time [${closingTime}], Max Booking Hours [${maxBookingHours}], Repeat Booking Cooldown [${repeatBookingCooldown}]`,
    );

    const userType = req.userType;
    let { isPartner, clientId } = await isUserPartner(
      Number(userType),
      Number(req.id),
    );
    if (userType === CONSTANTS.USER_TYPE.CLIENT || isPartner) {
      log.info(
        `[${C}], [${F}], ${isPartner
          ? `Partner Id [${req.id}], Partner`
          : `Client Id [${clientId}], Client`
        }, Requesting....`,
      );
    } else {
      const staff = await staffDB.getById({ id: req.id });
      if (!staff) {
        log.info(`[${C}], [${F}], Staff Id [${req.id}], No Staff Found`);
        return res.status(400).json({
          msg: CONSTANTS.MSG.INVALID_REQUEST,
          isSuccess: false,
        });
      }
      let isStaffAllowed = await isPrivilegedStaff(staff.role, 3);
      if (!isStaffAllowed) {
        log.info(
          `[${C}], [${F}], User Type [${userType}], User Id [${req.id}], Staff Not Authorized`,
        );
        return res.status(400).json({
          msg: "Unauthorized Access",
          isSuccess: false,
        });
      }
    }

    if (propIds && propIds.length > 0) {
      for (const propId of propIds) {
        const property = await propertyDB.getById({ id: propId });
        if (!property) {
          log.info(`[${C}], [${F}], Property Id [${propId}], No Property Found`);
          return res.status(400).json({
            msg: "Invalid Property",
            isSuccess: false,
          });
        }

        await facilityDB.add({
          clientId: clientId,
          propId,
          type,
          status: CONSTANTS.FACILITY_STATUS.ACTIVE,
          maxConcurrentCap,
          name,
          openingTime,
          closingTime,
          maxBookingHours,
          repeatBookingCooldown,
        });
      }
    }

    log.info(
      `[${C}], [${F}], Client Id [${clientId}], Property Id [${propIds}], Type [${type}], Max Concurrent Cap [${maxConcurrentCap}], Name [${name}], Opening Time [${openingTime}], Closing Time [${closingTime}], Max Booking Hours [${maxBookingHours}], Repeat Booking Cooldown [${repeatBookingCooldown}], Facility Added Successfully`,
    );
    return res.status(200).json({
      msg: "Facility Added Successfully",
      isSuccess: true,
    });
  } catch (error) {
    log.error(`
      [${C}], [${F}], Error [${error}]`);
    return res.status(500).json({
      msg: "Internal Server Error",
      isSuccess: false,
    });
  }
};

facility.Update = async (req: CustomRequest, res: Response) => {
  const C = "Facility Controller";
  const F = "Update";

  try {
    const {
      facilityId,
      status,
      maxConcurrentCap,
      name,
      openingTime,
      closingTime,
      maxBookingHours,
      repeatBookingCooldown,
    } = req.body;

    log.info(
      `[${C}], [${F}], Facility Id [${facilityId}], Status [${status}], Max Concurrent Cap [${maxConcurrentCap}], Name [${name}], Opening Time [${openingTime}], Closing Time [${closingTime}], Max Booking Hours [${maxBookingHours}], Repeat Booking Cooldown [${repeatBookingCooldown}]`,
    );

    const userType = req.userType;
    let { isPartner, clientId } = await isUserPartner(
      Number(userType),
      Number(req.id),
    );
    if (userType === CONSTANTS.USER_TYPE.CLIENT || isPartner) {
      log.info(
        `[${C}], [${F}], ${isPartner
          ? `Partner Id [${req.id}], Partner`
          : `Client Id [${clientId}], Client`
        }, Requesting....`,
      );
    } else {
      const staff = await staffDB.getById({ id: req.id });
      if (!staff) {
        log.info(`[${C}], [${F}], Staff Id [${req.id}], No Staff Found`);
        return res.status(400).json({
          msg: CONSTANTS.MSG.INVALID_REQUEST,
          isSuccess: false,
        });
      }
      let isStaffAllowed = await isPrivilegedStaff(staff.role, 3);
      if (!isStaffAllowed) {
        log.info(
          `[${C}], [${F}], User Type [${userType}], User Id [${req.id}], Staff Not Authorized`,
        );
        return res.status(400).json({
          msg: "Unauthorized Access",
          isSuccess: false,
        });
      }
    }

    const facility = await facilityDB.getById({ id: facilityId });
    if (!facility) {
      log.info(`[${C}], [${F}], Facility Id [${facilityId}], No Facility Found`);
      return res.status(400).json({
        msg: "Invalid Facility",
        isSuccess: false,
      });
    }

    if (Number(status) === CONSTANTS.FACILITY_STATUS.INACTIVE) {
      log.info(`[${C}], [${F}], Facility Id [${facilityId}], Status [${status}], Facility Status Is Inactive, Deleting Booked Slots`)
      // const bookedSlots = await facilityDB.getFutureBookedSlotsById({ id: facilityId });
      // if (bookedSlots && bookedSlots.length > 0) {
      //   for (let booking of bookedSlots) {
      //     await facilityDB.deleteBooking({ id: booking.id });
      //   }
      // }
    }

    await facilityDB.update({
      id: facilityId,
      status,
      maxConcurrentCap,
      name,
      openingTime,
      closingTime,
      maxBookingHours,
      repeatBookingCooldown,
    });

    log.info(
      `[${C}], [${F}], Client Id [${clientId}], Facility Id [${facilityId}], Status [${status}], Max Concurrent Cap [${maxConcurrentCap}], Name [${name}], Opening Time [${openingTime}], Closing Time [${closingTime}], Max Booking Hours [${maxBookingHours}], Repeat Booking Cooldown [${repeatBookingCooldown}], Facility Updated Successfully`,
    );
    return res.status(200).json({
      msg: "Facility Updated Successfully",
      isSuccess: true,
    });

  } catch (error) {
    log.error(`
      [${C}], [${F}], Error [${error}]`);
    return res.status(500).json({
      msg: "Internal Server Error",
      isSuccess: false,
    });
  }
};

facility.Delete = async (req: CustomRequest, res: Response) => {
  const C = "Facility Controller";
  const F = "Delete";

  try {
    const { facilityId } = req.body;

    log.info(`[${C}], [${F}], Facility Id [${facilityId}]`);

    const userType = req.userType;
    let { isPartner, clientId } = await isUserPartner(
      Number(userType),
      Number(req.id),
    );
    if (userType === CONSTANTS.USER_TYPE.CLIENT || isPartner) {
      log.info(
        `[${C}], [${F}], ${isPartner
          ? `Partner Id [${req.id}], Partner`
          : `Client Id [${clientId}], Client`
        }, Requesting....`,
      );
    } else {
      const staff = await staffDB.getById({ id: req.id });
      if (!staff) {
        log.info(`[${C}], [${F}], Staff Id [${req.id}], No Staff Found`);
        return res.status(400).json({
          msg: CONSTANTS.MSG.INVALID_REQUEST,
          isSuccess: false,
        });
      }
      let isStaffAllowed = await isPrivilegedStaff(staff.role, 3);
      if (!isStaffAllowed) {
        log.info(
          `[${C}], [${F}], User Type [${userType}], User Id [${req.id}], Staff Not Authorized`,
        );
        return res.status(400).json({
          msg: "Unauthorized Access",
          isSuccess: false,
        });
      }
    }

    const facility = await facilityDB.getById({ id: facilityId });
    if (!facility) {
      log.info(`[${C}], [${F}], Client Id [${clientId}], Facility Id [${facilityId}], No Facility Found`);
      return res.status(400).json({
        msg: CONSTANTS.MSG.INVALID_REQUEST,
        isSuccess: false,
      });
    }

    const bookedSlots = await facilityDB.getFutureBookedSlotsById({ id: facilityId });

    // if (bookedSlots && bookedSlots.length > 0) {
    //   for (let booking of bookedSlots) {
    //     await facilityDB.deleteBooking({ id: booking.id });
    //   }
    // }

    await facilityDB.deleteFacility({ id: facilityId });

    log.info(`[${C}], [${F}], Client Id [${clientId}], Facility Id [${facilityId}], Facility Deleted Successfully`);

    return res.status(200).json({
      msg: "Facility Deleted Successfully",
      isSuccess: true,
    });
  } catch (error) {
    log.error(`[${C}], [${F}], Error [${error}]`);
    return res.status(500).json({
      msg: "Internal Server Error",
      isSuccess: false,
    });
  }
};

facility.ListForClient = async (req: CustomRequest, res: Response) => {
  const C = "Facility Controller";
  const F = "ListForClient";

  try {
    let { propFilter, typeFilter } = req.query;

    if (propFilter && typeof propFilter === "string") {
      propFilter = propFilter.split(",").map(v => v.trim()).filter(Boolean);
    }

    if (typeFilter && typeof typeFilter === "string") {
      typeFilter = typeFilter.split(",").map(v => v.trim()).filter(Boolean);
    }

    log.info(`[${C}], [${F}], Property Filter [${propFilter}], Type Filter [${typeFilter}]`);

    let facilities: any[] | boolean = [];

    const userType = req.userType;
    let { isPartner, clientId } = await isUserPartner(
      Number(userType),
      Number(req.id),
    );
    if (userType === CONSTANTS.USER_TYPE.CLIENT || isPartner) {
      log.info(
        `[${C}], [${F}], ${isPartner
          ? `Partner Id [${req.id}], Partner`
          : `Client Id [${clientId}], Client`
        }, Requesting....`,
      );

      facilities = await facilityDB.getByClientIdAndFilters({
        clientId,
        propFilter: propFilter ? propFilter : null,
        typeFilter: typeFilter ? typeFilter : null,
      });

    } else {
      const staff = await staffDB.getById({ id: req.id });
      if (!staff) {
        log.info(`[${C}], [${F}], Staff Id [${req.id}], No Staff Found`);
        return res.status(400).json({
          msg: CONSTANTS.MSG.INVALID_REQUEST,
          isSuccess: false,
        });
      }
      let isStaffAllowed = await isPrivilegedStaff(staff.role, 3);
      if (!isStaffAllowed) {
        log.info(
          `[${C}], [${F}], User Type [${userType}], User Id [${req.id}], Staff Not Authorized`,
        );
        return res.status(400).json({
          msg: "Unauthorized Access",
          isSuccess: false,
        });
      }

      const staffLinkedProps = await propertyDB.getPropsByStaffId({
        staffId: staff.id,
      });

      if (staffLinkedProps) {
        const propertiesIds = staffLinkedProps
          .map((prop: propertiesTypes) => prop.id)
          .join(",");

        facilities = await facilityDB.getByClientIdAndFiltersForStaff({
          clientId,
          propertiesIds,
          propFilter: propFilter ? propFilter : null,
          typeFilter: typeFilter ? typeFilter : null,
        });
      }
    }

    return res.status(200).json({
      result: true,
      message: "Facilities fetched successfully",
      data: { facilities },
    });
  } catch (error) {
    log.error(`[${C}], [${F}], Error [${error}]`);
    return res.status(500).json({
      msg: "Internal Server Error",
      isSuccess: false,
    });
  }
};

facility.ListForTenant = async (req: CustomRequest, res: Response) => {
  const C = "Facility Controller";
  const F = "ListForTenant";

  try {
    let { typeFilter } = req.query;

    if (typeFilter && typeof typeFilter === "string") {
      typeFilter = typeFilter.split(",").map(v => v.trim()).filter(Boolean);
    }

    log.info(`[${C}], [${F}], Client Id [${req.clientId}], Tenant Id [${req.id}], Type Filter [${typeFilter}]`);

    const tenantId = req.id;
    const tenant = await tenantDB.getById({ id: tenantId });
    if (!tenant) {
      log.info(`[${C}], [${F}], Tenant Id [${tenantId}], No Tenant Found`);
      return res.status(400).json({
        msg: CONSTANTS.MSG.INVALID_REQUEST,
        isSuccess: false,
      });
    }

    const clientId = req.clientId;
    const client = await clientDB.getById({ id: clientId });
    if (!client) {
      log.info(`[${C}], [${F}], Client Id [${clientId}], No Client Found`);
      return res.status(400).json({
        msg: CONSTANTS.MSG.INVALID_REQUEST,
        isSuccess: false,
      });
    }

    const occupancy = await occupancyDB.getByTenantIdAndClientId({ tenantId, clientId });
    if (!occupancy) {
      log.info(`[${C}], [${F}], Tenant Id [${tenantId}], No Occupancy Found`);
      return res.status(400).json({
        msg: CONSTANTS.MSG.INVALID_REQUEST,
        isSuccess: false,
      });
    }

    let facilities = await facilityDB.getByClientIdAndFilters({
      clientId,
      propFilter: [occupancy.propId],
      typeFilter: typeFilter ? typeFilter : null,
    });

    if (facilities && facilities.length > 0) {
      for (let facility of facilities) {
        const bookedSlots = await facilityDB.getFutureBookedSlotsById({
          id: facility.id,
        });

        let slots = [];
        let startTime = facility.openingTime;
        while(startTime <= facility.closingTime){
          let endTime = moment(startTime, "HH:mm").add(facility.slotDuration, "hours").format("HH:mm");
          if(endTime > facility.closingTime){
            endTime = facility.closingTime;
          }
          slots.push({
            startTime: startTime,
            endTime: endTime,
          });
          startTime = endTime;
        }

        facility.slots = slots;
        facility.bookedSlots = bookedSlots || [];
      }
    }

    return res.status(200).json({
      result: true,
      message: "Facilities fetched successfully",
      data: facilities ? facilities : [],
    });
  } catch (error) {
    log.error(`[${C}], [${F}], Error [${error}]`);
    return res.status(500).json({
      msg: "Internal Server Error",
      isSuccess: false,
    });
  }
};

facility.GetSlots = async (req: CustomRequest, res: Response) => {
  const C = "Facility Controller";
  const F = "GetSlots";

  try {
    const { facilityId, bookingDate } = req.query;

    log.info(`[${C}], [${F}], Facility Id [${facilityId}], Booking Date [${bookingDate}]`);

    const facility = await facilityDB.getById({ id: Number(facilityId) });
    if (!facility) {
      log.info(`[${C}], [${F}], Facility Id [${facilityId}], No Facility Found`);
      return res.status(400).json({
        msg: CONSTANTS.MSG.INVALID_REQUEST,
        isSuccess: false,
      });
    }

    const bookedSlots = await facilityDB.getFutureBookedSlotsByBookingDate({
      id: facility.id,
      bookingDate: bookingDate,
    });

    let slots = [];
    let startTime = moment(String(bookingDate), "YYYY-MM-DD").set({hour: facility.openingTime.split(":")[0], minute: facility.openingTime.split(":")[1]}).format("YYYY-MM-DD HH:mm:ss");
    let isLastSlot = false;

    while(!isLastSlot){
      let endTime = moment(startTime).add(facility.slotDuration, "hours").format("YYYY-MM-DD HH:mm:ss");
      if(moment(endTime) > moment(String(bookingDate), "YYYY-MM-DD").set({hour: facility.closingTime.split(":")[0], minute: facility.closingTime.split(":")[1]})){
        log.info(`isLastSlot true`);
        endTime = facility.closingTime;
        isLastSlot = true;
      }

      let isOverlapping = false;
      if(bookedSlots && bookedSlots.length > 0){
        isOverlapping = bookedSlots.some((booked: any) => {
            const bookedStart = moment(booked.startTime, ["HH:mm:ss", "HH:mm"]).format("HH:mm");
            const bookedEnd = moment(booked.endTime, ["HH:mm:ss", "HH:mm"]).format("HH:mm");
        
            return moment(startTime).format("HH:mm") < bookedEnd && moment(endTime).format("HH:mm") > bookedStart;
        });
      }

      slots.push({
        startTime: moment(startTime).format("HH:mm"),
        endTime: moment(endTime).format("HH:mm"),
        isFree: isOverlapping ? 0 : 1,
      });

      startTime = endTime;

      if (moment(startTime) >= moment(String(bookingDate), "YYYY-MM-DD").set({hour: facility.closingTime.split(":")[0], minute: facility.closingTime.split(":")[1]})) {
        break;
      }
    }

    let maxSlot = Math.ceil(facility.maxBookingHours / facility.slotDuration) || 1;

    const mediaPlatforms = [
      {id: '1', name: 'Netflix'},
      {id: '2', name: 'Amazon Prime'},
      {id: '3', name: 'Jio Hotstar'},
      {id: '4', name: 'Zee 5'},
      {id: '5', name: 'Sony Liv'},
    ];

    log.info(`[${C}], [${F}], Facility Id [${facilityId}], Booking Date [${bookingDate}], Max Slot [${maxSlot}], Slots Sent Successfully`);

    return res.status(200).json({
      result: true,
      message: "Slots fetched successfully",
      data: slots,
      maxSlot: maxSlot ? maxSlot : 1,
      mediaPlatforms,
      maxNoOfPeople: Number(facility.maxConcurrentCap) ? Number(facility.maxConcurrentCap) : 4,
    });

  } catch (error) {
    log.error(`[${C}], [${F}], Error [${error}]`);
    return res.status(500).json({
      msg: "Internal Server Error",
      isSuccess: false,
    });
  }
};

facility.ListTenantBookings = async (req: CustomRequest, res: Response) => {
  const C = "Facility Controller";
  const F = "ListTenantBookings";

  try {
    const tenantId = req.id;
    const clientId = req.clientId;
    const { pageNum=1 } = req.query;
    const limit = 10;

    log.info(`[${C}], [${F}], Client Id [${clientId}], Tenant Id [${tenantId}], Page Number [${pageNum}], Limit [${limit}]`);

    const tenant = await tenantDB.getById({ id: tenantId });
    if (!tenant) {
      log.info(`[${C}], [${F}], Tenant Id [${tenantId}], No Tenant Found`);
      return res.status(400).json({
        msg: CONSTANTS.MSG.INVALID_REQUEST,
        isSuccess: false,
      });
    }

    const client = await clientDB.getById({ id: clientId });
    if (!client) {
      log.info(`[${C}], [${F}], Client Id [${clientId}], No Client Found`);
      return res.status(400).json({
        msg: CONSTANTS.MSG.INVALID_REQUEST,
        isSuccess: false,
      });
    }

    const occupancy = await occupancyDB.getByTenantIdAndClientId({ tenantId, clientId });
    if (!occupancy) {
      log.info(`[${C}], [${F}], Tenant Id [${tenantId}], No Occupancy Found`);
      return res.status(400).json({
        msg: CONSTANTS.MSG.INVALID_REQUEST,
        isSuccess: false,
      });
    }

    const bookings = await facilityDB.getBookingsByTenantIdAndClientId({ 
      tenantId, 
      clientId, 
      pageNum,
      limit
    });

    let cancelledByName = null;
    if (bookings && bookings.length > 0) {
      for (let booking of bookings) {
        if (booking.cancelledBy && booking.cancelledByUserType) {
          if (booking.cancelledByUserType === CONSTANTS.USER_TYPE.CLIENT) {
            const client = await clientDB.getById({ id: booking.cancelledBy });
            cancelledByName = client.name;
          } else if (booking.cancelledByUserType === CONSTANTS.USER_TYPE.STAFF) {
            const staff = await staffDB.getById({ id: booking.cancelledBy });
            cancelledByName = staff.name;
          } else if (booking.cancelledByUserType === CONSTANTS.USER_TYPE.TENANT) {
            const tenant = await tenantDB.getById({ id: booking.cancelledBy });
            cancelledByName = tenant.name;
          }
        }
        booking.cancelledByName = cancelledByName;
      }
    }

    log.info(`[${C}], [${F}], Client Id [${clientId}], Tenant Id [${tenantId}], Bookings fetched successfully`);

    return res.status(200).json({
      result: true,
      message: "Bookings fetched successfully",
      data: bookings || [],
    });

  } catch (error) {
    log.error(`[${C}], [${F}], Error [${error}]`);
    return res.status(500).json({
      msg: "Internal Server Error",
      isSuccess: false,
    });
  }
};

facility.ListBookingsForClient = async (req: CustomRequest, res: Response) => {
  const C = "Facility Controller";
  const F = "ListBookingsForClient";

  try {
    const { pageNum=1, startDate, endDate } = req.query;
    const limit = 10;
    const userType = req.userType;

    let { isPartner, clientId } = await isUserPartner(
      Number(userType),
      Number(req.id)
    );

    log.info(`[${C}], [${F}], Client Id [${clientId}], Start Date [${startDate}], End Date [${endDate}], Page Number [${pageNum}], Limit [${limit}]`);

    if (userType === CONSTANTS.USER_TYPE.CLIENT || isPartner) {
      log.info(
        `[${C}], [${F}], ${isPartner
          ? `Partner Id [${req.id}], Partner`
          : `Client Id [${clientId}], Client`
        }, Requesting....`
      );
    } else {
      const staffId = req.id;
      log.info(`[${C}], [${F}], Staff Id [${staffId}], Staff Requesting....`);
      const staff = await staffDB.getById({ id: staffId });
      if (!staff) {
        log.info(`[${C}], [${F}], Staff Id [${staffId}], No Staff Found`);
        return res
          .status(400)
          .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
      }
      if (staff.role === CONSTANTS.STAFF_ROLES.PARTNER || staff.role === CONSTANTS.STAFF_ROLES.ADMIN || staff.role === CONSTANTS.STAFF_ROLES.BACK_OFFICE) {
        log.info(
          `[${C}], [${F}], Staff Id [${staff.id}], Staff Role [${staff.role}], Staff Requested....`
        );
      } else {
        log.info(
          `[${C}], [${F}], Staff Id [${req.id}], Staff Not Authorized`
        );
        return res.status(400).json({
          msg: "Unauthorized Access",
          isSuccess: false,
        });
      }
      clientId = staff.clientId;
    }

    const bookings = await facilityDB.listBookingsForClient({
      clientId: Number(clientId),
      startDate: startDate ? moment(String(startDate)).format("YYYY-MM-DD") : null,
      endDate: endDate ? moment(String(endDate)).format("YYYY-MM-DD") : null,
      pageNum: Number(pageNum),
      limit: Number(limit),
    });

    if (bookings && bookings.length > 0) {
      for (let booking of bookings) {
        let isEvicted = false;
        let occupancy = await occupancyDB.getByTenantIdAndClientId({
          tenantId: booking.tenantId,
          clientId: booking.clientId,
        });

        if (!occupancy) {
          isEvicted = true;
          occupancy = await moveOutDB.getByTenantIdAndClientId({
            tenantId: booking.tenantId,
            clientId: booking.clientId,
          });

          if (!occupancy) continue;
        }

        booking.profilePicture = occupancy.profilePicture;
        booking.roomNum = occupancy.roomNum;
        
        let flatName = "";
        if (occupancy.flatId) {
          const { name } = await flatDB.getById({ id: occupancy.flatId });
          flatName = name;
        } else {
          flatName =
            occupancy.floor === "G"
              ? "Ground Floor"
              : "Floor " + occupancy.floor;
        }
        booking.flatName = flatName;

        booking.isEvicted = isEvicted;
        booking.kycStatus = occupancy.kycStatus;
        booking.status = occupancy.status;

        const tenant = await tenantDB.getById({
          id: occupancy.tenantId,
        });

        booking.mobile = tenant.mobile;

        let cancelledByName = null;
        if (booking.cancelledBy && booking.cancelledByUserType) {
          if (booking.cancelledByUserType === CONSTANTS.USER_TYPE.CLIENT) {
            const client = await clientDB.getById({ id: booking.cancelledBy });
            cancelledByName = client.name;
          } else if (booking.cancelledByUserType === CONSTANTS.USER_TYPE.STAFF) {
            const staff = await staffDB.getById({ id: booking.cancelledBy });
            cancelledByName = staff.name;
          } else if (booking.cancelledByUserType === CONSTANTS.USER_TYPE.TENANT) {
            const tenant = await tenantDB.getById({ id: booking.cancelledBy });
            cancelledByName = tenant.name;
          }
        }
        booking.cancelledByName = cancelledByName;
      }
    }

    log.info(`[${C}], [${F}], Client Id [${clientId}], Start Date [${startDate}], End Date [${endDate}], Bookings fetched successfully`);

    return res.status(200).json({
      result: true,
      message: "Bookings fetched successfully",
      data: bookings || [],
    });

  } catch (error) {
    log.error(`[${C}], [${F}], Error [${error}]`);
    return res.status(500).json({
      msg: "Internal Server Error",
      isSuccess: false,
    });
  }
};

facility.Book = async (req: CustomRequest, res: Response) => {
  const C = "Facility Controller";
  const F = "Book";

  try {
    const { facilityId, bookingDate, startTime, endTime, description, noOfPeople, } = req.body;

    log.info(`[${C}], [${F}], Client Id [${req.clientId}], Tenant Id [${req.id}], Facility Id [${facilityId}], Booking Date [${bookingDate}], Start Time [${startTime}], End Time [${endTime}], Description [${description}], No Of People [${noOfPeople}]`);

    const tenantId = req.id;
    const tenant = await tenantDB.getById({ id: tenantId });
    if (!tenant) {
      log.info(`[${C}], [${F}], Tenant Id [${tenantId}], No Tenant Found`);
      return res.status(400).json({
        msg: CONSTANTS.MSG.INVALID_REQUEST,
        isSuccess: false,
      });
    }

    const clientId = req.clientId;
    const client = await clientDB.getById({ id: clientId });
    if (!client) {
      log.info(`[${C}], [${F}], Client Id [${clientId}], No Client Found`);
      return res.status(400).json({
        msg: CONSTANTS.MSG.INVALID_REQUEST,
        isSuccess: false,
      });
    }

    const occupancy = await occupancyDB.getByTenantIdAndClientId({ tenantId, clientId });
    if (!occupancy) {
      log.info(`[${C}], [${F}], Tenant Id [${tenantId}], No Occupancy Found`);
      return res.status(400).json({
        msg: CONSTANTS.MSG.INVALID_REQUEST,
        isSuccess: false,
      });
    }

    const facility = await facilityDB.getById({ id: facilityId });
    if (!facility) {
      log.info(`[${C}], [${F}], Facility Id [${facilityId}], No Facility Found`);
      return res.status(400).json({
        msg: CONSTANTS.MSG.INVALID_REQUEST,
        isSuccess: false,
      });
    }

    const bookedSlots = await facilityDB.getFutureBookedSlotsByBookingDate({ id: facilityId, bookingDate: bookingDate });
    if (bookedSlots && bookedSlots.length > 0) {
      for (let bookedSlot of bookedSlots) {
        // if (startTime > bookedSlot.startTime && startTime < bookedSlot.endTime) {
        //   log.info(`[${C}], [${F}], Facility Id [${facilityId}], Booking Date [${bookingDate}], Start Time [${startTime}], Already Booked`);
        //   return res.status(400).json({
        //     msg: "Facility already booked at this time",
        //     isSuccess: false,
        //   });
        // }
        // if (endTime > bookedSlot.startTime && endTime < bookedSlot.endTime) {
        //   log.info(`[${C}], [${F}], Facility Id [${facilityId}], Booking Date [${bookingDate}], End Time [${endTime}], Already Booked`);
        //   return res.status(400).json({
        //     msg: "Facility already booked at this time",
        //     isSuccess: false,
        //   });
        // }
        if (moment(startTime).format("HH:mm") < moment(bookedSlot.endTime).format("HH:mm") && moment(endTime).format("HH:mm") > moment(bookedSlot.startTime).format("HH:mm")) {
          log.info(`[${C}], [${F}], Facility Id [${facilityId}], Booking Date [${bookingDate}], End Time [${endTime}], Already Booked`);
          return res.status(400).json({
            msg: "Facility already booked at this time",
            isSuccess: false,
          });
        }
      }
    }

    const booking = await facilityDB.addBooking({
      commonFacilityId: facilityId,
      bookingDate,
      startTime,
      endTime,
      tenantId,
      clientId,
      propId: occupancy.propId,
      description,
      noOfPeople,
    });

    const title = `Facility Booked`;
    const messageDescription = `Tenant "${tenant?.name}" has booked facility "${facility.name}" for ${noOfPeople} people on ${bookingDate} from ${startTime} to ${endTime}.`;

    let isNotiSent = false;

    if (client.regId) {
      isNotiSent = await sendNotification({
        title: title,
        message: messageDescription,
        regId: client.regId,
        userId: client.id,
        userType: CONSTANTS.USER_TYPE.CLIENT,
        notiCategory: CONSTANTS.NOTIFICATION_CATEGORY.COMMON_FACILITY_BOOKING,
        clientId: client.id,
      });
    } else {
      await notificationDB.add({
        userId: client.id,
        userType: CONSTANTS.USER_TYPE.CLIENT,
        title,
        message: messageDescription,
        notiCategory: CONSTANTS.NOTIFICATION_CATEGORY.COMMON_FACILITY_BOOKING,
      });
      log.info(
        `[${C}], [${F}], Tenant Id [${tenantId}], No regId found of client [${client.id}]`
      );
    }

    log.info(
      `[${C}], [${F}], Booking Id [${booking}], Facility Id [${facilityId}], Booking Date [${bookingDate}], Start Time [${startTime}], End Time [${endTime}], Tenant Id [${tenantId}], Client Id [${clientId}], Prop Id [${occupancy.propId}], Description [${description}], No Of People [${noOfPeople}], Facility Booked Successfully`
    )

    return res.status(200).json({
      result: true,
      message: "Facility booked successfully",
      data: booking,
    });
  } catch (error) {
    log.error(`[${C}], [${F}], Error [${error}]`);
    return res.status(500).json({
      msg: "Internal Server Error",
      isSuccess: false,
    });
  }
};

facility.CancelBooking = async (req: CustomRequest, res: Response) => {
  const C = "Facility Controller";
  const F = "CancelBooking";

  try {
    const { bookingId } = req.body;

    log.info(`[${C}], [${F}], Booking Id [${bookingId}]`);

    const booking = await facilityDB.getBookingById({ id: Number(bookingId) });
    if (!booking) {
      log.info(`[${C}], [${F}], Booking Id [${bookingId}], No Booking Found`);
      return res.status(400).json({
        msg: CONSTANTS.MSG.INVALID_REQUEST,
        isSuccess: false,
      });
    }

    log.info(`Booking [${JSON.stringify(booking)}]`);

    log.info(`Booking Date [${moment(booking.bookingDate).format("YYYY-MM-DD")}], Current Date [${moment().format("YYYY-MM-DD")}], 
      Booking Start Time [${moment(booking.startTime, ["HH:mm:ss", "HH:mm"]).format("HH:mm")}], Current Time [${moment().format("HH:mm")}]`)

    if (moment(booking.bookingDate).isBefore(moment().format("YYYY-MM-DD"), "day")) {
      log.info(`[${C}], [${F}], Booking Id [${bookingId}], Booking Date [${booking.bookingDate}], Booking Already Passed`);
      return res.status(400).json({
        msg: "Booking already passed",
        isSuccess: false,
      });
    }

    if (moment(booking.bookingDate).format("YYYY-MM-DD") === moment().format("YYYY-MM-DD")) {
      if (moment(booking.startTime, ["HH:mm:ss", "HH:mm"]).isBefore(moment())) {
        log.info(`[${C}], [${F}], Booking Id [${bookingId}], Booking Date [${booking.bookingDate}], Booking Start Time [${booking.startTime}], Booking End Time [${booking.endTime}], Booking Already Passed`);
        return res.status(400).json({
          msg: "Booking cannot be cancelled as it is already started",
          isSuccess: false,
        });
      }
    }

    await facilityDB.deleteBooking({
      id: Number(bookingId),
      cancelledBy: req.id, 
      cancelledByUserType: req.userType,
    });

    log.info(`[${C}], [${F}], Booking Id [${bookingId}], Booking Cancelled Successfully`);

    return res.status(200).json({
      result: true,
      message: "Booking cancelled successfully",
    });
  } catch (error) {
    log.error(`[${C}], [${F}], Error [${error}]`);
    return res.status(500).json({
      msg: "Internal Server Error",
      isSuccess: false,
    });
  }
};

export default facility;
