import { Response } from "express";
import clientDB from "../models/client.model";
import log from "../config/log";
import CONSTANTS from "../config/constants";
import propertyDB from "../models/property.model";
import CustomRequest from "../types/requestType";
import extraChargeDB from "../models/extraCharges.model";
import getExtraChargeName from "../utils/getExtraChargeName";
import propertiesTypes from "../schemas/property.schema";
import staffDB from "../models/staff.model";
import expenseDB from "../models/expense.model";
import vendorDB from "../models/vendor.model";
import exp from "constants";
import { isUserPartner } from "../utils/isUserPartner";
import landlordDB from "../models/landlord.model";

const vendor: any = {};

vendor.AddVendor = async (req: CustomRequest, res: Response) => {
  const C = "Vendor Controller";
  const F = "AddVendor";

  try {
    let { name, mobile, type=1 } = req.body;

    const userType = req.userType;
    let clientId = req.id;

    if (userType === CONSTANTS.USER_TYPE.STAFF) {
      const staff = await staffDB.getById({ id: req.id });
      if (!staff) {
        log.info(
          `[${C}], [${F}], Name [${name}], Mobile [${mobile}], Type [${type}], Staff Id [${req.id}], No Staff Found`
        );
        return res
          .status(400)
          .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
      }

      clientId = staff.clientId;

      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Name [${name}], Mobile [${mobile}], Type [${type}], Staff Id [${req.id}], Staff Requested....`
      );
    } else {
      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Name [${name}], Mobile [${mobile}], Type [${type}], Client Requested....`
      );
    }

    let alreadyAdded = false;

    const client = await clientDB.getById({ id: clientId });

    if (!client) {
      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Name [${name}], Mobile [${mobile}], Type [${type}], No Client Found`
      );
      return res
        .status(400)
        .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
    }

    if (mobile === client.mobile) {
      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Name [${name}], Mobile [${mobile}], Type [${type}], Trying to add owner as vendor`
      );
      return res
        .status(400)
        .json({ msg: "You can't add owner as vendor", isSuccess: false });
    }

    //Want to discuss -- 29-09-2025(Abhinav)
    if (mobile.length > 0) {
      const isSameMobileExists = await vendorDB.getByMobileAndClientId({
        mobile: mobile,
        clientId: clientId,
      });
      // const isSameMobileExists = await vendorDB.getByMobile({
      //   mobile,
      // });

      if (isSameMobileExists) {
        if (isSameMobileExists.status === CONSTANTS.VENDOR_STATUS.DELETED) {
          log.info(
            `[${C}], [${F}], Client Id [${clientId}], Name [${name}], Mobile [${mobile}], Type [${type}], Vendor Already Exsits With Deleted Status Updating Status`
          );

          await vendorDB.updateStatus({
            id: isSameMobileExists.id,
            status: CONSTANTS.VENDOR_STATUS.ACTIVE,
          });

          await vendorDB.edit({
            id: isSameMobileExists.id,
            clientId: clientId,
            name: name,
            mobile: mobile,
            type: type
          });

          alreadyAdded = true;
        } else {
          log.info(
            `[${C}], [${F}], Client Id [${clientId}], Name [${name}], Mobile [${mobile}], Type [${type}], Another account exists with the same mobile`
          );
          return res.status(400).json({
            msg: "Another account exists with the same mobile",
            isSuccess: false,
          });
        }
      }
    }

    if (!alreadyAdded) {
      await vendorDB.create({
        name,
        mobile,
        clientId,
        type: type,
      });

      if (type === CONSTANTS.VENDOR_TYPES.LANDLORD) {
        await landlordDB.create({
          name,
          mobile,
        });
      }
    }

    // For web, add expense----->
    let users = await staffDB.getActiveByClientId({ clientId });
    if (!users) users = [];

    let vendors = await vendorDB.getByClientId({ clientId });
    if (!vendors) vendors = [];

    vendors = [...users, ...vendors];
    // ------->

    log.info(
      `[${C}], [${F}], Client Id [${clientId}], Name [${name}], Mobile [${mobile}], Vendor Added Successfully`
    );

    return res.status(200).json({
      msg: "Vendor added successfully!",
      isSuccess: true,
      vendors, // For web, add expense
    });
  } catch (error: any) {
    log.info(`[${C}], [${F}], Error: ${error?.message || error}`);
    return res.status(500).json({
      msg: CONSTANTS.MSG.ERROR_MESSAGE,
      isSuccess: false,
    });
  }
};

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

  try {
    const userType = req.userType;
    const { pageNum, s } = req.query;
    // const limit = 10;

    log.info(`[${C}], [${F}], User Type [${userType}], Page Num [${pageNum}], Search Val [${s}]`);

    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,
        });
      }
      // if (staff.role !== CONSTANTS.STAFF_ROLES.ADMIN && staff.role !== CONSTANTS.STAFF_ROLES.BACK_OFFICE && staff.role !== CONSTANTS.STAFF_ROLES.FINANCE_ADMIN) {
      //   log.info(
      //     `[${C}], [${F}], User Type [${userType}], User Id [${req.id}], Staff Not Admin, Back Office`
      //   );
      //   return res.status(400).json({
      //     msg: "Unauthorized Access",
      //     isSuccess: false,
      //   });
      // }
      log.info(
        `[${C}], [${F}], Staff Id [${req.id}], Staff Role [${staff.role}], Staff Requested....`
      );
    }

    let vendors = [];

    if (s && s !== "" && s !== "undefined" && s !== "null") {
      vendors = await vendorDB.getByClientIdAndSearchVal({
        clientId,
        searchVal: s,
      });
    } else {
      vendors = await vendorDB.getByClientId({
        clientId,
        // pageNum: Number(pageNum),
        // limit,
      });
    }

    if (vendors && vendors.length > 0) {
      for( let vendor of vendors) {               
        const totalExpense = await expenseDB.getTotalByPaidTo({
          clientId: clientId,
          paidTo: vendor.id,
          paidToUserType: CONSTANTS.USER_TYPE.VENDOR,
        });
        vendor.totalExpense = totalExpense;
      }
    }

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

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

vendor.ListForClientX = async (req: CustomRequest, res: Response) => {
  const C = "Vendor Controller";
  const F = "ListForClientX";

  try {
    const userType = req.userType;
    const { pageNum, s } = req.query;
    // const limit = 10;

    log.info(`[${C}], [${F}], User Type [${userType}], Page Num [${pageNum}], Search Val [${s}]`);

    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}], Staff Id [${req.id}], Staff Requested....`
      );
    }

    let vendors = [];

    if (s && s !== "" && s !== "undefined" && s !== "null") {
      vendors = await vendorDB.getByClientIdAndSearchValX({
        clientId,
        searchVal: s,
      });
    } else {
      vendors = await vendorDB.getByClientIdX({
        clientId,
        // pageNum: Number(pageNum),
        // limit,
      });
    }

    if (vendors && vendors.length > 0) {
      for( let vendor of vendors) {               
        const totalExpense = await expenseDB.getTotalByPaidTo({
          clientId: clientId,
          paidTo: vendor.id,
          paidToUserType: CONSTANTS.USER_TYPE.VENDOR,
        });
        vendor.totalExpense = totalExpense;
      }
    }

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

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

vendor.Edit = async (req: CustomRequest, res: Response) => {
  const C = "Vendor Controller";
  const F = "Edit";

  try {
    const { vendorId, name, mobile, type=1 } = req.body;

    log.info(
      `[${C}], [${F}], Vendor Id [${vendorId}], Name [${name}], Mobile [${mobile}], 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}], Staff Id [${req.id}], No Staff Found`
        );
        return res.status(400).json({ 
          msg: CONSTANTS.MSG.INVALID_REQUEST, 
          isSuccess: false 
        });
      }
      
      log.info(
        `[${C}], [${F}], Staff Id [${req.id}], Staff Requested.....`
      );
    }

    await vendorDB.edit({
      id: vendorId,
      clientId: clientId,
      name: name,
      mobile: mobile,
      type: type
    });

    log.info(
      `[${C}], [${F}], Vendor Id [${vendorId}], Name [${name}], Mobile [${mobile}], Vendor Edited Successfully`
    );

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

vendor.ExpenseList = async (req: CustomRequest, res: Response) => {
  const C = "Vendor Controller";
  const F = "ExpenseList";

  try {
    const { vendorId, pageNum, s } = req.query;
    const limit = 10;

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

    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 
        });
      }
      // if (staff.role !== CONSTANTS.STAFF_ROLES.ADMIN && staff.role !== CONSTANTS.STAFF_ROLES.BACK_OFFICE && staff.role !== CONSTANTS.STAFF_ROLES.FINANCE_ADMIN) {
      //   log.info(
      //     `[${C}], [${F}], User Type [${userType}], User Id [${req.id}], Non-admin Staff Not Authorized`
      //   );
      //   return res.status(400).json({
      //     msg: "Unauthorized Access",
      //     isSuccess: false,
      //   });
      // }
      log.info(
        `[${C}], [${F}], Staff Id [${req.id}], Staff Requested.....`
      );
    }

    let expenseList = [];

    if (s && s !== "" && s !== "undefined" && s !== "null") {
      expenseList = await expenseDB.getByPaidToAndSearchVal({
        clientId: clientId,
        paidTo: vendorId,
        paidToUserType: CONSTANTS.USER_TYPE.VENDOR,
        limit: limit,
        pageNum: pageNum,
        searchVal: s,
      });
    } else {
      expenseList = await expenseDB.getByPaidTo({
        clientId: clientId,
        paidTo: vendorId,
        paidToUserType: CONSTANTS.USER_TYPE.VENDOR,
        limit: limit,
        pageNum: pageNum,
      });
    }


    let totalExpense = 0;
    if (expenseList && expenseList.length > 0) {
      expenseList.forEach((expense: any) => {
        totalExpense += expense.amount;
      });
    }

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

    return res.status(200).json({
      msg: "Vendor Expense list sent successfully",
      isSuccess: true,
      expenseList,
      totalExpense,
    });
  } catch (error: any) {
    log.info(`[${C}], [${F}], Error: ${error?.message || error}`);
    return res.status(500).json({
      msg: CONSTANTS.MSG.ERROR_MESSAGE,
      isSuccess: false,
    });
  }
};

vendor.ExpenseListWeb = async (req: CustomRequest, res: Response) => {
  const C = "Vendor Controller";
  const F = "ExpenseListWeb";

  try {
    const { vendorId, s, startDate, endDate } = req.query;
    // const limit = 10;

    log.info(`[${C}], [${F}], Vendor Id [${vendorId}], Search Val [${s}], Start Date [${startDate}], End Date [${endDate}]`);

    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 
        });
      }
      // if (staff.role !== CONSTANTS.STAFF_ROLES.ADMIN && staff.role !== CONSTANTS.STAFF_ROLES.BACK_OFFICE && staff.role !== CONSTANTS.STAFF_ROLES.FINANCE_ADMIN) {
      //   log.info(
      //     `[${C}], [${F}], User Type [${userType}], User Id [${req.id}], Non-admin Staff Not Authorized`
      //   );
      //   return res.status(400).json({
      //     msg: "Unauthorized Access",
      //     isSuccess: false,
      //   });
      // }
      log.info(
        `[${C}], [${F}], Staff Id [${req.id}], Staff Requested.....`
      );
    }

    let expenseList = [];

    if (s && s !== "" && s !== "undefined" && s !== "null") {
      expenseList = await expenseDB.getByPaidToAndSearchValWeb({
        clientId: clientId,
        paidTo: vendorId,
        paidToUserType: CONSTANTS.USER_TYPE.VENDOR,
        searchVal: s,
      });
    } else if (startDate && endDate) {
      expenseList = await expenseDB.getByPaidToAndDateRange({
        clientId: clientId,
        paidTo: vendorId,
        paidToUserType: CONSTANTS.USER_TYPE.VENDOR,
        startDate: startDate,
        endDate: endDate,
      });
    } else {
      expenseList = await expenseDB.getByPaidToWeb({
        clientId: clientId,
        paidTo: vendorId,
        paidToUserType: CONSTANTS.USER_TYPE.VENDOR,
      });
    }


    let totalExpense = 0;
    if (expenseList && expenseList.length > 0) {
      expenseList.forEach((expense: any) => {
        totalExpense += expense.amount;
      });
    }

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

    return res.status(200).json({
      msg: "Vendor Expense list sent successfully",
      isSuccess: true,
      expenseList,
      totalExpense,
    });
  } catch (error: any) {
    log.info(`[${C}], [${F}], Error: ${error?.message || error}`);
    return res.status(500).json({
      msg: CONSTANTS.MSG.ERROR_MESSAGE,
      isSuccess: false,
    });
  }
};

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

  try {
    const { vendorId } = req.body;

    log.info(
      `[${C}], [${F}], Vendor Id [${vendorId}]`
    );
    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 
        });
      }
      // if (staff.role !== CONSTANTS.STAFF_ROLES.ADMIN && staff.role !== CONSTANTS.STAFF_ROLES.BACK_OFFICE && staff.role !== CONSTANTS.STAFF_ROLES.FINANCE_ADMIN) {
      //   log.info(
      //     `[${C}], [${F}], User Type [${userType}], User Id [${req.id}], Non-admin Staff Not Authorized`
      //   );
      //   return res.status(400).json({
      //     msg: "Unauthorized Access",
      //     isSuccess: false,
      //   });
      // }
      log.info(
        `[${C}], [${F}], Staff Id [${req.id}], Staff Role [${staff.role}], Staff Requested.....`
      );
    }

    //Delete Vendor
    await vendorDB.updateStatus({
      id: vendorId,
      status: CONSTANTS.VENDOR_STATUS.DELETED,
    });

    log.info(
      `[${C}], [${F}], Vendor Id [${vendorId}], Vendor Deleted Successfully`
    );

    return res.status(200).json({
      msg: "Vendor 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 vendor;
