import { Response } from "express";
import moment from "moment";
import CONSTANTS from "../config/constants";
import log from "../config/log";
import CustomRequest from "../types/requestType";
import { isUserPartner } from "../utils/isUserPartner";
import staffDB from "../models/staff.model";
import staffTasksDB from "../models/staffTasks.model";
import getStaffTaskList, { getCommonAreaTaskList } from "../utils/getStaffTasks";
import fsPromises from "fs/promises";
import fs from "fs";
import path from "path";
import roomDB from "../models/room.model";
import checkPermission from "../utils/checkPermission";
import propertyDB from "../models/property.model";
import propertiesTypes from "../schemas/property.schema";

const staffTask: any = {};

staffTask.RecordTask = async (req: CustomRequest, res: Response) => {
  const C = "Staff Task Controller";
  const F = "Record Task";

  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 {
    let { roomIds, propId, taskCompleted, staffId, remarks, type } = req.body;

    const userType = req.userType;
    const platform = req.platform;

    log.info(
      `[${C}], [${F}], Room Ids [${roomIds}], Prop Id [${propId}], Task Type [${type}], Task Completed [${taskCompleted}], StaffId [${staffId}], Remarks [${remarks}], Platform [${platform}], Is File Uploaded ${files ? `[Yes], ${files.length} Files` : "[No]"}`,
    );

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

    const { 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}]`
        }, Platform [${req.platform}], ${
          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}], Client Id [${clientId}], Staff Id [${req.id}], Staff Role [${staff.role}], Platform [${req.platform}], Staff Requesting....`,
      );
    }

    let tasks = [];

    if (roomIds && roomIds.length > 0 && Number(type) === CONSTANTS.STAFF_TASK_TYPE.ROOM_TASK) {
      for (let roomId of roomIds) {
        const taskId = await staffTasksDB.record({
          clientId,
          propId,
          roomId,
          type,
          doneBy: staffId && Number(staffId) > 0 ? Number(staffId) : req.id,
          taskCompleted,
          taskDate: moment().format("YYYY-MM-DD HH:mm:ss"),
          recordedById: req.id,
          recordedByUserType: req.userType,
          remarks: remarks || null,
        });

        tasks.push({roomId, taskId});
      }

      if (files) {
        let i = 1; //for image indexing
        for (let file of files) {
          const folderName = `staffTaskImages`;
          // const folderPath = `uploads/documents/${clientId}/${folderName}`;
          const folderPath = `uploads/${folderName}/${moment().format('YYYY')}/${clientId}`;
          const fileExtension = file.mimetype.split("/")[1];
          const filename = `Image${i}_${clientId}_${propId}_${moment().format('YYYYMMDDHHmmss')}.${fileExtension}`;
  
          if (!fs.existsSync(folderPath)) {
            await fsPromises.mkdir(folderPath, { recursive: true });
          }
  
          const oldPath = `uploads/tmp/${file.filename}`;
          const newPath = `${folderPath}/${filename}`;
          let url = `${process.env.UPLOAD_PATH}/${folderName}/${moment().format('YYYY')}/${clientId}/${filename}`;
  
          await fsPromises.copyFile(oldPath, newPath);
          await fsPromises.unlink(oldPath).catch(() => {}); //Deleting the temp file

          if (tasks && tasks.length > 0) {
            for (let task of tasks) {
              await staffTasksDB.AddImage({
                clientId,
                propId: propId,
                roomId: task.roomId,
                staffTaskId: task.taskId,
                value: url,
              });
            }
          }
  
          log.info(
            `[${C}], [${F}], Client Id [${clientId}], Old Path [${oldPath}], New Path [${newPath}], Url [${url}], Document Saved in DB.`,
          );

          i += 1;
        }
      }
    } else if (Number(type) === CONSTANTS.STAFF_TASK_TYPE.COMMON_AREA_TASK) {
      const taskId = await staffTasksDB.record({
        clientId,
        propId,
        roomId: null,
        type,
        doneBy: staffId && Number(staffId) > 0 ? Number(staffId) : req.id,
        taskCompleted,
        taskDate: moment().format("YYYY-MM-DD HH:mm:ss"),
        recordedById: req.id,
        recordedByUserType: req.userType,
        remarks: remarks || null,
      });

      if (files) {
        let i = 1; //for image indexing
        for (let file of files) {
          const folderName = `staffTaskImages`;
          // const folderPath = `uploads/documents/${clientId}/${folderName}`;
          const folderPath = `uploads/${folderName}/${moment().format('YYYY')}/${clientId}`;
          const fileExtension = file.mimetype.split("/")[1];
          const filename = `Image${i}_${clientId}_${propId}_${moment().format('YYYYMMDDHHmmss')}.${fileExtension}`;
  
          if (!fs.existsSync(folderPath)) {
            await fsPromises.mkdir(folderPath, { recursive: true });
          }
  
          const oldPath = `uploads/tmp/${file.filename}`;
          const newPath = `${folderPath}/${filename}`;
          let url = `${process.env.UPLOAD_PATH}/${folderName}/${moment().format('YYYY')}/${clientId}/${filename}`;
  
          await fsPromises.copyFile(oldPath, newPath);
          await fsPromises.unlink(oldPath).catch(() => {}); //Deleting the temp file

          await staffTasksDB.AddImage({
            clientId,
            propId: propId,
            roomId: null,
            staffTaskId: taskId,
            value: url,
          });
  
          log.info(
            `[${C}], [${F}], Client Id [${clientId}], Old Path [${oldPath}], New Path [${newPath}], Url [${url}], Document Saved in DB.`,
          );

          i += 1;
        }
      }
    } else {
      //Invalid type
      log.info(`[${C}], [${F}], Client Id [${clientId}], Type [${type}], Invalid Task Type`);
      return res.status(400).json({ 
        msg: "Invalid task type", 
        isSuccess: false 
      });
    }


    log.info(
      `[${C}], [${F}], Client Id [${clientId}], Room Ids [${roomIds}], Prop Id [${propId}], Task Completed [${taskCompleted}], StaffId [${staffId}], Platform [${platform}], Remarks [${remarks}], Tasks Recorded Successfully`,
    );

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

staffTask.List = async (req: CustomRequest, res: Response) => {
  const C = "Staff Task Controller";
  const F = "List";

  try {
    let { propFilters, taskDate, s, pageNum, filter, type } = req.query;

    const userType = req.userType;
    const platform = req.platform;
    const limit = 10;
    let summary = {totalRooms: 0, cleanedRooms: 0, uncleanedRooms: 0};

    log.info(
      `[${C}], [${F}], Task Type [${type}], Task Date [${taskDate}], Filter [${filter}], Page Num [${pageNum}], Prop Filter [${propFilters}], Search Value [${s}], Platform [${platform}]`,
    );

    // if (staffFilters && typeof staffFilters === "string") {
    //   staffFilters = staffFilters
    //     .split(",")
    //     .map((v) => v.trim())
    //     .filter(Boolean);
    // }
    if (propFilters && typeof propFilters === "string") {
      propFilters = propFilters
        .split(",")
        .map((v) => v.trim())
        .filter(Boolean);
    } else {
      propFilters = [];
    }

    const { 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}]`
        }, Platform [${req.platform}], ${
          isPartner ? "Partner Requesting" : "Client Requesting"
        }....`,
      );
      
      summary = await staffTasksDB.getSummaryByClientIdAndFilters({
        clientId,
        taskDate,
        propFilters: propFilters && Number(propFilters.length) > 0 ? propFilters : null,
      });
    } 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}], Client Id [${clientId}], Staff Id [${req.id}], Staff Role [${staff.role}], Platform [${req.platform}], Staff Requesting....`,
      );

      const staffLinkedProps = await propertyDB.getPropsByStaffId({
        staffId: staff.id,
      });

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

        if(propFilters && Number(propFilters.length) > 0) {
          //propFilters = Array.from(new Set([...propFilters, ...propertiesIds]));
          propFilters = propFilters;
        } else {
          propFilters = propertiesIds;
        }

        summary = await staffTasksDB.getSummaryByClientIdAndFiltersForStaff({
          clientId,
          propertiesIds,
          taskDate,
          propFilters: propFilters && Number(propFilters.length) > 0 ? propFilters : null,
        });
      }
    }

    let tasks = [];
    let roomsWithTasks = [];

    if (Number(type) === CONSTANTS.STAFF_TASK_TYPE.ROOM_TASK) {
      tasks = await staffTasksDB.getRoomTasksByClientIdAndFilters({
        clientId,
        taskDate,
        propFilters: propFilters ? propFilters : null,
        pageNum: null,
        limit,
      });
      
      if (tasks && tasks.length > 0) {
        for (let task of tasks) {
          const taskImages = await staffTasksDB.getByImagesByTaskId({
            staffTaskId: task.id,
            clientId,
          });
  
          task.taskImages = taskImages || [];
        }
      }
  
      const taskMap = tasks.reduce((acc: any, cur: any) => {
        if (!acc[cur.roomId]) acc[cur.roomId] = [];
        acc[cur.roomId].push(cur);
        return acc;
      }, {});
  
      const rooms = await roomDB.getByClientIdAndFilterForTask({
        clientId,
        propIds: propFilters && Number(propFilters.length) > 0 ? propFilters : null,
        taskDate,
        taskFilter: filter,
        searchVal: s,
        pageNum: pageNum && Number(pageNum) > 0 ? Number(pageNum) : null,
        limit,
      });
  
      roomsWithTasks = rooms.map((room: any) => ({
        ...room,
        tasks: taskMap[room.id] && taskMap[room.id].length > 0 ? taskMap[room.id] : null,
      }));
    } else if (Number(type) === CONSTANTS.STAFF_TASK_TYPE.COMMON_AREA_TASK) {
      tasks = await staffTasksDB.getCommonAreaTasksByClientIdAndFilters({
        clientId,
        taskDate,
        propFilters: propFilters ? propFilters : null,
        pageNum: pageNum && Number(pageNum) > 0 ? Number(pageNum) : null,
        limit,
      });
      
      if (tasks && tasks.length > 0) {
        for (let task of tasks) {
          const taskImages = await staffTasksDB.getByImagesByTaskId({
            staffTaskId: task.id,
            clientId,
          });
  
          task.taskImages = taskImages || [];
        }
      }

      roomsWithTasks = tasks || [];
    } else {
      log.info(`[${C}], [${F}], Client Id [${clientId}], Type [${type}], Invalid Task Type`);
      return res.status(400).json({ 
        msg: "Invalid task type", 
        isSuccess: false 
      });
    }
    

    const taskList = getStaffTaskList();
    const commonAreaTaskList = getCommonAreaTaskList();

    log.info(
      `[${C}], [${F}], Client Id [${clientId}], Page Num [${pageNum}], Prop Filter [${propFilters}], Search Value [${s}], Tasks List Sent Successfully`,
    );

    return res.status(200).json({
      msg: "Tasks list fetched successfully",
      isSuccess: true,
      data: roomsWithTasks || [],
      taskList: taskList || [],
      commonAreaTaskList: commonAreaTaskList || [],
      summary,
    });
  } 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 staffTask;
