import { Response } from "express";
import log from "../config/log";
import CONSTANTS from "../config/constants";
import CustomRequest from "../types/requestType";
import { isUserPartner } from "../utils/isUserPartner";
import occupancyDB from "../models/occupancy.model";
import transitServiceDB from "../models/transitService.model";
import staffDB from "../models/staff.model";

const transitService: any = {};

//Tenant App API
transitService.ListForTenant = async (req: CustomRequest, res: Response) => {
  const C = "TransitService";
  const F = "ListForTenant";

  try {
    const { pageNum } = req.query;

    const tenantId = req.id;
    const clientId = req.clientId;
    const limit = 10;

    log.info(
      `[${C}], [${F}], Client Id [${clientId}], Tenant Id [${tenantId}], PageNum [${pageNum}], Tenant Requesting....`,
    );

    const occupancy = await occupancyDB.getByTenantIdAndClientId({
      tenantId,
      clientId: clientId,
    });

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

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

    const locations = await transitServiceDB.getTransitPointsByClientId({
      clientId,
    });

    const timeSlots = [
      { id: 1, slot: "7:00AM - 8:00AM" },
      { id: 2, slot: "8:00AM - 9:00AM" },
      { id: 3, slot: "9:00AM - 10:00AM" },
      { id: 4, slot: "10:00AM - 11:00AM" },
      { id: 5, slot: "11:00AM - 12:00PM" },
      { id: 6, slot: "12:00PM - 1:00PM" },
      { id: 7, slot: "1:00PM - 2:00PM" },
      { id: 8, slot: "2:00PM - 3:00PM" },
      { id: 9, slot: "3:00PM - 4:00PM" },
      { id: 10, slot: "4:00PM - 5:00PM" },
      { id: 11, slot: "5:00PM - 6:00PM" },
      { id: 12, slot: "6:00PM - 7:00PM" },
      { id: 13, slot: "7:00PM - 8:00PM" },
      { id: 14, slot: "8:00PM - 9:00PM" },
      { id: 15, slot: "9:00PM - 10:00PM" },
      { id: 16, slot: "10:00PM - 11:00PM" },
    ];

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

    return res.status(200).json({
      msg: "Bookings fetched successfully",
      isSuccess: true,
      locations: locations || [],
      timeSlots: timeSlots || [],
      bookings: bookings || [],
    });
  } catch (error: any) {
    log.info(`[${C}], [${F}], Error: ${error?.message || error}`);

    return res.status(500).json({
      msg: CONSTANTS.MSG.ERROR_MESSAGE,
      isSuccess: false,
    });
  }
};

transitService.AddTransitRequest = async (
  req: CustomRequest,
  res: Response,
) => {
  const C = "TransitService";
  const F = "AddTransitRequest";

  try {
    const { slot, pickupId, dropId, transitDate } = req.body;

    const tenantId = req.id;
    const clientId = req.clientId;

    log.info(
      `[${C}], [${F}], Client Id [${clientId}], Tenant Id [${tenantId}], Slot [${slot}], Pickup Id [${pickupId}], Drop Id [${dropId}], Transit Date [${transitDate}], Tenant Requesting....`,
    );

    const occupancy = await occupancyDB.getByTenantIdAndClientId({
      tenantId,
      clientId: clientId,
    });

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

    await transitServiceDB.add({
      tenantId,
      clientId,
      transitDate,
      slot,
      pickupId,
      dropId,
      status: CONSTANTS.TRANSIT_REQUEST_STATUS.PENDING,
    });

    log.info(
      `[${C}], [${F}], Client Id [${clientId}], Tenant Id [${tenantId}], Slot [${slot}], Pickup Id [${pickupId}], Drop Id [${dropId}], Booking Added Successfully`,
    );

    return res.status(200).json({
      msg: "Booking added successfully",
      isSuccess: true,
    });
  } catch (error: any) {
    log.info(`[${C}], [${F}], Error: ${error?.message || error}`);

    return res.status(500).json({
      msg: CONSTANTS.MSG.ERROR_MESSAGE,
      isSuccess: false,
    });
  }
};

//Client App API
transitService.ListForClient = async (req: CustomRequest, res: Response) => {
  const C = "TransitService";
  const F = "ListForClient";

  try {
    let { transitDate, slot, pickupId, dropId, pageNum } = req.query;

    transitDate = transitDate && String(transitDate).trim() !== "" && String(transitDate).trim() !== "null" && String(transitDate).trim() !== "undefined" ? String(transitDate).trim() : undefined;
    
    slot = slot && Number(slot) ? slot : undefined;
    
    pickupId = pickupId && Number(pickupId) ? pickupId : undefined;
    
    dropId = dropId && Number(dropId) ? dropId : undefined;  

    const userType = req.userType;
    const limit = 10;

    log.info(
      `[${C}], [${F}], Booking Date [${transitDate}], Slot [${slot}], Pickup Id [${pickupId}], Drop Id [${dropId}], PageNum [${pageNum}]`,
    );

    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}]` : `Client Id [${clientId}]`
        }, ${isPartner ? "Partner Requesting" : "Client Requesting"}....`,
      );
    } else {
      const staff = await staffDB.getById({ id: req.id });
      if (!staff) {
        log.info(
          `[${C}], [${F}], User Id [${req.id}], User Type [${userType}] Staff Not Found`,
        );
        return res.status(400).json({
          msg: "Staff Not Found",
          isSuccess: false,
        });
      }
      clientId = staff.clientId;
      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Staff Id [${req.id}], Staff Role [${staff.role}], Staff Requesting....`,
      );
    }

    const locations = await transitServiceDB.getTransitPointsByClientId({
      clientId,
    });

    const timeSlots = [
      { id: 1, slot: "7:00AM - 8:00AM" },
      { id: 2, slot: "8:00AM - 9:00AM" },
      { id: 3, slot: "9:00AM - 10:00AM" },
      { id: 4, slot: "10:00AM - 11:00AM" },
      { id: 5, slot: "11:00AM - 12:00PM" },
      { id: 6, slot: "12:00PM - 1:00PM" },
      { id: 7, slot: "1:00PM - 2:00PM" },
      { id: 8, slot: "2:00PM - 3:00PM" },
      { id: 9, slot: "3:00PM - 4:00PM" },
      { id: 10, slot: "4:00PM - 5:00PM" },
      { id: 11, slot: "5:00PM - 6:00PM" },
      { id: 12, slot: "6:00PM - 7:00PM" },
      { id: 13, slot: "7:00PM - 8:00PM" },
      { id: 14, slot: "8:00PM - 9:00PM" },
      { id: 15, slot: "9:00PM - 10:00PM" },
      { id: 16, slot: "10:00PM - 11:00PM" },
    ];

    const bookings = await transitServiceDB.getBookingsByClientIdAndFilters({
      clientId,
      transitDate: transitDate || null,
      slot: slot || null,
      pickupId: pickupId || null,
      dropId: dropId || null,
      pageNum,
      limit,
    });

    if (bookings && bookings.length>0) {
      for (let booking of bookings) {
        const matchedSlot = timeSlots.find(ts => ts.id === booking.slot);
        booking.slotTime = matchedSlot ? matchedSlot.slot : "Unknown Slot";
      }
    }

    const bookingCount = await transitServiceDB.getBookingsCountByClientIdAndFilters({
      clientId,
      transitDate: transitDate || null,
      slot: slot || null,
      pickupId: pickupId || null,
      dropId: dropId || null,
    });


    log.info(
      `[${C}], [${F}], Booking Date [${transitDate}], Slot [${slot}], Pickup Id [${pickupId}], Drop Id [${dropId}], PageNum [${pageNum}], Transit Bookings Sent Successfully`,
    );

    return res.status(200).json({
      msg: "Transit bookings fetched successfully",
      isSuccess: true,
      data: bookings || [],
      bookingCount: bookingCount || 0,
      locations: locations || [],
      timeSlots: timeSlots || [],
    });
  } catch (error: any) {
    log.info(`[${C}], [${F}], Error: ${error?.message || error}`);

    return res.status(500).json({
      msg: CONSTANTS.MSG.ERROR_MESSAGE,
      isSuccess: false,
    });
  }
};

transitService.UpdateStatus = async (req: CustomRequest, res: Response) => {
  const C = "TransitService";
  const F = "UpdateStatus";

  try {
    let { id, status } = req.body; 

    const userType = req.userType;
    const limit = 10;

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

    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}]` : `Client Id [${clientId}]`
        }, ${isPartner ? "Partner Requesting" : "Client Requesting"}....`,
      );
    } else {
      const staff = await staffDB.getById({ id: req.id });
      if (!staff) {
        log.info(
          `[${C}], [${F}], User Id [${req.id}], User Type [${userType}] Staff Not Found`,
        );
        return res.status(400).json({
          msg: "Staff Not Found",
          isSuccess: false,
        });
      }
      clientId = staff.clientId;
      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Staff Id [${req.id}], Staff Role [${staff.role}], Staff Requesting....`,
      );
    }

    await transitServiceDB.updateStatus({
      id: id,
      status: status,
    });

    log.info(
      `[${C}], [${F}], Client Id [${clientId}], Booking Id [${id}], Status [${status}], Transit Bookings Status Updated Successfully`,
    );

    return res.status(200).json({
      msg: "Booking status updated successfully",
      isSuccess: true,
    });
  } catch (error: any) {
    log.info(`[${C}], [${F}], Error: ${error?.message || error}`);

    return res.status(500).json({
      msg: CONSTANTS.MSG.ERROR_MESSAGE,
      isSuccess: false,
    });
  }
};

export default transitService;
