import { Response } from "express";
import log from "../config/log";
import CustomRequest from "../types/requestType";
import CONSTANTS from "../config/constants";
import { isUserPartner } from "../utils/isUserPartner";
import assetsDB from "../models/assets.model";
import propertyDB from "../models/property.model";
import propertyAssetsDB from "../models/propertyAssets.model";
import fsPromises from "fs/promises";
import fs from "fs";
import moment from "moment";
import assetDocumentDB from "../models/assetDocument.model";
import vendorDB from "../models/vendor.model";
import staffDB from "../models/staff.model";
import assetMaintenanceDB from "../models/assetMaintenance.model";
import vendor from "./vendors.controller";
import { ParsedQs } from "qs";
import { isPrivilegedStaff } from "../utils/isPrivilegedStaff";
import expenseDB from "../models/expense.model";

const assets: any = {};

assets.Add = async (req: CustomRequest, res: Response) => {
  const C = "Assets Controller";
  const F = "Add";

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

  try {
    const {
      name,
      type,
      purchaseDate,
      count,
      cost,
      status,
      description,
      depreciationRate,
      vendorId,
      warrentyExpire,
      vehicleNum,
    } = req.body;
    const userType = req.userType;

    log.info(
      `[${C}], [${F}], Name [${name}], Type [${type}], Purchase Date [${purchaseDate}], Count [${count}], Cost [${cost}], Description [${description}], Status [${status}], Depreciation Rate [${depreciationRate}], Vendor Id [${vendorId}], Warrenty Expire [${warrentyExpire}], Vehicle Number [${vehicleNum}]`
    );

    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 {
      // log.info(
      //   `[${C}], [${F}], User Type [${userType}], User Id [${req.id}], Staff Not Authorized`
      // );

      // await removeTmpImages();

      // return res.status(400).json({
      //   msg: "Unauthorized Access",
      //   isSuccess: false,
      // });
      const staffId = req.id;
      log.info(`[${C}], [${F}], Staff Id [${staffId}], Staff Requesting....`);
      const staff = await staffDB.getById({ id: staffId });
      if (!staff) {
        await removeTmpImages();
        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 {
        await removeTmpImages();
        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 assetId = await assetsDB.add({
      name: name,
      clientId: clientId,
      type: type,
      purchaseDate: purchaseDate,
      total: count,
      free: count,
      cost: cost,
      depreciationRate: depreciationRate === "" ? null : depreciationRate,
      status: status,
      description: description,
      vendorId: vendorId,
      warrentyExpire: warrentyExpire === "" ? null : warrentyExpire,
    });

    if (vehicleNum && String(vehicleNum).trim() !== "" && String(vehicleNum).toLowerCase() !== 'null' && String(vehicleNum).toLowerCase() !== 'undefined') {
      await assetsDB.addAssetInfo({
        clientId,
        assetId,
        type: CONSTANTS.ASSET_INFO_TYPES.VEHICLE_NUMBER,
        value: vehicleNum,
      });
    }

    let flag = 0;
    if (files) {
      for (let file of files) {
        if (file !== null) {
          const folderName = `asset_docs/${moment().format("DD_MM_YYYY")}`;
          const folderPath = `uploads/documents/client_${clientId}/asset_${assetId}/${folderName}`;
          const urlBase = folderPath.replace(
            "uploads/",
            `${process.env.UPLOAD_PATH}/`
          );

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

          const ext = file.mimetype.split("/")[1];
          let fileName = `Invoice.${ext}`;
          if (flag !== 0) {
            fileName = `Warranty.${ext}`;
          }

          const oldPath = `uploads/tmp/${files[flag].filename}`;
          const newPath = `${folderPath}/${fileName}`;
          await fsPromises.copyFile(oldPath, newPath);
          const url = `${urlBase}/${fileName}`;

          await assetDocumentDB.add({
            assetId: assetId,
            clientId: clientId,
            type:
              flag === 0
                ? CONSTANTS.DOCUMENT_TYPES.ASSET_INVOICE
                : CONSTANTS.DOCUMENT_TYPES.ASSET_WARRANTY,
            value: url,
          });
        }
        flag += 1;
      }
    }

    log.info(
      `[${C}], [${F}], Client Id [${clientId}], Name [${name}], Type [${type}], Purchase Date [${purchaseDate}], Count [${count}], Cost [${cost}], Description [${description}], Status [${status}], Depreciation Rate [${depreciationRate}], Vendor Id [${vendorId}], Asset Added Successfully`
    );

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

assets.AssignProperty = async (req: CustomRequest, res: Response) => {
  const C = "Assets Controller";
  const F = "AssignProperty";

  try {
    const { assetId, propId, count, status, assignedTo, assignedToId=null, } = req.body;
    const userType = req.userType;

    log.info(
      `[${C}], [${F}], Asset Id [${assetId}], Property Id [${propId}], Count [${count}], Status [${status}], Assigned To [${assignedTo}], Assigned To Id [${assignedToId}]`
    );

    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 {
      // 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 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}], User 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 asset = await assetsDB.getById({ id: assetId });
    if (!asset) {
      log.info(`[${C}], [${F}], Asset Id [${assetId}], No Asset Found`);
      return res.status(400).json({
        msg: "Asset Not Found",
        isSuccess: false,
      });
    }

    if (asset.free < count) {
      log.info(`[${C}], [${F}], Asset Id [${assetId}], Not Enough Assets`);
      return res.status(400).json({
        msg: "Not enough assets to assign",
        isSuccess: false,
      });
    }

    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: "Property Not Found",
        isSuccess: false,
      });
    }

    const isAssigned = await propertyAssetsDB.getByPropId({
      propId: propId,
      assetId: assetId,
    });

    if (isAssigned) {
      await propertyAssetsDB.updateUnitCount({
        id: isAssigned.id,
        unitCount: isAssigned.unitCount + count,
      });
    } else {
      await propertyAssetsDB.add({
        clientId: clientId,
        assetId: assetId,
        propId: propId,
        status: status,
        unitCount: count,
        assignedTo: assignedTo,
        assignedToId: assignedToId,
      });
    }

    await assetsDB.updateFreeUnits({
      id: assetId,
      free: asset.free - count,
    });

    log.info(
      `[${C}], [${F}], Client Id [${clientId}], Asset Id [${assetId}], Property Id [${propId}], Count [${count}], Status [${status}], Assigned To [${assignedTo}], Asset Assigned Successfully`
    );

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

assets.EditBasicDetails = async (req: CustomRequest, res: Response) => {
  const C = "Assets Controller";
  const F = "EditBasicDetails";

  try {
    const { assetId, count, description, vehicleNum, } = req.body;
    const userType = req.userType;

    log.info(
      `[${C}], [${F}], Asset Id [${assetId}], Count [${count}], Description [${description}], Vehicle Num [${vehicleNum}]`
    );

    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 {
      // 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 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}], User Id [${staffId}], No Staff Found`);
        return res
          .status(400)
          .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
      }
      let isStaffAllowed = await isPrivilegedStaff(staff.role, 3);
      //if (staff.role === CONSTANTS.STAFF_ROLES.PARTNER || staff.role === CONSTANTS.STAFF_ROLES.ADMIN || staff.role === CONSTANTS.STAFF_ROLES.BACK_OFFICE) 
      if (isStaffAllowed) {
        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 asset = await assetsDB.getById({ id: assetId });
    if (!asset) {
      log.info(`[${C}], [${F}], Asset Id [${assetId}], No Asset Found`);
      return res.status(400).json({
        msg: "Asset Not Found",
        isSuccess: false,
      });
    }

    const diff = Number(asset.total) - Number(count);

    if (diff !== 0) {
      if (asset.free < diff) {
        log.info(
          `[${C}], [${F}], Asset Id [${assetId}], Cannot Reduce Asset Count while Asset is being used`
        );
        return res.status(400).json({
          msg: "Cannot reduce asset count while it is being used",
          isSuccess: false,
        });
      }

      await assetsDB.updateAssetCount({
        id: assetId,
        total: count,
        free: asset.free - diff,
      });
    }

    await assetsDB.updateDescription({
      id: assetId,
      description: description,
    });

    if (vehicleNum && String(vehicleNum).toLowerCase() !== "null") {
      const isExists = await assetsDB.getAssetInfoByClientIdAndType({
        clientId,
        assetId,
        type: CONSTANTS.ASSET_INFO_TYPES.VEHICLE_NUMBER,
      });
  
      if (isExists) {
        await assetsDB.updateAssetInfo({
          clientId,
          assetId,
          type: CONSTANTS.ASSET_INFO_TYPES.VEHICLE_NUMBER,
          value: vehicleNum,
        });
      }
    }

    log.info(
      `[${C}], [${F}], Client Id [${clientId}], Asset Id [${assetId}], Count [${count}], Description [${description}], Vehicle Number [${vehicleNum}], Asset Details Updated Successfully`
    );

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

assets.EditAssignmentDetails = async (req: CustomRequest, res: Response) => {
  const C = "Assets Controller";
  const F = "EditAssignmentDetails";

  try {
    const { id, assetId, propId, count, status, assignedTo, assignedToId=null } = req.body;
    const userType = req.userType;

    log.info(
      `[${C}], [${F}], ID [${id}], Asset Id [${assetId}], Property Id [${propId}], Count [${count}], Status [${status}], Assigned To [${assignedTo}], Assigned To Id [${assignedToId}]`
    );

    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 {
      // 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 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}], User 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 propertyAsset = await propertyAssetsDB.getById({
      id: id,
    });
    if (!propertyAsset) {
      log.info(`[${C}], [${F}], No Asset Found For Property`);
      return res.status(400).json({
        msg: "No asset found for property",
        isSuccess: false,
      });
    }

    const asset = await assetsDB.getById({ id: propertyAsset.assetId });
    if (!asset) {
      log.info(
        `[${C}], [${F}], Asset Id [${propertyAsset.assetId}], No Asset Found`
      );
      return res.status(400).json({
        msg: "Asset Not Found",
        isSuccess: false,
      });
    }

    const diff = Number(count) - Number(propertyAsset.unitCount);

    if (diff !== 0) {
      if (asset.free < diff) {
        log.info(
          `[${C}], [${F}], Asset Id [${asset.id}], Not Enough Assets Available`
        );
        return res.status(400).json({
          msg: "Not enough assets available",
          isSuccess: false,
        });
      } else {
        await assetsDB.updateFreeUnits({
          id: asset.id,
          free: asset.free - diff,
        });

        await propertyAssetsDB.updateUnitCount({
          id: id,
          unitCount: count,
        });
      }
    }

    if (count === 0) {
      await propertyAssetsDB.delete({
        id: id,
      });
    } else {
      await propertyAssetsDB.update({
        id: id,
        propId: propId,
        status: status,
        assignedTo: assignedTo,
        assignedToId: assignedToId,
      });
    }

    log.info(
      `[${C}], [${F}], Client Id [${clientId}], Asset Id [${assetId}], Property Id [${propId}], Count [${count}], Status [${status}], Assigned To [${assignedTo}], Asset Details Updated Successfully`
    );

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

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

  try {
    const userType = req.userType;

    const { filter, filterVal } = req.query;

    log.info(`[${C}], [${F}], Filter [${filter}], Filter Value [${filterVal}]`);

    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 });
      let isStaffAllowed = await isPrivilegedStaff(staff.role, 3);
      //if (staff?.role !== CONSTANTS.STAFF_ROLES.ADMIN && staff.role !== CONSTANTS.STAFF_ROLES.BACK_OFFICE) 
      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,
        });
      }
      log.info(
        `[${C}], [${F}], Client Id [${staff.clientId}], Staff Id [${req.id}], Staff Role [${staff.role}], Staff Requesting....`
      );
    }

    let assets = await assetsDB.getByClientId({ clientId: clientId });

    for (let asset of assets) {
      const propertyAssets = await propertyAssetsDB.getByAssetId({
        assetId: asset.id,
      });
      const assetDocs = await assetDocumentDB.getByAssetId({
        assetId: asset.id,
      });
      asset.propertyAssets = propertyAssets;
      asset.assetDocs = assetDocs;

      const assetVendor = await vendorDB.getById({ id: asset.vendorId });
      asset.vendorName = assetVendor.name || "";

      const vehicleNumInfo = await assetsDB.getParticularAssetInfoByAssetId({
        assetId: asset.id,
        type: CONSTANTS.ASSET_INFO_TYPES.VEHICLE_NUMBER,
      });
      if (vehicleNumInfo) {
        asset.vehicleNum = vehicleNumInfo?.value;
      } 
      else {
        asset.vehicleNum = null;
      }

      const assetInfo = await assetsDB.getAssetInfoByAssetId({
        assetId: asset.id,
      });
      asset.assetInfo = assetInfo || [];

      const expenseAmount = await expenseDB.getTotalByAssetId({
        clientId,
        assetId: asset.id,
      });
      asset.totalExpense = expenseAmount || 0;
    }

    if (filter === "category") {
      assets = assets.filter((asset: any) => asset.type === Number(filterVal));
    } else if (filter === "vendorId") {
      assets = assets.filter(
        (asset: any) => asset.vendorId === Number(filterVal)
      );
    } else if (filter === "status") {
      if (Number(filterVal) === 5) {
        assets = assets.filter((asset: any) => asset.free !== 0);
      } else {
        assets = assets.filter(
          (asset: any) =>
            Array.isArray(asset.propertyAssets) &&
            asset.propertyAssets.some(
              (propertyAsset: any) => propertyAsset.status === Number(filterVal)
            )
        );
      }
    } else if (filter === "assetName") {
      assets = assets.filter((asset: any) =>
        asset.name.toLowerCase().includes(filterVal?.toString().toLowerCase())
      );
    }

    const staffList = await staffDB.getActiveByClientId({
      clientId,
    });

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

    return res.status(200).json({
      msg: "Assets Listed Successfully",
      isSuccess: true,
      data: assets,
      staffList: staffList || [],
    });
  } catch (error: any) {
    log.info(`[${C}], [${F}], Error: ${error?.message || error}`);
    return res.status(500).json({
      msg: CONSTANTS.MSG.ERROR_MESSAGE,
      isSuccess: false,
    });
  }
};

assets.UploadInspectionImgs = async (req: CustomRequest, res: Response) => {
  const C = "Assets Controller";
  const F = "UploadInspectionImgs";

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

  try {
    const { assetId } = req.body;

    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 {
      log.info(
        `[${C}], [${F}], User Type [${userType}], User Id [${req.id}], Staff Not Authorized`
      );

      await removeTmpImages();

      return res.status(400).json({
        msg: "Unauthorized Access",
        isSuccess: false,
      });
    }

    const asset = await assetsDB.getById({ id: assetId });
    if (!asset) {
      log.info(`[${C}], [${F}], Asset Id [${assetId}], No Asset Found`);

      await removeTmpImages();

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

    if (!files) {
      log.info(`[${C}], [${F}], Client Id [${clientId}], No files uploaded`);
      return res
        .status(400)
        .json({ msg: "No files uploaded", isSuccess: false });
    }

    let count = 0;
    for (let file of files) {
      if (file) {
        const folderName = `asset_docs/${moment().format("DD_MM_YYYY")}`;
        const folderPath = `uploads/documents/client_${clientId}/asset_${assetId}/${folderName}`;
        const urlBase = folderPath.replace(
          "uploads/",
          `${process.env.UPLOAD_PATH}/`
        );

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

        const ext = file.mimetype.split("/")[1];
        let fileName = `asset_img${count}.${ext}`;

        const oldPath = `uploads/tmp/${files[count].filename}`;
        const newPath = `${folderPath}/${fileName}`;
        await fsPromises.copyFile(oldPath, newPath);
        const url = `${urlBase}/${fileName}`;

        await assetDocumentDB.add({
          assetId: assetId,
          clientId: clientId,
          type: CONSTANTS.DOCUMENT_TYPES.ASSET_IMAGE,
          value: url,
        });
      }
      count += 1;
    }

    log.info(
      `[${C}], [${F}], Client Id [${clientId}], Asset Id [${assetId}], Images Uploaded Successfully`
    );

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

assets.AddMaintenance = async (req: CustomRequest, res: Response) => {
  const C = "Assets Controller";
  const F = "AddMaintenance";

  try {
    const {
      assetId,
      propId,
      description,
      cost,
      assignedToId,
      assignedToType,
      lastMaintenance,
      nextMaintenance,
      addExpense=0,
    } = req.body;
    const userType = req.userType;

    log.info(
      `[${C}], [${F}], Asset Id [${assetId}], Property Id [${propId}], Description [${description}], Cost [${cost}], Assigned To Id [${assignedToId}], Assigned To Type [${assignedToType}], Last Maintenance [${lastMaintenance}], Next Maintenance [${nextMaintenance}], Add Expense [${addExpense}]`
    );

    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?.role !== CONSTANTS.STAFF_ROLES.ADMIN) {
        log.info(
          `[${C}], [${F}], User Type [${userType}], User Id [${req.id}], Staff Not Authorized`
        );

        return res.status(400).json({
          msg: "Unauthorized Access",
          isSuccess: false,
        });
      } else {
        log.info(`[${C}], [${F}], Admin Id [${req.id}], Admin Requesting....`);
      }
    }

    const asset = await assetsDB.getById({ id: assetId });
    if (!asset) {
      log.info(`[${C}], [${F}], Asset Id [${assetId}], No Asset Found`);
      return res.status(400).json({
        msg: "Asset Not Found",
        isSuccess: false,
      });
    }

    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: "Property Not Found",
        isSuccess: false,
      });
    }

    let expenseId = null;

    if (addExpense && Number(addExpense) === 1) {
      expenseId = await expenseDB.create({
        type: 76, //Vehicle Maintenance  type
        amount: cost,
        clientId,
        paidDate: moment().format("YYYY-MM-DD HH:mm:ss"),
        paidByUserType: CONSTANTS.USER_TYPE.CLIENT,
        paidBy: clientId,
        paidTo: assignedToId,
        paidToUserType: assignedToType,
        description,
        paymentMethod: CONSTANTS.TRANSACTION_MODES.OFFLINE,
        repetitionType: 0,
        noOfMonths: null,
        dueDate: moment().format("YYYY-MM-DD HH:mm:ss"),
        isPaid: 0,
        paymentAccountNo: null,
        paymentAccountName: null,
        assetId: assetId,
      });
    }

    await assetMaintenanceDB.add({
      clientId: clientId,
      propId: propId,
      assetId: assetId,
      description: description,
      cost: cost,
      assignedToId: assignedToId,
      assignedToType: assignedToType,
      lastMaintenance: lastMaintenance,
      nextMaintenance: nextMaintenance,
      expenseId: expenseId,
    });

    log.info(
      `[${C}], [${F}], Client Id [${clientId}], Asset Id [${assetId}], Property Id [${propId}], Description [${description}], Cost [${cost}], Assigned To Id [${assignedToId}], Assigned To Type [${assignedToType}], Last Maintenance [${lastMaintenance}], Next Maintenance [${nextMaintenance}], Asset Maintenance Added Successfully`
    );
    return res.status(200).json({
      msg: "Asset Maintenance 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,
    });
  }
};

assets.ListMaintenanceRecordsForPropAndAsset = async (
  req: CustomRequest,
  res: Response
) => {
  const C = "Assets Controller";
  const F = "ListMaintenanceRecordsForPropAndAsset";

  try {
    const { assetId, propId } = req.params;
    const userType = req.userType;
    log.info(`[${C}], [${F}], Asset Id [${assetId}]`);

    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?.role !== CONSTANTS.STAFF_ROLES.ADMIN || staff?.role !== CONSTANTS.STAFF_ROLES.PARTNER  || staff?.role !== CONSTANTS.STAFF_ROLES.BACK_OFFICE) {
        log.info(
          `[${C}], [${F}], User Type [${userType}], User Id [${req.id}], Staff Not Authorized`
        );

        return res.status(400).json({
          msg: "Unauthorized Access",
          isSuccess: false,
        });
      } else {
        log.info(`[${C}], [${F}], Admin Id [${req.id}], Staff Requesting....`);
      }
    }

    const asset = await assetsDB.getById({ id: assetId });
    if (!asset) {
      log.info(`[${C}], [${F}], Asset Id [${assetId}], No Asset Found`);
      return res.status(400).json({
        msg: "Asset Not Found",
        isSuccess: false,
      });
    }

    const maintenanceRecords = await assetMaintenanceDB.getByPropIdAndAssetId({
      assetId: assetId,
      propId: propId,
    });

    if (maintenanceRecords) {
      for (let record of maintenanceRecords) {
        if (record.assignedToType === CONSTANTS.USER_TYPE.STAFF) {
          const staff = await staffDB.getById({
            id: record.assignedToId,
          });
          record.vendorName = staff.name;
        } else {
          const vendor = await vendorDB.getById({
            id: record.assignedToId,
          });
          record.vendorName = vendor.name;
        }
      }
    }

    let propName = "";
    const property = await propertyDB.getById({ id: propId });
    if (property) {
      propName = property.name;
    }

    let assetName = asset.name;
    let assetType = asset.type;

    const vendors = await vendorDB.getByClientId({
      clientId,
    });

    log.info(
      `[${C}], [${F}], Client Id [${clientId}], Asset Id [${assetId}], Asset Maintenance Records Sent Successfully`
    );

    return res.status(200).json({
      msg: "Asset Maintenance Records Sent Successfully",
      isSuccess: true,
      data: maintenanceRecords || [],
      vendorList: vendors || [],
      propName: propName,
      assetType: assetType,
      assetName: assetName,
    });
  } catch (error: any) {
    log.info(`[${C}], [${F}], Error: ${error?.message || error}`);
    return res.status(500).json({
      msg: CONSTANTS.MSG.ERROR_MESSAGE,
      isSuccess: false,
    });
  }
};

assets.EditMaintenanceRecord = async (req: CustomRequest, res: Response) => {
  const C = "Assets Controller";
  const F = "EditMaintenanceRecord";

  try {
    const {
      id,
      description,
      cost,
      assignedToId,
      assignedToType,
      lastMaintenance,
      nextMaintenance,
    } = req.body;
    const userType = req.userType;
    log.info(
      `[${C}], [${F}], ID [${id}], Description [${description}], Cost [${cost}], Assigned To Id [${assignedToId}], Assigned To Type [${assignedToType}], Last Maintenance [${lastMaintenance}], Next Maintenance [${nextMaintenance}]`
    );

    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?.role !== CONSTANTS.STAFF_ROLES.ADMIN) {
        log.info(
          `[${C}], [${F}], User Type [${userType}], User Id [${req.id}], Staff Not Authorized`
        );

        return res.status(400).json({
          msg: "Unauthorized Access",
          isSuccess: false,
        });
      } else {
        log.info(`[${C}], [${F}], Admin Id [${req.id}], Admin Requesting....`);
      }
    }

    const maintenanceRecord = await assetMaintenanceDB.getById({ id: id });
    if (!maintenanceRecord) {
      log.info(`[${C}], [${F}], ID [${id}], No Asset Maintenance Record Found`);
      return res.status(400).json({
        msg: "Asset Maintenance Record Not Found",
        isSuccess: false,
      });
    }

    await assetMaintenanceDB.edit({
      id: id,
      description: description,
      cost: cost,
      assignedToId: assignedToId,
      assignedToType: assignedToType,
      lastMaintenance: lastMaintenance,
      nextMaintenance: nextMaintenance,
    });

    if (maintenanceRecord?.expenseId && Number(maintenanceRecord?.expenseId)) {
      const expense = await expenseDB.getById({ id: maintenanceRecord?.expenseId });
      if (expense) {
        let finalAmt = cost;
  
        if (expense.balance !== cost && expense.balance !== expense.amount) {
          finalAmt = expense.amount + (cost - expense.balance);
        }
  
        await expenseDB.update({
          type: 76, //Vehicle Maintenance Type 
          amount: finalAmt,
          balance: cost,
          paidDate: moment().format("YYYY-MM-DD hh:mm:ss"),
          paidByUserType: CONSTANTS.USER_TYPE.CLIENT,
          paidToUserType: assignedToType,
          paidBy: clientId,
          paidTo: assignedToId,
          description,
          paymentMethod: CONSTANTS.TRANSACTION_MODES.OFFLINE,
          id: maintenanceRecord?.expenseId,
        });
      }

    }

    log.info(
      `[${C}], [${F}], Client Id [${clientId}], ID [${id}], Description [${description}], Cost [${cost}], Assigned To Id [${assignedToId}], Assigned To Type [${assignedToType}], Last Maintenance [${lastMaintenance}], Next Maintenance [${nextMaintenance}], Asset Maintenance Record Edited Successfully`
    );

    return res.status(200).json({
      msg: "Asset Maintenance Record Edited 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,
    });
  }
};

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

  try {
    const { id } = req.body;
    const userType = req.userType;

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

    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}], Client Id [${clientId}], Staff Id [${req.id}], Staff Not 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}], Client Id [${clientId}], Staff Id [${req.id}], Staff Role [${staff?.role}], Staff Not Authorized`
        );

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

    const propertyAssets = await propertyAssetsDB.getByAssetId({
      assetId: id,
    });

    if (propertyAssets) {
      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Asset Id [${id}], Asset Is Assigned, Cannot Deleted`
      );

      return res.status(400).json({
        msg: "Cannot delete assigned assets",
        isSuccess: false,
      });
    }

    await assetsDB.updateStatus({
      id,
      status: CONSTANTS.ASSETS_STATUS.DELETED,
    });

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

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

assets.UpdateAssetInfo = async (req: CustomRequest, res: Response) => {
  const C = "Asset Controller";
  const F = "UpdateAssetInfo";

  try {
    const { assetId, type, value } = req.body;

    log.info(`[${C}], [${F}], Asset Id [${assetId}], Type [${type}], Value [${value}]`);

    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}], Client Id [${clientId}], Staff Id [${req.id}], Staff Not 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}], Client Id [${clientId}], Staff Id [${req.id}], Staff Role [${staff?.role}], Staff Not Authorized`
        );

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

    const isExists = await assetsDB.getAssetInfoByClientIdAndType({
      clientId,
      assetId,
      type,
    });

    if (isExists) {
      await assetsDB.updateAssetInfo({
        clientId,
        assetId,
        type,
        value,
      });
    } else {
      await assetsDB.addAssetInfo({
        clientId,
        assetId,
        type: type,
        value: value,
      });
    }

    log.info(`[${C}], [${F}], Client Id [${clientId}], Asset Id [${assetId}], Type [${type}], Value [${value}], Asset Info Updated Successfully`)

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

assets.DeleteAssetInfo = async (req: CustomRequest, res: Response) => {
  const C = "Asset Controller";
  const F = "DeleteAssetInfo";

  try {
    const { assetId, type } = req.body;

    log.info(`[${C}], [${F}], Asset Id [${assetId}], Type [${type}]`);

    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}], Client Id [${clientId}], Staff Id [${req.id}], Staff Not 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}], Client Id [${clientId}], Staff Id [${req.id}], Staff Role [${staff?.role}], Staff Not Authorized`
        );

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

    await assetsDB.deleteAssetInfo({
      clientId,
      assetId,
      type,
    });

    log.info(`[${C}], [${F}], Client Id [${clientId}], Asset Id [${assetId}], Type [${type}], Asset Info Deleted Successfully`)

    return res.status(200).json({
      msg: "Asset alert deleted 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 assets;
