import { Response } from "express";
import moment from "moment";
import log from "../config/log";
import expenseDB from "../models/expense.model";
import landlordTransactionDB from "../models/landlordTransaction.model";
import staffDB from "../models/staff.model";
import landlordDB from "../models/landlord.model";
import vendorDB from "../models/vendor.model";
import CustomRequest from "../types/requestType";
import CONSTANTS from "../config/constants";
import { isUserPartner } from "../utils/isUserPartner";
import { logExpenseActivity } from "../utils/logActivity";

const landlordTransactions: any = {};
landlordTransactions.Add = async (req: CustomRequest, res: Response) => {
  const C = "Landlord Transaction Controller";
  const F = "Add";
  try {
    let {
      gId,
      landlordId,
      propId,
      amount,
      gateway,
      mode,
      type,
      remark,
      bankRefNum,
      expenseId,
    } = req.body;

    log.info(
      `[${C}], [${F}], Gid [${gId}], Landlord Id [${landlordId}], Prop Id [${propId}], Amount [${amount}], Gateway [${gateway}], Mode [${mode}], Type [${type}], Remark [${remark}], Bank Ref Num [${bankRefNum}], Expense Id [${expenseId}]`
    );
    
    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}]`
            : `Client Id [${clientId}]`
        }, gId [${gId}], Bank Ref Num [${bankRefNum}], Remark [${remark}], LandlordId [${landlordId}], PropId [${propId}], Amount [${amount}], Gateway [${gateway}], Mode [${mode}], Type [${type}],  ${
          isPartner ? "Partner Requesting" : "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}], gId [${gId}], Bank Ref Num [${bankRefNum}], Remark [${remark}], LandlordId [${landlordId}], PropId [${propId}], Amount [${amount}], Gateway [${gateway}], Mode [${mode}], Type [${type}], Staff Requested.....`
      );
    }
    let paymentDate = moment().format("YYYY-MM-DD HH:mm:ss");
    let landLord = await landlordDB.getById({id: landlordId});
    if(!landLord) {
      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Landlord ID [${landlordId}], No Landlord Found`
      );
      return res.status(400).json({ 
          msg: CONSTANTS.MSG.INVALID_REQUEST, 
          isSuccess: false 
        });
    }
    // let vendor = await vendorDB.getByMobileAndClientId({mobile: landLord?.mobile, clientId});

    // if(!vendor) {
    //   log.info(
    //     `[${C}], [${F}], Client Id [${clientId}], Landlord ID [${landlordId}], Landlord Mobile [${landLord?.mobile}], No Vendor Found`
    //   );
    //   return res.status(400).json({ 
    //       msg: CONSTANTS.MSG.INVALID_REQUEST, 
    //       isSuccess: false 
    //     });
    // }

    
    let description = "";
    let expenseType=0;
    if(Number(type) === 1) {
      description = "Building rent paid to landlord";
      expenseType = 1;
    } else if(Number(type) === 2 || Number(type) === 43) {
      description = "Building security paid to landlord";
      expenseType = 43;
    }
    
    let expenseDetail = await expenseDB.getById({id:expenseId});

    if(Number(amount)=== Number(expenseDetail.amount)) {
      //Update to markpaid, update
      log.info(`[${C}], [${F}], ClientId [${clientId}], gId [${gId}], LandlordId [${landlordId}], PropId [${propId}], Amount [${amount}], ExpenseId [${expenseId}], Gateway [${gateway}], Mode [${mode}], PaymentDate [${paymentDate}], Description [${description}], Type [${type}], Marking expense paid`);
      expenseDB.updateExpenseOnPaid({id:expenseId, paidDate: paymentDate, paymentMethod: mode })

    } else if(Number(amount)<Number(expenseDetail.amount)) {

      let oldExpenseId = expenseId;
      log.info(`[${C}], [${F}], ClientId [${clientId}], gId [${gId}], LandlordId [${landlordId}], PropId [${propId}], Amount [${amount}], Old Expense Id [${oldExpenseId}], ExpenseId [${expenseId}], Gateway [${gateway}], Mode [${mode}], PaymentDate [${paymentDate}], Description [${description}], Type [${type}], Creating expense and updating amount`);

      expenseId = await expenseDB.create({
        type: expenseType,
        amount,
        clientId,
        paidDate: moment().format("YYYY-MM-DD hh:mm:ss"),
        paidByUserType : CONSTANTS.USER_TYPE.CLIENT,
        paidBy: clientId,
        paidTo: expenseDetail?.paidTo,
        paidToUserType: expenseDetail?.paidToUserType,
        description: description,
        paymentMethod: mode,
        repetitionType: CONSTANTS.REPETITION_TYPE.ONE_TIME,
        noOfMonths: 0,
        dueDate: expenseDetail?.dueDate,
        isPaid: 1,
        bankRefNum: bankRefNum,
      });
      await expenseDB.addProperty({
        expenseId,
        propId: propId,
        clientId,
      });
      //Update balance amount and of the Old
      expenseDB.updateAmount({
        id: oldExpenseId, 
        amount: Number(expenseDetail.amount) - Number(amount)
      });
    }

    const expense = await expenseDB.getById({
      id: expenseId,
    });

    const expenseProperty = await expenseDB.getExpensePropertyById({id: expenseId});

    await logExpenseActivity(
      req.userType!,
      Number(req.id)!,
      Number(req.parentClientId!),
      Number(req.platform),
      CONSTANTS.ACTIVITY_TYPES.MARKED_EXPENSE,
      clientId,
      CONSTANTS.USER_TYPE.CLIENT,
      landlordId,
      CONSTANTS.USER_TYPE.LANDLORD,
      type,
      amount,
      mode,
      expenseProperty?.propId || null,
    );

    await landlordTransactionDB.add({
      clientId,
      gId,
      landlordId,
      propId,
      amount,
      expenseId,
      gateway,
      mode,
      paymentDate : moment().format("YYYY-MM-DD hh:mm:ss"),
      description: `${description} for ${moment(expenseDetail?.dueDate).format("MMM")} Month`,
      status: 1,
      type,
      remarks:remark,
      bankRefNum
    });
    log.info(`[${C}], [${F}], ClientId [${clientId}], gId [${gId}], LandlordId [${landlordId}], PropId [${propId}], Amount [${amount}], ExpenseId [${expenseId}], Gateway [${gateway}], Mode [${mode}], PaymentDate [${paymentDate}], Description [${description}], Type [${type}], Landlord Transaction Added Successfully`);
    return res.status(200).json({
      msg: "Landlord Transaction Added Successfully",
      isSuccess: true,
    });
  } catch (error) {
    log.error(`
      [${C}], [${F}], Error [${error}]`);
    return res.status(500).json({
      msg: "Internal Server Error",
      isSuccess: false,
    });
  }
};
landlordTransactions.GetLandlordTransactions = async (req: CustomRequest, res: Response) => {
  const C = "Landlord Transaction Controller";
  const F = "GetLandlordTransactions";
  try {
    const { propId, landlordId, s, t } = req.query;
    log.info(`[${C}], [${F}], Landlord Id [${landlordId}], PropId [${propId}], Search Type [${t}], Search Value [${s}]`);
    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) {
        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}], Admin Requested....`);
    }

    let transactions: any[] = [];
    if(propId && Number(propId)>0) {
      if(s && s != '') {
        log.info(`[${C}], [${F}], Staff Id [${req.id}], Search Type [${t}], Search Value [${s}], In Search `);
        transactions = await landlordTransactionDB.getLandlordTransactionsByPropertyForFilter ({
          clientId,
          propId,
          searchType: Number(t), 
          searchVal:s
        });
      } else {
        transactions = await landlordTransactionDB.getLandlordTransactionsByProperty({
          clientId, 
          propId: Number(propId)
        });
      }
    } else if (landlordId && Number(landlordId) !== 0) {
      const landlord = await landlordDB.getById({
        id: landlordId,
      });
      
      // const vendorRecord = await vendorDB.getByMobileAndClientId({
      //   mobile: landlord?.mobile,
      //   clientId,
      // });

      if(s != '') {
        transactions = await expenseDB.getByPaidToForLandlordTransactionByLandlordIdAndSearch ({
        clientId,
        landlordId: landlord?.id,
        searchType: t, 
        searchVal:s
      });
      } else {
        // transactions = await expenseDB.getByPaidToForLandlordTransactions({
        //   clientId,
        //   paidTo: vendorRecord?.id,
        //   paidToUserType: CONSTANTS.USER_TYPE.VENDOR,
        // });
        transactions = await expenseDB.getByPaidToForLandlordTransactionByLandlordId({
          clientId,
          landlordId: landlord?.id,
        });
      }

    } else {
      if(s != '') {
        transactions = await landlordTransactionDB.getLandlordTransactionsByClientForFilter ({
        clientId,
        searchType: t, 
        searchVal:s
      });
      } else {
        transactions = await landlordTransactionDB.getLandlordTransactionsByClient({
          clientId
        });
      }
    }
    
    const totalAmount = transactions 
      ? transactions.reduce((sum, tx) => sum + Number(tx.amount || 0), 0)
      : 0;


    log.info(`[${C}], [${F}], ClientId [${clientId}], Landlord Id [${landlordId}], PropId [${propId}], Landlord Transactions Fetched Successfully`);

    return res.status(200).json({
      msg: "Landlord Transactions Fetched Successfully",
      totalAmount,
      data: transactions ? transactions : [],
      isSuccess: true,
    });
  } catch (error) {
    log.error(`
      [${C}], [${F}], Error [${error}]`);
    return res.status(500).json({
      msg: "Internal Server Error",
      isSuccess: false,
    });
  }
};
export default landlordTransactions;
