import CustomRequest from "../types/requestType";
import log from "../config/log";
import CONSTANTS from "../config/constants";
import { Response } from "express";
import { isUserPartner } from "../utils/isUserPartner";
import staffDB from "../models/staff.model";
import {
  collectionReport,
  dueReport,
  expenseReport,
  tenantReport,
  tenantReportForSivani,
  occupancyReport,
  bedOccupancyReport,
  // tenantComplaintReport,
  propertyComplaintReport,
  leadReport,
  activityReport,
  moveOutReport,
  bookingReport,
  propertyReport,
  PropertyLeaseReport,
  RefundRequests,
  tenantRentReviewReport,
  profitLossReport,
  tenantAttendanceReport,
} from "../utils/generateReports";
import reportDB from "../models/reports.model";
import clientDB from "../models/client.model";
import property from "./property.controller";
import propertyDB from "../models/property.model";
import path from "path";
import { report } from "process";
import moment from "moment";
import { isPrivilegedStaff } from "../utils/isPrivilegedStaff"

const reports: any = {};

reports.GenerateReport = async (req: CustomRequest, res: Response) => {
  const C = "Reports Controller";
  const F = "GenerateReport";

  try {
    let {
      startDate = moment().format('YYYY-MM-DD'),
      endDate = moment().format('YYYY-MM-DD'),
      s,
      t,
      propId,
      filter,
      fileType = 1,
      reportType,
    } = req.query;
    const userType = req.userType;

    propId = String(propId);

    log.info(
      `[${C}], [${F}], Start Date [${startDate}], End Date [${endDate}], S [${s}], T [${t}], Prop Id [${propId}], Filter [${filter}], File Type [${fileType}], Report Type [${reportType}]`
    );

    let generatedBy = "";

    if (Number(propId) === 0) {
      propId = [];
    } else if (propId && typeof propId === 'string' && propId !== "undefined") {
      propId = propId.split(',').map(v => v.trim()).filter(Boolean);
    }

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

      let isStaffAuthorized = await isPrivilegedStaff(
        staff.role,
        1,
      );

      if (staff.role === CONSTANTS.STAFF_ROLES.ADMIN || staff.role === CONSTANTS.STAFF_ROLES.WARDEN || staff.role === CONSTANTS.STAFF_ROLES.BACK_OFFICE || isStaffAuthorized) {
        log.info(
          `[${C}], [${F}], Client Id [${clientId}], Staff Id [${req.id}], Admin/Warden Requesting....`
        );
        generatedBy = staff.name;
      } else {
        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,
        });
      }
    }

    let reportUrl;

    if (Number(reportType) === 1) { // Collection Report
      reportUrl = await collectionReport(
        Number(fileType),
        clientId,
        propId,
        s?.toString()!,
        startDate?.toString()!,
        endDate?.toString()!
      );
    } else if (Number(reportType) === 2) { // Due Report
      reportUrl = await dueReport(
        Number(fileType),
        clientId,
        propId,
        s?.toString()!,
        startDate?.toString()!,
        endDate?.toString()!
      );
    } else if (Number(reportType) === 3) {// Tenant Report
      if (Number(clientId) === 308) {
        reportUrl = await tenantReportForSivani(
          Number(fileType),
          clientId,
          propId,
          startDate?.toString()!,
          endDate?.toString()!
        );
      } else {
        reportUrl = await tenantReport(
          Number(fileType),
          clientId,
          propId,
          startDate?.toString()!,
          endDate?.toString()!
        );
      }
    } else if (Number(reportType) === CONSTANTS.REPORT_TYPE.BOOKING) {// Booking Report
      reportUrl = await bookingReport(
        Number(fileType),
        clientId,
        propId
      );

    } else if (Number(reportType) === 4) { // Expense Report
      reportUrl = await expenseReport(
        Number(fileType),
        clientId,
        propId,
        s?.toString()!,
        startDate?.toString()!,
        endDate?.toString()!    
      );
    } else if (Number(reportType) === 5) { // Occupancy Report
      reportUrl = await occupancyReport(
        Number(fileType),
          clientId,
          propId,
          startDate?.toString()!,
          endDate?.toString()!
      );
    } else if (Number(reportType) === 6) { // Bed Occupancy Report
      let startDateNew = (startDate === 'Invalid date' ? moment().format('YYYY-MM-DD') : startDate?.toString()!);
      let endDateNew = (endDate === 'Invalid date' ? moment().format('YYYY-MM-DD') : endDate?.toString()!);
      reportUrl = await bedOccupancyReport(
        Number(fileType),
          clientId,
          propId,
          startDateNew,
          endDateNew
      );
    } else if (Number(reportType) === CONSTANTS.REPORT_TYPE.PROPERTY_COMPLAINT) { //Complaints report
      reportUrl = await propertyComplaintReport(
        Number(fileType),
        clientId,
        propId,
        startDate?.toString()!,
        endDate?.toString()!
      );
    } else if (Number(reportType) === CONSTANTS.REPORT_TYPE.LEAD) { // Lead Report
      reportUrl = await leadReport(
        Number(fileType),
        clientId,
        propId,
        startDate?.toString()!,
        endDate?.toString()!
      );
    } else if (Number(reportType) === CONSTANTS.REPORT_TYPE.ACTIVITY_LOGS) {
      reportUrl = await activityReport(
        Number(fileType),
        clientId,
        propId,
        startDate?.toString()!,
        endDate?.toString()!
      );
    } else if (Number(reportType) === CONSTANTS.REPORT_TYPE.MOVED_OUT_TENANTS) {
      reportUrl = await moveOutReport(
        Number(fileType),
          clientId,
          propId,
          startDate?.toString()!,
          endDate?.toString()!
      );      
    } else if (Number(reportType) === CONSTANTS.REPORT_TYPE.PROPERTY) {
      reportUrl = await propertyReport(
        Number(fileType),
          clientId,
          propId,
      );      
    } else if (Number(reportType) === CONSTANTS.REPORT_TYPE.PROPERTY_LEASE) {
      reportUrl = await PropertyLeaseReport(
        Number(fileType),
          clientId,
          propId,
      );      
    } else if (Number(reportType) === CONSTANTS.REPORT_TYPE.REFUND_REQUEST) {
      reportUrl = await RefundRequests(
        Number(fileType),
          clientId,
          CONSTANTS.REQUEST_TYPE.REFUND,
          propId,
      );      
    } else if (Number(reportType) === CONSTANTS.REPORT_TYPE.RENT_ADDED) {
      reportUrl = await tenantRentReviewReport(
        Number(fileType),
          clientId,
          propId,
      );      
    } else if (Number(reportType) === CONSTANTS.REPORT_TYPE.PROFIT_LOSS) {
      reportUrl = await profitLossReport(
        Number(fileType),
        clientId,
        Number(propId),
        String(startDate),
        String(endDate),
      );
    } else if (Number(reportType) === CONSTANTS.REPORT_TYPE.TENANT_ATTENDANCE) {
      reportUrl = await tenantAttendanceReport(
        Number(fileType),
        clientId,
        propId,
        String(startDate),
        String(endDate),
      );
    }
    if (!reportUrl) {
      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Start Date [${startDate}], End Date [${endDate}], S [${s}], T [${t}], Prop Id [${propId}], Filter [${filter}], Report Type [${reportType}], URL [${reportUrl}], Failed To Generate Report`
      );
      return res.status(200).json({
        msg: "No Data available",
        isSuccess: false,
      });
    }

    let startDateNew = (startDate === 'Invalid date' ? moment().format('YYYY-MM-DD') : startDate);
    let endDateNew = (endDate === 'Invalid date' ? moment().format('YYYY-MM-DD') : endDate);
    let reportId = "";
    if (reportUrl && typeof reportUrl === "object") {
      let reportName = reportUrl?.fileName.replace(".xlsx", "") || "";
      reportId = await reportDB.add({
        reportName: reportName,
        reportType: Number(reportType),
        clientId: clientId,
        propId: Array.isArray(propId) && propId.length > 0 ? Number(propId[0]) : 0,
        status: 1,
        value: reportUrl?.url || "",
        startDate: startDateNew,
        endDate: endDateNew,
        generatedBy: generatedBy,
      });
    }

    log.info(
      `[${C}], [${F}], Client Id [${clientId}], Start Date [${startDate}], End Date [${endDate}], S [${s}], T [${t}], Prop Id [${propId}], Filter [${filter}], Report Type [${reportType}], URL [${JSON.stringify(
        reportUrl
      )}] Report Sent Successfully`
    );

    if (reportUrl && typeof reportUrl === "object") {
      return res.status(200).json({
        msg: "Report Sent Successfully",
        isSuccess: true,
        reportUrl: reportUrl?.url || "",
      });
    } else {
      log.info(
        `[${C}], [${F}], Client Id [${clientId}], Start Date [${startDate}], End Date [${endDate}], S [${s}], T [${t}], Prop Id [${propId}], Filter [${filter}], Report Type [${reportType}], Report Not Sent`
      );

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

reports.GetReportList = async (req: CustomRequest, res: Response) => {
  const C = "Reports Controller";
  const F = "GetReportList";

  try {
    const { pageNum=1 } = req.query; 
    const userType = req.userType;
    const platform = req.platform;

    log.info(`[${C}], [${F}], pageNum [${pageNum}], userType [${userType}], platform [${platform}]`);

    let limit = 10;
    if (platform === CONSTANTS.TENANT_DEVICE_TYPE.WEB) limit = 10e9;

    let { isPartner, clientId } = await isUserPartner(
      Number(userType),
      Number(req.id)
    );

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

    if (userType === CONSTANTS.USER_TYPE.CLIENT || isPartner) {
      log.info(
        `[${C}], [${F}], ${
          isPartner ? `Partner Id [${req.id}]` : `Client Id [${clientId}]`
        }, ${isPartner ? "Partner Requesting" : "Client Requesting"}....`
      );
    } else {
      const staff = await staffDB.getById({ id: req.id });
      if (!staff) {
        log.info(
          `[${C}], [${F}], User Type [${userType}], User 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 || staff.role === CONSTANTS.STAFF_ROLES.WARDEN || staff.role === CONSTANTS.STAFF_ROLES.SALES_HEAD) {
        log.info(
          `[${C}], [${F}], Client Id [${clientId}], Staff Id [${req.id}], Staff Requesting.....`
        );
      } else {
        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,
        });
      }
    }

    const reportList = await reportDB.getListByClientId({
      clientId,
      pageNum: pageNum || 1,
      limit,
    });

    if (reportList.length > 0) {
      for (let report of reportList) {
        let propName = "";
        if (report.propId === 0) {
          propName = "All Properties";
        } else {
          const property = await propertyDB.getById({
            id: report.propId,
          });
          propName = property.name;
        }
        report.propName = propName;
        report.format = path.extname(report.value);
      }
    }

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

    return res.status(200).json({
      msg: "Report List",
      isSuccess: true,
      reportList,
      data: reportList,
      tenantAttendanceEnabled: client?.tenantAttendanceEnabled || 0,
    });
  } 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 reports;
