import { Response } from "express";
import log from "../config/log";
import CustomRequest from "../types/requestType";
import CONSTANTS from "../config/constants";
import { isUserFinanceAdmin, isUserPartner } from "../utils/isUserPartner";
import clientDB from "../models/client.model";
import activityLogsDB from "../models/activityLogs.model";
import getActivityDescription from "../utils/getActivityDescription";
import staffDB from "../models/staff.model";
import propertyDB from "../models/property.model";
import propertiesTypes from "../schemas/property.schema";
import { isPrivilegedStaff } from "../utils/isPrivilegedStaff";

const activityLogs: any = {};

activityLogs.GetForClient = async (req: CustomRequest, res: Response) => {
  const C = "ActivityLogs Controller";
  const F = "GetForClient";

  try {
    let { startDate, endDate, propId, s, filter, t, doneBy=null, doneByUserType=null } = req.query;

    const userType = req.userType;

    log.info(
      `[${C}], [${F}], Start Date [${startDate}], End Date [${endDate}], Property Id [${propId}], Search Value [${s}], Filter [${filter}], Search Type [${t}], Done By Id [${doneBy}], Done By User Type [${doneByUserType}]`
    );

    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}], Staff 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 (isStaffAllowed) {
        log.info(
          `[${C}], [${F}], Prop Id [${propId}], Staff Id [${staff.id}], Staff Role [${staff.role}], Staff Requested....`
        );
      } else {
        log.info(
          `[${C}], [${F}], Prop Id [${propId}], Staff Id [${staffId}], Staff Not Authorized`
        );
        return res.status(400).json({
          msg: "Unauthorized Access",
          isSuccess: false,
        });
      }
      clientId = staff.clientId;
    }

    const client = await clientDB.getById({ id: clientId });
    if (!client) {
      log.info(`[${C}], [${F}], Client Id [${clientId}], No Client Found`);
      return res
        .status(400)
        .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
    }

    let data = [];

    if (s && s !== " ") {
      if (Number(t) === 1) {
        data = await activityLogsDB.getByDoneByNameAndClientId({
          clientId: clientId,
          searchVal: s,
        });
      } else {
        // data = await activityLogsDB.getByTenantNameAndClientId({
        //   clientId: clientId,
        //   searchVal: s,
        // });
        data = await activityLogsDB.getByDescriptionAndClientId({
          clientId: clientId,
          searchVal: s,
        });
      }
    } else if (doneBy && doneByUserType) {
      data = await activityLogsDB.getByDoneByAndDoneByUserType({
        clientId: client.id,
        doneBy,
        doneByUserType,
      });
    } else if (Number(propId) != 0) {
      data = await activityLogsDB.getByPropIdandDateRange({
        propId: propId,
        startDate: startDate,
        endDate: endDate,
      });
    } else {
      data = await activityLogsDB.getByClientIdAndDateRange({
        clientId: client.id,
        startDate: startDate,
        endDate: endDate,
      });
    }

    if (data && data.length > 0) {
      data = data.map((act: any) => ({
        ...act,
        activityTitle: getActivityDescription(Number(act.activity)),
      }));
    }

    log.info(
      `[${C}], [${F}], Client Id [${clientId}], Start Date [${startDate}], End Date [${endDate}], Property Id [${propId}], Search Value [${s}], Filter [${filter}], Search Type [${t}], Done By Id [${doneBy}], Done By User Type [${doneByUserType}], Activity Logs sent successfully`
    );
    
    return res.status(200).json({
      msg: "Activity logs fetched successfully",
      isSuccess: true,
      data: data,
    });
  } catch (error: any) {
    log.info(`[${C}], [${F}], Error: ${error?.message || error}`);
    return res.status(500).json({
      msg: CONSTANTS.MSG.ERROR_MESSAGE,
      isSuccess: false,
    });
  }
};

activityLogs.GetForClientApp = async (req: CustomRequest, res: Response) => {
  const C = "ActivityLogs Controller";
  const F = "GetForClientApp";

  try {
    let { startDate, endDate, propId, s, filter, staffFilters } = req.query;

    const userType = req.userType;

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

    log.info(
      `[${C}], [${F}], Start Date [${startDate}], End Date [${endDate}], Property Id [${propId}], Search Value [${s}], Filter [${filter}], Staff Filters [${staffFilters}]`
    );

    let data = [];

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

    let { isFinanceAdmin } = await isUserFinanceAdmin(
      Number(userType),
      Number(req.id)
    );

    if (userType === CONSTANTS.USER_TYPE.CLIENT || isPartner || isFinanceAdmin) {
      log.info(
        `[${C}], [${F}], ${isFinanceAdmin
          ? `Finance Admin Id [${req.id}], Finance Admin`
          : isPartner
            ? `Partner Id [${req.id}], Partner`
            : `Client Id [${clientId}], Client`
        } Requesting....`
      );

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

      if (s && s !== " ") {
        data = await activityLogsDB.getBySearchValAndClientId({
          clientId: clientId,
          searchVal: s,
        });
      } else if (filter) {
        data = await activityLogsDB.getByClientIdAndActivity({
          clientId: clientId,
          activity: Number(filter),
          staffFilters: staffFilters,
        });
      } else if (propId) {
        data = await activityLogsDB.getByPropIdandDateRange({
          propId: propId,
          startDate: startDate,
          endDate: endDate,
        });
      } else {
        data = await activityLogsDB.getByClientIdAndDateRange({
          clientId: client.id,
          startDate: startDate,
          endDate: endDate,
          staffFilters: staffFilters,
        });
      }
    } else {
      const staff = await staffDB.getById({ id: req.id });

      let isStaffAllowed = await isPrivilegedStaff(staff.role, 3);
      if (isStaffAllowed) {
        log.info(`[${C}], [${F}], User Type [${userType}], User Id [${req.id}], Admin Requesting....`);
        const staffLinkedProps = await propertyDB.getPropsByStaffId({
          staffId: staff.id,
        });

        if (staffLinkedProps) {
          const propertiesIds = staffLinkedProps
            .map((prop: propertiesTypes) => prop.id)
            .join(",");

          if (s && s !== " ") {
            data = await activityLogsDB.getBySearchValAndClientIdForStaff({
              clientId: clientId,
              searchVal: s,
              propertiesIds: propertiesIds,
            });
          } else if (filter) {
            data = await activityLogsDB.getByClientIdAndActivityForStaff({
              clientId: clientId,
              activity: Number(filter),
              propertiesIds: propertiesIds,
              staffFilters: staffFilters,
            });
          } else if (propId) {
            data = await activityLogsDB.getByPropIdandDateRange({
              propId: propId,
              startDate: startDate,
              endDate: endDate,
            });
          } else {
            data = await activityLogsDB.getByClientIdAndDateRangeForStaff({
              clientId: clientId,
              startDate: startDate,
              endDate: endDate,
              propertiesIds: propertiesIds,
              staffFilters: staffFilters,
            });
          }
        }
      } 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,
        });
      }
    }

    if (data && data.length > 0) {
      data = data.map((act: any) => ({
        ...act,
        activityTitle: getActivityDescription(Number(act.activity)),
      }));
    }

    let activityDropDown = [
      { id: CONSTANTS.ACTIVITY_TYPES.ADD_DUES, name: "Due Added" },
      { id: CONSTANTS.ACTIVITY_TYPES.MARK_PAID, name: "Mark Paid" },
      { id: CONSTANTS.ACTIVITY_TYPES.PROPERTY_CHANGE, name: "Property Switch" },
      { id: CONSTANTS.ACTIVITY_TYPES.EDIT_DUES, name: "Due Edited" },
      { id: CONSTANTS.ACTIVITY_TYPES.DELETE_DUES, name: "Due Deleted" },
      { id: CONSTANTS.ACTIVITY_TYPES.TENANT_ADDED, name: "Tenant Added" },
      { id: CONSTANTS.ACTIVITY_TYPES.ADD_EXTRA_CHARGES, name: "Extra Charge Added" },
      { id: CONSTANTS.ACTIVITY_TYPES.ASSIGN_TENANT_COMPLAINT, name: "Assign Complaint" },
      { id: CONSTANTS.ACTIVITY_TYPES.SETTLE_EXCESS, name: "Settlements" },
      { id: CONSTANTS.ACTIVITY_TYPES.SETTLE_EXCESS_VIA_PAYOUT, name: "Settlements Online" },
      { id: CONSTANTS.ACTIVITY_TYPES.CANCEL_RESERVATION, name: "Cancelled Reservation" },
      { id: CONSTANTS.ACTIVITY_TYPES.BOOKED_AGAIN, name: "Tenant Re-assigned" },
      { id: CONSTANTS.ACTIVITY_TYPES.RENT_RENEWAL, name: "Rent Renewed" },
      { id: CONSTANTS.ACTIVITY_TYPES.RESTORE_TRANS, name: "Restore Transaction" },
      { id: CONSTANTS.ACTIVITY_TYPES.ADD_EXPENSE, name: "Expense Added" },
      { id: CONSTANTS.ACTIVITY_TYPES.EDIT_EXPENSE, name: "Expense Edited" },
      { id: CONSTANTS.ACTIVITY_TYPES.DELETE_EXPENSE, name: "Expense Deleted" },
      { id: CONSTANTS.ACTIVITY_TYPES.MARKED_EXPENSE, name: "Expense Marked" },
      { id: CONSTANTS.ACTIVITY_TYPES.MAKE_PROPERTY_ACTIVE, name: "Property Activated" },
      { id: CONSTANTS.ACTIVITY_TYPES.MAKE_PROPERTY_INACTIVE, name: "Property Deactivated" },
      { id: CONSTANTS.ACTIVITY_TYPES.DELETE_PROPERTY, name: "Property Deleted" },
      { id: CONSTANTS.ACTIVITY_TYPES.GUEST_REQUEST, name: "Guest Req" },
      { id: CONSTANTS.ACTIVITY_TYPES.GUEST_REQUEST_ACCEPTED, name: "Guest Req Accepted" },
      { id: CONSTANTS.ACTIVITY_TYPES.GUEST_REQUEST_REJECTED, name: "Guest Req Rejected" },
      { id: CONSTANTS.ACTIVITY_TYPES.ADD_RECURRING_EXPENSE, name: "Recurring Expense Added" },
      { id: CONSTANTS.ACTIVITY_TYPES.EDIT_RECURRING_EXPENSE, name: "Recurring Expense Edited" },
      { id: CONSTANTS.ACTIVITY_TYPES.DELETE_RECURRING_EXPENSE, name: "Recurring Expense Deleted" },
      // {id: CONSTANTS.ACTIVITY_TYPES.RENEW_AGREEMENT, name: "Renewed Agreement"},
      {id: CONSTANTS.ACTIVITY_TYPES.TENANT_ROOM_REQUEST, name: "Room Req"},
      {id: CONSTANTS.ACTIVITY_TYPES.TENANT_ROOM_REQUEST_ACCEPT, name: "Room Req Accepted"},
      {id: CONSTANTS.ACTIVITY_TYPES.TENANT_ROOM_REQUEST_CANCEL, name: "Room Req Cancelled"},
      {id: CONSTANTS.ACTIVITY_TYPES.TENANT_ROOM_REQUEST_REJECT, name: "Room Req Rejected"},
      {id: CONSTANTS.ACTIVITY_TYPES.MOVEOUT_INITIATED, name: "Initiate MoveOut"},
      {id: CONSTANTS.ACTIVITY_TYPES.MOVEOUT_NOW, name: "MoveOut"},
      {id: CONSTANTS.ACTIVITY_TYPES.MOVEOUT_REQUEST, name: "MoveOut Req"},
      {id: CONSTANTS.ACTIVITY_TYPES.MOVEOUT_REQUEST_ACCEPTED, name: "MoveOut Req Accepted"},
      {id: CONSTANTS.ACTIVITY_TYPES.MOVEOUT_REQUEST_REJECTED, name: "MoveOut Req Rejected"},
      {id: CONSTANTS.ACTIVITY_TYPES.MOVEOUT_REQUEST_CANCELLED, name: "MoveOut Req Cancelled"},
      {id: CONSTANTS.ACTIVITY_TYPES.TENANT_CANCELLED_MOVEOUT, name: "Tenant Cancelled MoveOut"},
      {id: CONSTANTS.ACTIVITY_TYPES.EXTEND_STAY, name: "Extend Stay"},
      {id: CONSTANTS.ACTIVITY_TYPES.REMOVE_BED, name: "Bed Deleted"},
      {id: CONSTANTS.ACTIVITY_TYPES.ADD_BED, name: "Bed Added"},
      {id: CONSTANTS.ACTIVITY_TYPES.DELETE_TENANT, name: "Tenant Deleted"},
      {id: CONSTANTS.ACTIVITY_TYPES.TENANT_OCCUPANCY_CHANGE, name: "Tenant Occupancy Change"},
      {id: CONSTANTS.ACTIVITY_TYPES.SWITCH_ONLINE_ACCOUNT, name: "Bank Account"},
      {id: CONSTANTS.ACTIVITY_TYPES.ADD_PROPERTY_LEASE, name: "Property Lease Added"},
      {id: CONSTANTS.ACTIVITY_TYPES.RENTAL_CYCLE_CHANGE, name: "Rental Cycle Changed"},
      {id: CONSTANTS.ACTIVITY_TYPES.STAFF_CHECKIN_MANUAL, name: "Manual Staff Check-in"},
      {id: CONSTANTS.ACTIVITY_TYPES.STAFF_CHECKOUT_MANUAL, name: "Manual Staff Check-out"},
      {id: CONSTANTS.ACTIVITY_TYPES.STAFF_MARK_ABSENT_MANUAL, name: "Staff Marked Absent"},
      {id: CONSTANTS.ACTIVITY_TYPES.TENANT_LATE_ARRIVAL_REQUEST, name: "Tenant Late Arrival"},
      {id: CONSTANTS.ACTIVITY_TYPES.TENANT_GOING_HOME_REQUEST, name: "Tenant Going Home"},
    ];

    const staffs = await staffDB.getAllByClientId({
      clientId: clientId,
      status: CONSTANTS.STAFF_STATUS.ACTIVE,
    });


    log.info(`[${C}], [${F}], Activity Logs sent successfully`);
    return res.status(200).json({
      msg: "Activity logs fetched successfully",
      isSuccess: true,
      data: data,
      activityDropDown,
      staffs: staffs,
    });
  } catch (error: any) {
    log.info(`[${C}], [${F}], Error: ${error?.message || error}`);
    return res.status(500).json({
      msg: CONSTANTS.MSG.ERROR_MESSAGE,
      isSuccess: false,
    });
  }
};

activityLogs.GetForTenant = async (req: CustomRequest, res: Response) => {
  const C = "ActivityLogs Controller";
  const F = "GetForTenant";

  try {
    let {id} = req.query;

    const userType = req.userType;

    log.info(
      `[${C}], [${F}], Tenant 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 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}], Staff Id [${staffId}], No Staff Found`);
        return res
          .status(400)
          .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
      }
      clientId = staff.clientId;
      let isStaffAllowed = await isPrivilegedStaff(staff.role, 3);
      if (isStaffAllowed) {
        log.info(
          `[${C}], [${F}], ClientId [${clientId}], Tenant Id [${id}], Staff Id [${staff.id}], Staff Role [${staff.role}], Staff Requested....`
        );
      } else {
        log.info(
          `[${C}], [${F}], ClientId [${clientId}], Tenant Id [${id}], Staff Id [${staffId}], Staff Not Authorized`
        );
        return res.status(400).json({
          msg: "Unauthorized Access",
          isSuccess: false,
        });
      }
    }

    const client = await clientDB.getById({ id: clientId });
    if (!client) {
      log.info(`[${C}], [${F}], Client Id [${clientId}], No Client Found`);
      return res
        .status(400)
        .json({ msg: CONSTANTS.MSG.INVALID_REQUEST, isSuccess: false });
    }

    let data = [];

    data = await activityLogsDB.getByTenantId({tenantId:id, clientId});

    if (data && data.length > 0) {
      data = data.map((act: any) => ({
        ...act,
        activityTitle: getActivityDescription(Number(act.activity)),
      }));
    }

    log.info(`[${C}], [${F}], Client Id [${clientId}], [${id}], Activity Logs sent successfully`);
    return res.status(200).json({
      msg: "Activity logs fetched successfully",
      isSuccess: true,
      data: data || [],
    });
  } 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 activityLogs;
