import { NextFunction, Request, Response } from "express";
import jwt from "jsonwebtoken";
import log from "../config/log";
import CONSTANTS from "../config/constants";
import staffDB from "../models/staff.model";
import tenantDB from "../models/tenant.model";
import clientDB from "../models/client.model";
import occupancyDB from "../models/occupancy.model";
import CustomRequest from "../types/requestType";

const authorize = async (
  req: CustomRequest,
  res: Response,
  next: NextFunction
) => {
  const token = req.headers.authorization;
  if (!token) {
    log.info("[Middleware], [Authorization], No Token Available");
    return res.status(401).json({
      msg: "Unauthorized Access",
      isSuccess: false,
    });
  }
  try {
    //log.info(`[Middleware], [Authorization], Token [${token}], Verifying Token`);
    const decoded: any = jwt.verify(
      token.replace("Bearer ", ""),
      process.env.TOKEN_SECRET as string
    );

    const { id, type, platform, isEvicted, clientId, parentClientId, role, switchingClient } = decoded;

    req.id = id;
    req.userType = type;
    req.platform = platform || CONSTANTS.TENANT_DEVICE_TYPE.ANDROID;
    req.parentClientId = parentClientId || id;
    req.switchingClient = switchingClient? switchingClient : id;

    if(!id && decoded?.routeAccess && 'CLIENT_WEBSITE' === platform) {
      let routeAccess = decoded?.routeAccess;
      const hasAccess = routeAccess.includes(req.originalUrl);
      log.info(`[Middleware], [Authorization], Token [${token}], Accessing route [${req.originalUrl}], Has Access [${hasAccess}]`);
      if(!hasAccess) {
        return res.status(401).json({
          msg: "Unauthorized Access",
          isSuccess: false,
        });
      }
    }
    if (CONSTANTS.USER_TYPE.TENANT == req.userType) {
      req.isEvicted = isEvicted;
      req.clientId = clientId;
    }
    if(CONSTANTS.USER_TYPE.STAFF == req.userType) {
      //req.clientId = clientId;
      let staff = await staffDB.getById({id: req.id});
      if(staff && staff?.status != CONSTANTS.STAFF_STATUS.ACTIVE) {
          log.info(`[Middleware], [Authorization], Staff Id [${req.id}], User Type [${req.userType}], User no more active, Token Expired`);
          return res.status(401).json({
            msg: "Session Expired",
            isSuccess: false,
          });
      } else if(role && Number(role) != Number(staff?.role)) {
        log.info(`[Middleware], [Authorization], Staff Id [${req.id}], User Type [${req.userType}], Token Role [${role}], Role Mismatch`);
          return res.status(401).json({
            msg: "Session Expired",
            isSuccess: false,
          });
      }
      if(staff) {
        const clientId = staff?.clientId;
        let client = await clientDB.getById({id: clientId});
        if(client && Number(client?.status) === CONSTANTS.CLIENT_STATUS.DEFAULTER) {
          log.info(`[Middleware], [Authorization], Staff Id [${req.id}], User Type [${req.userType}], Client Id [${req.id}], Client blocked due to defaulter`);
          return res.status(400).json({
            msg: "Your account is currently blocked",
            isSuccess: false,
          });
        }
      }
    }
    if(CONSTANTS.USER_TYPE.CLIENT === req.userType) {
      let client = await clientDB.getById({id: req.id});
      if(client && Number(client?.status) === CONSTANTS.CLIENT_STATUS.DEFAULTER) {
        log.info(`[Middleware], [Authorization], Client Id [${req.id}], User Type [${req.userType}], Client blocked due to defaulter`);
        return res.status(400).json({
          msg: "Your account is currently blocked",
          isSuccess: false,
        });
      }
    }
    next();
  } catch (err: any) {
    //log.info(`[Middleware], [Authorization], Token [${token}], Token Expired`);
    log.info(`[Middleware], [Authorization], Token [${token}], [Token Expired], Catch Error [${JSON.stringify(err)}]`);
    return res.status(401).json({
      msg: err?.message || err,
      isSuccess: false,
    });
  }
};

export default authorize;
