import { Response } from "express";
import CONSTANTS from "../config/constants";
import log from "../config/log";
import CustomRequest from "../types/requestType";
import { isUserPartner } from "../utils/isUserPartner";
import staffDB from "../models/staff.model";
import foodDB from "../models/food.model";
import occupancyDB from "../models/occupancy.model";
import moveOutDB from "../models/moveOut.model";
import moment from "moment";
import fsPromises from "fs/promises";
import fs from "fs";
import ExcelJS from "exceljs";

const food: any = {};

food.AddDayMenu = async (req: CustomRequest, res: Response) => {
  const C = "Food Controller";
  const F = "AddDayMenu";

  try {
    const {
      propId,
      dayOfWeek,
      breakfast,
      breakfastTiming,
      lunch,
      lunchNonVeg,
      lunchTiming,
      snacks,
      snacksTiming,
      dinner,
      dinnerNonVeg,
      dinnerTiming,
    } = req.body;

    const userType = req.userType;

    log.info(
      `[${C}], [${F}], Prop Id [${propId}], Day [${dayOfWeek}], Breakfast [${breakfast}], Breakfast Timing [${breakfastTiming}], Lunch [${lunch}], Non Veg Lunch [${lunchNonVeg}], Lunch Timing [${lunchTiming}], Snacks [${snacks}], Snacks Timing [${snacksTiming}], Dinner [${dinner}], Non Veg Dinner [${dinnerNonVeg}], Dinner Timing [${dinnerTiming}]`
    );

    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,
        });
      }
      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Staff Id [${req.id}], Staff Role [${staff.role}], Staff Requesting....`
      );
    }

    const isExists = await foodDB.getMenuByPropIdAndDay({
      propId: propId,
      dayOfWeek: dayOfWeek,
    });
    if (isExists) {
      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Prop Id [${propId}], Day [${dayOfWeek}], Menu Already Exists For This Day`
      );

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

    const isFoodPublished = await foodDB.IsFoodPublishedForProp({
      propId: propId,
      clientId: clientId,
    });

    let status = 0;
    if (isFoodPublished) {
      status = 1;
    }

    const menuId = await foodDB.AddDayMenu({
      clientId: clientId,
      dayOfWeek: dayOfWeek,
      breakfast: breakfast || null,
      breakfastTiming: breakfastTiming || null,
      lunch: lunch || null,
      lunchNonVeg: lunchNonVeg || null,
      lunchTiming: lunchTiming || null,
      snack: snacks || null,
      snackTiming: snacksTiming || null,
      dinner: dinner || null,
      dinnerNonVeg: dinnerNonVeg || null,
      dinnerTiming: dinnerTiming || null,
    });

    await foodDB.addDayMenuToProperty({
      propId: propId,
      clientId: clientId,
      menuId: menuId,
      status: status,
    });

    log.info(
      `[${C}], [${F}], Prop Id [${propId}], Day [${dayOfWeek}], Breakfast [${breakfast}], Breakfast Timing [${breakfastTiming}], Lunch [${lunch}], Lunch Timing [${lunchTiming}], Snacks [${snacks}], Snacks Timing [${snacksTiming}], Dinner [${dinner}], Dinner Timing [${dinnerTiming}], Menu Id [${menuId}], Day menu added successfully`
    );

    return res.status(200).json({
      msg: "Day menu 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,
    });
  }
};

food.UpdateMenuByExcel = async (req: CustomRequest, res: Response) => {
  const C = "Food Controller";
  const F = "UpdateMenuByExcel";

  const file = req.file as Express.Multer.File;
  const removeTmp = async () => {
    try {
      await fsPromises.unlink(file.path);
    } catch (err) {
      log.info(
        `[${C}], [${F}], Error in Removing Temp Image, Error [${JSON.stringify(
          err
        )}]`
      );
    }
  };

  interface DailyMenu {
    dayOfWeek: number;
    breakfast: string;
    breakfastTiming: string;
    lunch: string;
    lunchNonVeg: string;
    lunchTiming: string;
    snacks: string;
    snacksTiming: string;
    dinner: string;
    dinnerNonVeg: string;
    dinnerTiming: string;
  }
  try {
    const { propIds } = req.body;

    log.info(
      `[${C}], [${F}], Prop Id [${propIds}], Is File Uploaded [${file ? `Yes, File [${JSON.stringify(file)}]` : "No"}]`
    );

    let props = null;

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

    if (!req.file) {
      return res.status(400).json({
        msg: 'No file uploaded or file rejected by format filter.',
        isSuccess: false
      });
    }

    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`);

        if (file) {
          await fsPromises.unlink(file.path);
        }

        return res.status(400).json({
          msg: CONSTANTS.MSG.INVALID_REQUEST,
          isSuccess: false,
        });
      }
      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Staff Id [${req.id}], Staff Role [${staff.role}], Staff Requesting....`
      );
    }

    if (!clientId) {
      log.info(`[${C}], [${F}], Client Id [${clientId}], Invalid Client`);

      if (file) {
        await fsPromises.unlink(file.path);
      }

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

    const workbook = new ExcelJS.Workbook();

    if (file && file.path && fs.existsSync(file.path)) {
      await workbook.xlsx.readFile(file.path);
    } else {
      log.info(`[${C}], [${F}], Invalid File Path or File Missing`);

      if (file) {
        await fsPromises.unlink(file.path);
      }

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

    // Get the first worksheet
    const worksheet = workbook.worksheets[0];
    if (!worksheet) {
      log.info(`[${C}], [${F}], Client Id [${clientId}], Prop Id [${propIds}], No worksheet found in the Excel file`);

      if (file) {
        await fsPromises.unlink(file.path);
      }

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

    const menuArray: DailyMenu[] = [];

    // exceljs uses 1-based indexing for rows and columns.
    // Columns 2 to 8 map to MONDAY (Col B) through SUNDAY (Col H).
    let dayOfWeek = 1;
    for (let colIdx = 2; colIdx <= 8; colIdx++) {
      
      // Helper function to safely extract and clean string values from cells
      const getCellString = (rowIdx: number): string => {
        const cell = worksheet.getCell(rowIdx, colIdx);
        // text or value could be an object if it has rich text formatting, so we cast to String
        return cell.value ? String(cell.value).trim() : '';
      };

      // const obj: DailyMenu = {
      //   dayOfWeek:       dayOfWeek,  // Row 1: Day name (MONDAY, etc.)
      //   breakfast:       getCellString(4),  // Row 4: Veg Breakfast
      //   breakfastTiming: getCellString(3),  // Row 3: Breakfast Timing
      //   lunch:           getCellString(7),  // Row 7: Veg Lunch
      //   lunchNonVeg:     getCellString(8),  // Row 8: Non-Veg Lunch
      //   lunchTiming:     getCellString(6),  // Row 6: Lunch Timing
      //   snacks:          getCellString(11), // Row 11: Snacks
      //   snacksTiming:    getCellString(10), // Row 10: Snacks Timing
      //   dinner:          getCellString(14), // Row 14: Veg Dinner
      //   dinnerNonVeg:    getCellString(15), // Row 15: Non-Veg Dinner
      //   dinnerTiming:    getCellString(13)  // Row 13: Dinner Timing
      // };

      const obj: DailyMenu = {
        dayOfWeek:       dayOfWeek,          // Running loop ID (1 for Mon, 7 for Sun)
        breakfast:       getCellString(5),   // Row 5: Breakfast Menu Content
        breakfastTiming: getCellString(4),   // Row 4: Breakfast Timing String
        lunch:           getCellString(8),   // Row 8: Veg Lunch Content
        lunchNonVeg:     getCellString(9),   // Row 9: Non-Veg Lunch Content
        lunchTiming:     getCellString(7),   // Row 7: Lunch Timing String
        snacks:          getCellString(12),  // Row 12: Snacks Content
        snacksTiming:    getCellString(11),  // Row 11: Snacks Timing String
        dinner:          getCellString(15),  // Row 15: Veg Dinner Content
        dinnerNonVeg:    getCellString(16),  // Row 16: Non-Veg Dinner Content
        dinnerTiming:    getCellString(14)   // Row 14: Dinner Timing String
      };

      menuArray.push(obj);
      dayOfWeek += 1;
    }

    if (menuArray && menuArray.length < 1) {
      log.info(`[${C}], [${F}], Client Id [${clientId}], Prop Id [${propIds}], No Menu Found`);

      if (file) {
        await fsPromises.unlink(file.path);
      }

      return res.status(400).json({
        msg: "No Menu Found",
        isSuccess: false,
      });
    }

    log.info(
      `[${C}], [${F}], Client Id [${clientId}], Prop Id [${propIds}], Menu Array [${JSON.stringify(menuArray)}]`
    );

    // return res.status(200).json({
    //   msg: "Menu Array",
    //   isSuccess: true,
    //   data: menuArray
    // });

    let url = null;

    if (file) {
      const folderName = `food_menus`;
      const folderPath = `uploads/documents/client_${clientId}/${folderName}`;
      const fileExtension = file.mimetype.split("/")[1];
      const filename = `Food_Menu_${moment().format("DDMMYYYYHHmmss")}`;

      if (!fs.existsSync(folderPath)) {
        await fsPromises.mkdir(folderPath, { recursive: true });
      }

      const oldPath = `uploads/tmp/${file.filename}`;
      const newPath = `${folderPath}/${filename}`;
      url = `${process.env.UPLOAD_PATH}/documents/client_${clientId}/${folderName}/${filename}`;

      await fsPromises.copyFile(oldPath, newPath);

      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Old Path [${oldPath}], New Path [${newPath}], Url [${url}], Document Saved in DB.`
      );
    }

    if (props && props.length > 0) {
      for (let propId of props) {
        let dayOfWeek = 1;
        for (let menu of menuArray) {
          const existingMenu = await foodDB.getMenuByPropIdAndDayOfWeek({
            clientId,
            propId: Number(propId),
            dayOfWeek,
          });

          log.info(`[${C}], [${F}], Client Id [${clientId}], Prop Id [${propId}], DayOfWeek [${dayOfWeek}], Menu [${JSON.stringify(menu)}], Existing Menu [${JSON.stringify(existingMenu)}]`);

          if (existingMenu) {
            await foodDB.updateDayMenu({
              id: existingMenu.id,
              breakfast: menu.breakfast,
              breakfastTiming: menu.breakfastTiming,
              lunch: menu.lunch,
              lunchNonVeg: menu.lunchNonVeg,
              lunchTiming: menu.lunchTiming,
              snack: menu.snacks,
              snackTiming: menu.snacksTiming,
              dinner: menu.dinner,
              dinnerNonVeg: menu.dinnerNonVeg,
              dinnerTiming: menu.dinnerTiming,
              supportDoc: url,
            });
          } else {
            const menuId = await foodDB.AddDayMenu({
              clientId: Number(clientId),
              dayOfWeek: menu.dayOfWeek,
              breakfast: menu.breakfast,
              breakfastTiming: menu.breakfastTiming,
              lunch: menu.lunch,
              lunchNonVeg: menu.lunchNonVeg,
              lunchTiming: menu.lunchTiming,
              snack: menu.snacks,
              snackTiming: menu.snacksTiming,
              dinner: menu.dinner,
              dinnerNonVeg: menu.dinnerNonVeg,
              dinnerTiming: menu.dinnerTiming,
              supportDoc: url,
            });

            await foodDB.addDayMenuToProperty({
              propId: propId,
              clientId: clientId,
              menuId: menuId,
              status: 1,
            });
          }

          dayOfWeek += 1;
        }
      }
    }

    return res.status(200).json({
      msg: "Menu updated successfully",
      isSuccess: true,
    });

  } catch (error: any) {
    log.info(`[${C}], [${F}], Error: ${error?.message || error}`);

    if (file) {
      await removeTmp();
    }

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

food.ListPropertyMenu = async (req: CustomRequest, res: Response) => {
  const C = "Food Controller";
  const F = "ListPropertyMenu";

  try {
    const { propId } = req.query;

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

    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,
        });
      }
      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Staff Id [${req.id}], Staff Role [${staff.role}], Staff Requesting....`
      );
    }

    const menu = await foodDB.getMenuByPropId({
      propId: propId,
      clientId: clientId,
    });

    log.info(`[${C}], [${F}], Prop Id [${propId}], Menu fetched successfully`);

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

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

food.ReplicateDayMenu = async (req: CustomRequest, res: Response) => {
  const C = "Food Controller";
  const F = "ReplicateDayMenu";

  try {
    const {
      propId,
      dayOfWeek,
      breakfast,
      breakfastTiming,
      lunch,
      lunchNonVeg,
      lunchTiming,
      snacks,
      snacksTiming,
      dinner,
      dinnerNonVeg,
      dinnerTiming,
    } = req.body;

    const userType = req.userType;

    log.info(
      `[${C}], [${F}], Prop Id [${propId}], Day [${dayOfWeek}], Breakfast [${breakfast}], Breakfast Timing [${breakfastTiming}], Lunch [${lunch}], Lunch Non Veg [${lunchNonVeg}], Lunch Timing [${lunchTiming}], Snacks [${snacks}], Snacks Timing [${snacksTiming}], Dinner [${dinner}], Dinner Non Veg [${dinnerNonVeg}], Dinner Timing [${dinnerTiming}]`
    );

    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,
        });
      }
      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Staff Id [${req.id}], Staff Role [${staff.role}], Staff Requesting....`
      );
    }

    const isFoodPublished = await foodDB.IsFoodPublishedForProp({
      propId: propId,
      clientId: clientId,
    });

    let status = 0;
    if (isFoodPublished) {
      status = 1;
    }

    for (let i = 1; i <= 7; i++) {
      if (i === dayOfWeek) {
        continue;
      }
      log.info(`[${C}], [${F}], Replicating menu for day ${i}`);
      const menuId = await foodDB.AddDayMenu({
        clientId: clientId,
        dayOfWeek: i,
        breakfast: breakfast,
        breakfastTiming: breakfastTiming,
        lunch: lunch,
        lunchNonVeg: lunchNonVeg || null,
        lunchTiming: lunchTiming,
        snack: snacks,
        snackTiming: snacksTiming,
        dinner: dinner,
        dinnerNonVeg: dinnerNonVeg || null,
        dinnerTiming: dinnerTiming,
      });

      await foodDB.addDayMenuToProperty({
        propId: propId,
        clientId: clientId,
        menuId: menuId,
        status: status,
      });
    }

    log.info(
      `[${C}], [${F}], Prop Id [${propId}], Day [${dayOfWeek}], Breakfast [${breakfast}], Breakfast Timing [${breakfastTiming}], Lunch [${lunch}], Lunch Timing [${lunchTiming}], Snacks [${snacks}], Snacks Timing [${snacksTiming}], Dinner [${dinner}], Dinner Timing [${dinnerTiming}], Day menu replicated successfully`
    );

    return res.status(200).json({
      msg: "Day menu replicated 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,
    });
  }
};

food.PublishMenu = async (req: CustomRequest, res: Response) => {
  const C = "Food Controller";
  const F = "PublishMenu";

  try {
    const { propId, isFoodPublished } = req.query;

    log.info(
      `[${C}], [${F}], Prop Id [${propId}], Is Published [${isFoodPublished}]`
    );
    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,
        });
      }
      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Staff Id [${req.id}], Staff Role [${staff.role}], Staff Requesting....`
      );
    }

    await foodDB.updateStatusByPropId({
      propId: propId,
      status: isFoodPublished,
    });

    log.info(
      `[${C}], [${F}], Prop Id [${propId}], Menu published successfully`
    );
    return res.status(200).json({
      msg:
        Number(isFoodPublished) === 0
          ? "Menu unpublished successfully"
          : "Menu published 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,
    });
  }
};

food.EditDayMenu = async (req: CustomRequest, res: Response) => {
  const C = "Food Controller";
  const F = "EditDayMenu";

  try {
    const {
      menuId,
      dayOfWeek,
      breakfast,
      breakfastTiming,
      lunch,
      lunchNonVeg,
      lunchTiming,
      snacks,
      snacksTiming,
      dinner,
      dinnerNonVeg,
      dinnerTiming,
    } = req.body;

    log.info(
      `[${C}], [${F}], Menu Id [${menuId}], Day [${dayOfWeek}], Breakfast [${breakfast}], Breakfast Timing [${breakfastTiming}], Lunch [${lunch}], Lunch Non Veg [${lunchNonVeg}], Lunch Timing [${lunchTiming}], Snacks [${snacks}], Snacks Timing [${snacksTiming}], Dinner [${dinner}], Dinner Non Veg [${dinnerNonVeg}], Dinner Timing [${dinnerTiming}]`
    );
    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,
        });
      }
      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Staff Id [${req.id}], Staff Role [${staff.role}], Staff Requesting....`
      );
    }

    await foodDB.updateDayMenu({
      id: menuId,
      breakfast: breakfast,
      breakfastTiming: breakfastTiming,
      lunch: lunch,
      lunchNonVeg: lunchNonVeg || null,
      lunchTiming: lunchTiming,
      snack: snacks,
      snackTiming: snacksTiming,
      dinner: dinner,
      dinnerNonVeg: dinnerNonVeg || null,
      dinnerTiming: dinnerTiming,
    });

    log.info(
      `[${C}], [${F}], Menu Id [${menuId}], Day [${dayOfWeek}], Breakfast [${breakfast}], Breakfast Timing [${breakfastTiming}], Lunch [${lunch}], Lunch Timing [${lunchTiming}], Snacks [${snacks}], Snacks Timing [${snacksTiming}], Dinner [${dinner}], Dinner Timing [${dinnerTiming}], Day menu updated successfully`
    );
    return res.status(200).json({
      msg: "Day menu 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,
    });
  }
};

food.ListMenuForTenant = async (req: CustomRequest, res: Response) => {
  const C = "Food Controller";
  const F = "ListMenuForTenant";

  try {
    const { mealDate= moment().format("YYYY-MM-DD") } = req.query;
    const tenantId = req.id;
    let isEvicted = req.isEvicted;
    let clientId = req.clientId || 0;

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

    let occupancy = await occupancyDB.getByTenantId({ tenantId: tenantId });

    if (isEvicted) {
      occupancy = await moveOutDB.getMovedOutTenants({
        tenantId: tenantId,
      });
    }
    if(clientId != 0){
      occupancy = await occupancyDB.getByTenantIdAndClientId({ tenantId, clientId });
      if (isEvicted) {
        occupancy = await moveOutDB.getByTenantIdAndClientId({
          tenantId: tenantId,
          clientId: clientId,
        });
      }
    }

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

    const menu = await foodDB.getMenuByPropId({
      propId: occupancy.propId,
      clientId: occupancy.clientId,
    });
    if (!menu) {
      log.info(
        `[${C}], [${F}], Client Id [${occupancy.clientId}], Tenant Id [${tenantId}], Prop Id [${occupancy.propId}], No Menu Found`
      );
      return res.status(400).json({
        msg: "No menu found",
        isSuccess: false,
      });
    }

    const mealSelection = await foodDB.getTenantMealSelectionByDate({
      mealDate,
      tenantId,
      clientId,
    });

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

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

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

food.ListTenantHistory = async (req: CustomRequest, res: Response) => {
  const C = "Food Controller";
  const F = "ListTenantHistory";

  try {
    const { mealDate= moment().format("YYYY-MM-DD"), tenantId, isEvicted = 0 } = req.query;

    log.info(`[${C}], [${F}], Tenant Id [${tenantId}], Is Evicted [${isEvicted}], Meal Date [${mealDate}], Tenant Requesting....`);

    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,
        });
      }
      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Staff Id [${req.id}], Staff Role [${staff.role}], Staff Requesting....`
      );
    }

    let occupancy = await occupancyDB.getByTenantIdAndClientId({ tenantId, clientId });
    if (isEvicted) {
      occupancy = await moveOutDB.getByTenantIdAndClientId({
        tenantId: tenantId,
        clientId: clientId,
      });
    }

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

    // const menu = await foodDB.getMenuByPropId({
    //   propId: occupancy.propId,
    //   clientId: occupancy.clientId,
    // });
    // if (!menu) {
    //   log.info(
    //     `[${C}], [${F}], Client Id [${occupancy.clientId}], Tenant Id [${tenantId}], Prop Id [${occupancy.propId}], No Menu Found`
    //   );
    //   return res.status(400).json({
    //     msg: "No menu found",
    //     isSuccess: false,
    //   });
    // }

    const mealSelection = await foodDB.getTenantMealSelectionByDate({
      mealDate,
      tenantId,
      clientId,
    });

    log.info(
      `[${C}], [${F}], Client Id [${occupancy.clientId}], Tenant Id [${tenantId}], Meal Date [${mealDate}], Tenant Meal Selections Fetched Successfully`
    );

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

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

//Tenant App API
food.AddTenantMealSelection = async (req: CustomRequest, res: Response) => {
  const C = "Food Controller";
  const F = "AddTenantMealSelection";

  try {
    const { mealDate, breakfast, isBreakFastOpted=1, lunch, isLunchOpted=1, lunchNonVeg, snacks, isSnacksOpted=1, dinner, isDinnerOpted=1, dinnerNonVeg, } = req.body;

    const tenantId = req.id

    log.info(
      `[${C}], [${F}], Client Id [${req.clientId}], Tenant Id [${tenantId}], Meal Date [${mealDate}], Breakfast [${breakfast}], isBreakFastOpted [${isBreakFastOpted}], Lunch [${lunch}], isLunchOpted [${isLunchOpted}], Lunch Non Veg [${lunchNonVeg}], Snacks [${snacks}], isSnacksOpted [${isSnacksOpted}], Dinner [${dinner}], isDinnerOpted [${isDinnerOpted}], Dinner Non Veg [${dinnerNonVeg}]`
    );

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

    const isBreakFast = breakfast && breakfast.trim() !== "" && breakfast !== "null" && breakfast !== "undefined" ? true : false;

    const isVegLunch = (lunch && lunch.trim() !== "" && lunch !== "null" && lunch !== "undefined") ? true : false;

    const isNonVegLunch = (lunchNonVeg && lunchNonVeg.trim() !== "" && lunchNonVeg !== "null" && lunchNonVeg !== "undefined") ? true : false;

    const isSnacks = snacks && snacks.trim() !== "" && snacks !== "null" && snacks !== "undefined" ? true : false;

    const isVegDinner = (dinner && dinner.trim() !== "" && dinner !== "null" && dinner !== "undefined") ? true : false;
    
    const isNonVegDinner = (dinnerNonVeg && dinnerNonVeg.trim() !== "" && dinnerNonVeg !== "null" && dinnerNonVeg !== "undefined") ? true : false;

    log.info(`Is BreakFast [${isBreakFast}], Is Veg Lunch [${isVegLunch}], Is Non Veg Lunch [${isNonVegLunch}], Is Snacks [${isSnacks}], Is Veg Dinner [${isVegDinner}], Is Non Veg Dinner [${isNonVegDinner}]`);

    if (isBreakFast) {
      const isBreakfastExist = await foodDB.getMealSelectionByTenantIdAndDateAndType({
        clientId: occupancy.clientId,
        tenantId,
        mealDate,
        mealType: CONSTANTS.MEAL_TYPE.BREAKFAST,
      });

      if (!isBreakfastExist) {
        const mealId = await foodDB.addTenantMealSelection({
          clientId: occupancy.clientId,
          propId: occupancy.propId,
          roomId: occupancy.roomId,
          tenantId,
          mealDate,
          mealType: CONSTANTS.MEAL_TYPE.BREAKFAST,
          mealDescription: breakfast,
          dietPreference: CONSTANTS.DIET_PREFERENCE.VEG,
        });

        await foodDB.updateTenantMealStatus({
          id: mealId,
          status: Number(isBreakFastOpted) === 1 ? CONSTANTS.MEAL_CONSUMPTION_STATUS.PENDING : CONSTANTS.MEAL_CONSUMPTION_STATUS.OPT_OUT,
        });
      } else {
        await foodDB.updateTenantMealSelection({
          id: isBreakfastExist[0].id,
          mealDate,
          mealType: CONSTANTS.MEAL_TYPE.BREAKFAST,
          mealDescription: breakfast,
          dietPreference: CONSTANTS.DIET_PREFERENCE.VEG,
          status: Number(isBreakFastOpted) === 1 ? CONSTANTS.MEAL_CONSUMPTION_STATUS.PENDING : CONSTANTS.MEAL_CONSUMPTION_STATUS.OPT_OUT,
        });
      }
    }
    if (isSnacks) {
      const isSnacksExist = await foodDB.getMealSelectionByTenantIdAndDateAndType({
        clientId: occupancy.clientId,
        tenantId,
        mealDate,
        mealType: CONSTANTS.MEAL_TYPE.SNACKS,
      });

      if (!isSnacksExist) {
        const mealId = await foodDB.addTenantMealSelection({
          clientId: occupancy.clientId,
          propId: occupancy.propId,
          roomId: occupancy.roomId,
          tenantId,
          mealDate,
          mealType: CONSTANTS.MEAL_TYPE.SNACKS,
          mealDescription: snacks,
          dietPreference: CONSTANTS.DIET_PREFERENCE.VEG,
        });

        await foodDB.updateTenantMealStatus({
          id: mealId,
          status: Number(isSnacksOpted) === 1 ? CONSTANTS.MEAL_CONSUMPTION_STATUS.PENDING : CONSTANTS.MEAL_CONSUMPTION_STATUS.OPT_OUT,
        });
      } else {
        await foodDB.updateTenantMealSelection({
          id: isSnacksExist[0].id,
          mealDate,
          mealType: CONSTANTS.MEAL_TYPE.SNACKS,
          mealDescription: snacks,
          dietPreference: CONSTANTS.DIET_PREFERENCE.VEG,
          status: Number(isSnacksOpted) === 1 ? CONSTANTS.MEAL_CONSUMPTION_STATUS.PENDING : CONSTANTS.MEAL_CONSUMPTION_STATUS.OPT_OUT,
        });
      } 
    }

    if (isVegLunch || isNonVegLunch) {
      const isLunchExist = await foodDB.getMealSelectionByTenantIdAndDateAndType({
        clientId: occupancy.clientId,
        tenantId,
        mealDate,
        mealType: CONSTANTS.MEAL_TYPE.LUNCH,
      });

      if (!isLunchExist) {
        const mealId = await foodDB.addTenantMealSelection({
          clientId: occupancy.clientId,
          propId: occupancy.propId,
          roomId: occupancy.roomId,
          tenantId,
          mealDate,
          mealType: CONSTANTS.MEAL_TYPE.LUNCH,
          mealDescription: isVegLunch ? lunch : lunchNonVeg,
          dietPreference: isVegLunch ? CONSTANTS.DIET_PREFERENCE.VEG : CONSTANTS.DIET_PREFERENCE.NON_VEG,
        });

        await foodDB.updateTenantMealStatus({
          id: mealId,
          status: Number(isLunchOpted) === 1 ? CONSTANTS.MEAL_CONSUMPTION_STATUS.PENDING : CONSTANTS.MEAL_CONSUMPTION_STATUS.OPT_OUT,
        });
      } else {
        await foodDB.updateTenantMealSelection({
          id: isLunchExist[0].id,
          mealDate,
          mealType: CONSTANTS.MEAL_TYPE.LUNCH,
          mealDescription: isVegLunch ? lunch : lunchNonVeg,
          dietPreference: isVegLunch ? CONSTANTS.DIET_PREFERENCE.VEG : CONSTANTS.DIET_PREFERENCE.NON_VEG,
          status: Number(isLunchOpted) === 1 ? CONSTANTS.MEAL_CONSUMPTION_STATUS.PENDING : CONSTANTS.MEAL_CONSUMPTION_STATUS.OPT_OUT,
        });
      }
    }

    if (isVegDinner || isNonVegDinner) {
      const isDinnerExist = await foodDB.getMealSelectionByTenantIdAndDateAndType({
        clientId: occupancy.clientId,
        tenantId,
        mealDate,
        mealType: CONSTANTS.MEAL_TYPE.DINNER,
      });
      
      if (!isDinnerExist) {
        const mealId = await foodDB.addTenantMealSelection({
          clientId: occupancy.clientId,
          propId: occupancy.propId,
          roomId: occupancy.roomId,
          tenantId,
          mealDate,
          mealType: CONSTANTS.MEAL_TYPE.DINNER,
          mealDescription: isVegDinner ? dinner : dinnerNonVeg,
          dietPreference: isVegDinner ? CONSTANTS.DIET_PREFERENCE.VEG : CONSTANTS.DIET_PREFERENCE.NON_VEG,
        });

        await foodDB.updateTenantMealStatus({
          id: mealId,
          status: Number(isDinnerOpted) === 1 ? CONSTANTS.MEAL_CONSUMPTION_STATUS.PENDING : CONSTANTS.MEAL_CONSUMPTION_STATUS.OPT_OUT,
        });
      } else {
        await foodDB.updateTenantMealSelection({
          id: isDinnerExist[0].id,
          mealDate,
          mealType: CONSTANTS.MEAL_TYPE.DINNER,
          mealDescription: isVegDinner ? dinner : dinnerNonVeg,
          dietPreference: isVegDinner ? CONSTANTS.DIET_PREFERENCE.VEG : CONSTANTS.DIET_PREFERENCE.NON_VEG,
          status: Number(isDinnerOpted) === 1 ? CONSTANTS.MEAL_CONSUMPTION_STATUS.PENDING : CONSTANTS.MEAL_CONSUMPTION_STATUS.OPT_OUT,
        });
      }
    }

    log.info(
      `[${C}], [${F}], Client Id [${occupancy.clientId}], Tenant Id [${tenantId}], Meal Date [${mealDate}], Breakfast [${breakfast}], isBreakFastOpted [${isBreakFastOpted}], Lunch [${lunch}], isLunchOpted [${isLunchOpted}], Lunch Non Veg [${lunchNonVeg}], Snacks [${snacks}], isSnacksOpted [${isSnacksOpted}], Dinner [${dinner}], isDinnerOpted [${isDinnerOpted}], Dinner Non Veg [${dinnerNonVeg}], Tenant Meal Selection Added Successfully`
    );

    return res.status(200).json({
      msg: "Meal Selection 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 For Summary
food.GetTenantMealSelectionSummaryForClient = async (req: CustomRequest, res: Response) => {
  const C = "Food Controller";
  const F = "GetTenantMealSelectionSummaryForClient";

  try {
    let { mealDate, propId } = req.query;

    log.info(`[${C}], [${F}], Meal Date [${mealDate}], Prop Id [${propId}]`);

    let propIds: any = [];

    if (propId && typeof propId === 'string' && propId.trim() !== "" && propId.trim() !== "null" && propId.trim() !== "undefined") {
      propIds = propId.split(',').map(v => Number(v)).filter(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....`
      );
    } 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,
        });
      }
      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Staff Id [${req.id}], Staff Role [${staff.role}], Staff Requesting....`
      );
    }

    let mealSelectionSummary = await foodDB.getTenantMealSelectionSummaryByClientIdAndFilters({
      mealDate,
      propId: propIds && propIds.length > 0 ? propIds : null,
      clientId: Number(clientId),
    });

    const totalTenants = await occupancyDB.getTenantCountByClientIdAndPropIds({
      clientId,
      propId: propIds && propIds.length > 0 ? propIds : null,
    });

    // log.info(`Total Tenants [${totalTenants}]`);

    if (mealSelectionSummary && mealSelectionSummary.length > 0) {
      mealSelectionSummary = [{...mealSelectionSummary[0], totalTenants: totalTenants}];
    }

    // log.info(`Meal Selection Summary [${JSON.stringify(mealSelectionSummary)}]`);

    let menu = false;

    if (propIds && propIds.length > 0) {
      menu = await foodDB.getMenuByPropIdAndDayOfWeek({
        propId: propIds[0],
        clientId: clientId,
        dayOfWeek: moment(mealDate as string).isoWeekday(),
      });
    }

    // log.info(`Menu [${JSON.stringify(menu)}]`);

    log.info(
      `[${C}], [${F}], Client Id [${clientId}], Prop Id [${propId}], Meal Date [${mealDate}], Meal Selection Fetched Successfully`
    );

    return res.status(200).json({
      msg: "Meal Selection Fetched Successfully",
      isSuccess: true,
      data: mealSelectionSummary[0] || {},
      menu: menu,
    });
  } 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 For List
food.GetTenantMealSelectionListForClient = async (req: CustomRequest, res: Response) => {
  const C = "Food Controller";
  const F = "GetTenantMealSelectionListForClient";

  try {
    let { mealDate, propId, dietPreference, mealType, pageNum } = req.query;

    const platform = req.platform;

    const limit = 10;

    log.info(`[${C}], [${F}], Meal Date [${mealDate}], Prop Id [${propId}], Diet Preference [${dietPreference}], Meal Type [${mealType}], Page Num [${pageNum}], Platform [${platform}], Limit [${limit}]`);

    let propIds: any = [];

    if (propId && typeof propId === 'string' && propId.trim() !== "" && propId.trim() !== "null" && propId.trim() !== "undefined") {
      propIds = propId.split(',').map(v => Number(v)).filter(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....`
      );
    } 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,
        });
      }
      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Staff Id [${req.id}], Staff Role [${staff.role}], Staff Requesting....`
      );
    }

    let mealSelection: any = []

    if (Number(platform) === CONSTANTS.TENANT_DEVICE_TYPE.WEB) {
      mealSelection = await foodDB.getTenantMealSelectionByClientIdAndFiltersForWeb({
        mealDate: mealDate,
        propId: propIds && propIds.length > 0 ? propIds : null,
        clientId: Number(clientId),
        mealType: mealType || null,
        dietPreference: dietPreference || null,
      });
    } else {
      mealSelection = await foodDB.getTenantMealSelectionByClientIdAndFilters({
        mealDate: mealDate,
        propId: propIds && propIds.length > 0 ? propIds : null,
        clientId: Number(clientId),
        mealType: mealType || null,
        dietPreference: dietPreference || null,
        pageNum: pageNum,
        limit: limit,
      });
    }

    log.info(
      `[${C}], [${F}], Client Id [${clientId}], Prop Id [${propId}], Meal Date [${mealDate}], Meal Selection Fetched Successfully`
    );

    return res.status(200).json({
      msg: "Meal Selection Fetched Successfully",
      isSuccess: true,
      data: mealSelection || [],
    });
  } catch (error: any) {
    log.info(`[${C}], [${F}], Error: ${error?.message || error}`);

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

food.UpdateTenantMealStatus = async (req: CustomRequest, res: Response) => {
  const C = "Food Controller";
  const F = "UpdateTenantMealStatus";

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

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

    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,
        });
      }
      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Staff Id [${req.id}], Staff Role [${staff.role}], Staff Requesting....`
      );
    }

    await foodDB.updateTenantMealStatus({
      id: mealId,
      status: status,
    });

    log.info(
      `[${C}], [${F}], Client Id [${clientId}], Meal Id [${mealId}], Status [${status}], Meal Selection Updated Successfully`
    );

    return res.status(200).json({
      msg: "Meal Selection 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,
    });
  }
};

food.AddInventory = async (req: CustomRequest, res: Response) => {
  const C = "Food Controller";
  const F = "AddInventory";

  const files = req.files as Express.Multer.File[];
  
  const removeTmpImages = async () => {
    if (!files) return;
    for (const file of files) {
      try { await fsPromises.unlink(file.path); } catch (err) {}
    }
  };

  try {
    let { propId, itemData, mealDate, mealType, type, } = req.body;

    // log.info(`[${C}], [${F}], RAW REQ CHECK -> Is req.files defined? [${!!req.files}], Type of req.files: [${typeof req.files}], Is Array? [${Array.isArray(req.files)}], Length: [${req.files ? (req.files as any).length : 0}]`);

    if (req.files && Array.isArray(req.files) && req.files.length > 0) {
      const incomingFilesLog = (req.files as Express.Multer.File[]).map(f => ({
        incomingKeyName: f.fieldname,      // e.g., "item_0_image_0"
        originalFileName: f.originalname,  // e.g., "breakfast.jpg"
        sizeInBytes: f.size
      }));
      log.info(`[${C}], [${F}], Total Images Found: [${req.files.length}], File Details: ${JSON.stringify(incomingFilesLog)}`);
    } else {
      log.info(`[${C}], [${F}], No images found in this request (req.files is empty or undefined).`);
    }

    log.info(`[${C}], [${F}], Prop Id [${propId}], Meal Date [${mealDate}], Meal Type [${mealType}], Type [${type}], Item Data [${JSON.stringify(itemData)}]`);

    if (Array.isArray(itemData) && itemData.length === 1 && typeof itemData[0] === 'string') {
      itemData = itemData[0];
    }

    if (typeof itemData === 'string') {
      itemData = JSON.parse(itemData);
    }

    if (!Array.isArray(itemData)) {
      return res.status(400).json({ msg: "Invalid itemData structure", isSuccess: false });
    }

    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,
        });
      }
      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Staff Id [${req.id}], Staff Role [${staff.role}], Staff Requesting....`
      );
    }

    const itemImagesMap: { [key: number]: { img1?: string; img2?: string } } = {};

    if (files && files.length > 0) {
      const folderPath = `uploads/documents/client_${clientId}/prop_${propId}/foodInventory/`;
      if (!fs.existsSync(folderPath)) {
        await fsPromises.mkdir(folderPath, { recursive: true });
      }

      for (const file of files) {

        const match = file.fieldname.match(/^item_(\d+)_image_(\d+)$/);
        if (match) {
          const itemIdx = parseInt(match[1], 10);
          const imgIdx = parseInt(match[2], 10); 
          if (imgIdx > 1) {
            try { await fsPromises.unlink(file.path); } catch {}
            continue;
          }

          const fileExtension = file.mimetype.split("/")[1] || "png";
          const filename = `${file.filename}_${moment().format("DDMMYYYYHHmmss")}.${fileExtension}`;
          const newPath = `${folderPath}/${filename}`;
          const fileUrl = `${process.env.UPLOAD_PATH}/documents/client_${clientId}/prop_${propId}/foodInventory/${filename}`;

          await fsPromises.copyFile(file.path, newPath);
          await fsPromises.unlink(file.path);

          if (!itemImagesMap[itemIdx]) itemImagesMap[itemIdx] = {};
          
          if (imgIdx === 0) itemImagesMap[itemIdx].img1 = fileUrl;
          if (imgIdx === 1) itemImagesMap[itemIdx].img2 = fileUrl;
        }
      }
    }

    let i = 0; // flag for image mapping  
    for (let item of itemData) {

      const uploadedImages = itemImagesMap[i] || {};

      const isFoodInventoryRecordExsits = await foodDB.getFoodInventoryByDateAndMealTypeAndName({
        clientId,
        propId: Number(propId),
        mealDate: mealDate,
        mealType: Number(mealType),
        itemName: item.itemName,
      });

      if (isFoodInventoryRecordExsits) {
        log.info(
          `[${C}], [${F}], Client Id [${clientId}], Prop Id [${propId}], Meal Date [${mealDate}], Meal Type [${mealType}], Item Name [${item.itemName}], Food Inventory Record Already Exsits, Updating Record`
        );

        const preparedFoodImg = Number(type) === 1 ? 
          uploadedImages.img1 !== undefined ? 
            uploadedImages.img1 
            : isFoodInventoryRecordExsits.preparedFoodImg
          : isFoodInventoryRecordExsits.preparedFoodImg;
        
        const remainingFoodImg = Number(type) === 2 ? 
          uploadedImages.img1 !== undefined ? 
            uploadedImages.img1 
            : isFoodInventoryRecordExsits.remainingFoodImg 
          : isFoodInventoryRecordExsits.remainingFoodImg;
        
        const leftoverWeight = (item.leftoverWeight === "" || item.leftoverWeight === null || item.leftoverWeight === undefined || item.leftoverWeight === "null") ?
          (typeof isFoodInventoryRecordExsits.leftoverWeight === 'number' || isFoodInventoryRecordExsits.leftoverWeight) ?
            isFoodInventoryRecordExsits.leftoverWeight
            : null
          : Number(item.leftoverWeight);

        const boughtWeight = (item.boughtWeight === "" || item.boughtWeight === null || item.boughtWeight === undefined || item.boughtWeight === "null") ?
          (typeof isFoodInventoryRecordExsits.boughtWeight === 'number' || isFoodInventoryRecordExsits.boughtWeight) ?
            isFoodInventoryRecordExsits.boughtWeight
            : null
          : Number(item.boughtWeight);

        await foodDB.updateFoodInventory({
          id: isFoodInventoryRecordExsits.id,
          mealDate: mealDate,
          mealType: Number(mealType),
          itemName: item.itemName,
          // boughtWeight: Number(item.boughtWeight),
          // leftoverWeight: Number(item.leftoverWeight),
          boughtWeight: boughtWeight,
          leftoverWeight: leftoverWeight,
          preparedFoodImg: preparedFoodImg,
          remainingFoodImg: remainingFoodImg,
        });
      } else {
        log.info(
          `[${C}], [${F}], Client Id [${clientId}], Prop Id [${propId}], Meal Date [${mealDate}], Meal Type [${mealType}], Item Name [${item.itemName}], Food Inventory Record Not Found, Adding Record`
        );

        const preparedFoodImg = Number(type) === 1 ? 
          uploadedImages.img1 !== undefined ? 
            uploadedImages.img1 
            : null
          : null;
        
        const remainingFoodImg = Number(type) === 2 ? 
          uploadedImages.img1 !== undefined ? 
            uploadedImages.img1 
            : null 
          : null;

        const leftoverWeight = (item.leftoverWeight === "" || item.leftoverWeight === null || item.leftoverWeight === undefined || item.leftoverWeight === "null") ?
          (typeof isFoodInventoryRecordExsits.leftoverWeight === 'number' || isFoodInventoryRecordExsits.leftoverWeight) ?
            isFoodInventoryRecordExsits.leftoverWeight
            : null
          : Number(item.leftoverWeight);

        const boughtWeight = (item.boughtWeight === "" || item.boughtWeight === null || item.boughtWeight === undefined || item.boughtWeight === "null") ?
          (typeof isFoodInventoryRecordExsits.boughtWeight === 'number' || isFoodInventoryRecordExsits.boughtWeight) ?
            isFoodInventoryRecordExsits.boughtWeight
            : null
          : Number(item.boughtWeight);
          
        await foodDB.addFoodInventory({
          clientId: Number(clientId),
          propId: Number(propId),
          mealDate: mealDate,
          mealType: Number(mealType),
          itemName: item.itemName,
          // boughtWeight: Number(item.boughtWeight),
          // leftoverWeight: Number(item.leftoverWeight),
          boughtWeight: boughtWeight,
          leftoverWeight: leftoverWeight,
          preparedFoodImg: preparedFoodImg,
          remainingFoodImg: remainingFoodImg,
        });
      }

      i += 1;
    }

    log.info(`[${C}], [${F}], Client Id [${clientId}], Prop Id [${propId}], Meal Date [${mealDate}], Meal Type [${mealType}], Type [${type}], Inventory recorded successfully`)

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

    await removeTmpImages();

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

food.GetInventoryRecordForClient = async (req: CustomRequest, res: Response) => {
  const C = "Food Controller";
  const F = "GetInventoryRecordForClient";

  try {
    let { propId, mealDate, mealType } = req.query;

    log.info(`[${C}], [${F}], Prop Id [${propId}], Meal Date [${mealDate}], Meal Type [${mealType}]`);

    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,
        });
      }
      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Staff Id [${req.id}], Staff Role [${staff.role}], Staff Requesting....`
      );
    }

    const foodInventoryRecord = await foodDB.getFoodInventoryByDateAndMealType({
      clientId,
      propId: Number(propId),
      mealDate: mealDate,
      mealType: Number(mealType),
    });

    log.info(
      `[${C}], [${F}], Client Id [${clientId}], Prop Id [${propId}], Meal Date [${mealDate}], Meal Type [${mealType}], Food Inventory Record Sent Successfully`
    );

    return res.status(200).json({
      msg: "Food Inventory Record Found",
      isSuccess: true,
      data: foodInventoryRecord || [],
    });
  } catch (error: any) {
    log.info(`[${C}], [${F}], Error: ${error?.message || error}`);

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

food.GetInventorySummaryForClient = async (req: CustomRequest, res: Response) => {
  const C = "Food Controller";
  const F = "GetInventoryRecordForClient";

  try {
    let { propId, mealDate } = req.query;

    log.info(`[${C}], [${F}], Prop Id [${propId}], Meal Date [${mealDate}]`);

    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,
        });
      }
      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Staff Id [${req.id}], Staff Role [${staff.role}], Staff Requesting....`
      );
    }

    const foodInventoryRecord = await foodDB.getFoodInventoryByDate({
      clientId,
      propId: Number(propId),
      mealDate: mealDate,
    });

    log.info(
      `[${C}], [${F}], Client Id [${clientId}], Prop Id [${propId}], Meal Date [${mealDate}], Food Inventory Record Sent Successfully`
    );

    return res.status(200).json({
      msg: "Food Inventory Record Found",
      isSuccess: true,
      data: foodInventoryRecord || [],
    });
  } 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 food;
