import { Request, Response } from 'express';
import { verifyAccess } from '../middlewares/authentication';
import { Asset, User } from '../models';
import { SEARCH_QUERY } from '../utils/constants';
import {
  createAsssetSchema,
  editAsssetSchema,
  getAsssetSchema,
  activateAssetSchema,
  batchActivateAssetSchema,
} from '../validators/assetValidator';

export const deactivateOrActivateAsset = async (
  req: Request,
  res: Response,
) => {
  const { company_id } = req.user!;
  const { error: errorParams, value: valueParams } =
    activateAssetSchema.params.validate(req.params);
  const { error: errorQuery, value: valueQuery } =
    activateAssetSchema.query.validate(req.query);

  if (errorParams || errorQuery) {
    return res.status(400).json({
      success: false,
      message: errorParams
        ? errorParams.details[0].message
        : errorQuery!.details[0].message,
    });
  }
  const { assetID } = valueParams;
  const { action } = valueQuery;

  const asset = await Asset.findOne({
    company_id,
    _id: assetID,
  });
  if (!asset)
    return res.status(404).json({
      success: false,
      message: 'Asset does not exist',
    });

  if (action === 'activate') {
    if (asset.assetStatus)
      return res.status(401).json({
        success: false,
        message: 'Asset is already activated',
      });
    asset.assetStatus = true;
    await asset.save();
    return res.status(201).json({
      success: true,
      message: 'Asset activated successfully',
    });
  }

  if (!asset.assetStatus)
    return res.status(401).json({
      success: false,
      message: 'Asset is already deactivated',
    });
  asset.assetStatus = false;
  await asset.save();
  return res.status(201).json({
    success: true,
    message: 'Asset deactivated successfully',
  });
};

export const batchDeactivateOrActivateAsset = async (
  req: Request,
  res: Response,
) => {
  const { company_id } = req.user!;
  const { error: errorParams, value: valueParams } =
    batchActivateAssetSchema.params.validate(req.params);
  const { error: errorBody, value: valueBody } =
    batchActivateAssetSchema.body.validate(req.body);

  if (errorParams || errorBody) {
    return res.status(400).json({
      success: false,
      message: errorParams
        ? errorParams.details[0].message
        : errorBody!.details[0].message,
    });
  }
  const { action } = valueParams;
  const { assetID } = valueBody;
  const actionType = action === 'activate';

  await Asset.updateMany(
    { _id: { $in: assetID }, company_id },
    { assetStatus: actionType },
  );

  return res.status(201).json({
    success: true,
    message: `Users ${action}d successfully`,
  });
};

export const createAsset = async (req: Request, res: Response) => {
  const { company_id } = req.user!;
  const { error, value } = createAsssetSchema.body.validate(req.body);

  if (error) {
    return res.status(400).json({
      success: false,
      message: error.details[0].message,
    });
  }
  const { assetName, regNo, idNo, assignee } = value;

  const validAccess = await verifyAccess(req, 'create_assets');
  if (!validAccess) {
    return res.status(403).json({
      success: false,
      message: 'Access denied',
    });
  }

  if (assignee) {
    const exist = await User.findOne({
      company_id,
      _id: assignee,
      userType: 'rider',
    });

    if (!exist) {
      return res.status(404).json({
        success: false,
        message: 'Rider does not exist',
      });
    }
  }

  try {
    const existing = await Asset.findOne({
      company_id,
      $or: [{ regNo }, { idNo }, { assetName }],
    });

    if (existing) {
      return res.status(401).json({
        success: false,
        message: `Asset with either ${assetName} or ${regNo} or ${idNo} already exists`,
      });
    }

    const data = {
      company_id,
      assetName,
      regNo,
      idNo,
      assetStatus: true,
      assignee,
    };

    if (assignee) {
      Object.assign(data, { assignedStatus: true });
    }

    const newRole = await Asset.create(data);

    return res.status(201).json({
      success: true,
      message: 'Asset created successfully',
      data: {
        role: newRole,
      },
    });
  } catch (err: any) {
    return res.status(500).json({
      success: false,
      message: err.message,
    });
  }
};

export const editAsset = async (req: Request, res: Response) => {
  const { company_id } = req.user!;
  const { error: errorParams, value: valueParams } =
    editAsssetSchema.params.validate(req.params);
  const { error: errorBody, value: valueBody } = editAsssetSchema.body.validate(
    req.body,
  );

  if (errorParams || errorBody) {
    return res.status(400).json({
      success: false,
      message: errorParams
        ? errorParams.details[0].message
        : errorBody!.details[0].message,
    });
  }
  const { assetID } = valueParams;
  const { assetName, regNo, idNo, assignee } = valueBody;

  const validAccess = await verifyAccess(
    req,
    'create_assets',
    'view_dispatchers',
  );
  if (!validAccess) {
    return res.status(403).json({
      success: false,
      message: 'Access denied',
    });
  }

  if (assignee) {
    const exist = await User.findOne({
      company_id,
      _id: assignee,
      userType: 'rider',
    });

    if (!exist) {
      return res.status(404).json({
        success: false,
        message: 'Rider does not exist',
      });
    }
  }

  const asset = await Asset.findOne({
    company_id,
    _id: assetID,
  });
  if (!asset)
    return res.status(404).json({
      success: false,
      message: 'Role does not exist',
    });

  asset.assetName = assetName || asset.assetName;
  asset.regNo = regNo || asset.regNo;
  asset.idNo = idNo || asset.idNo;
  asset.assignee = assignee || asset.assignee;

  if (assignee === null) {
    asset.set({
      assignee: undefined,
      assignedStatus: false,
    });
  } else {
    asset.set({
      assignee,
      assignedStatus: true,
    });
  }

  await asset.save();

  return res.status(201).json({
    success: true,
    message: 'Asset updated successfully',
    data: {
      asset,
    },
  });
};

export const getAssets = async (req: Request, res: Response) => {
  const { company_id } = req.user!;
  const { error, value } = getAsssetSchema.query.validate(req.query);

  if (error) {
    return res.status(400).json({
      success: false,
      message: error.details[0].message,
    });
  }
  const { assetID, keyword, assetStatus, assignedStatus, sort, limit, page } = value;

  const validAccess = await verifyAccess(req, 'view_assets');
  if (!validAccess) {
    return res.status(403).json({
      success: false,
      message: 'Access denied',
    });
  }

  const selector = { company_id };

  let sortBy: string = 'createdAt';
  let sortOrder: string = 'desc';
  if (sort !== undefined){
    sortBy = sort.field ? sort.field : sortBy;
    sortOrder = sort.sort ? sort.sort : sortOrder;
  }
  const options = {
    limit: SEARCH_QUERY.LIMIT,
    sort: [[sortBy, sortOrder]],
    // sort: { createdAt: 'desc' },
    populate: 'assignee',
  };

  try {
    //Quering
    if (assetID) {
      Object.assign(selector, { _id: assetID });
    }
    if (keyword) {
      Object.assign(selector, 
        {
          $or:[
            {
              regNo: keyword
            },
            {
              idNo: keyword
            },
            {
              assetName: new RegExp(`^.*${keyword}.*$`, 'i')
            } 
          ]
        });
    }
 
    if (assetStatus) {
      let assetStatusOpt: boolean;
      if(assetStatus === 'true'){
        assetStatusOpt = true;
      } else {
        assetStatusOpt = false;
      }
      Object.assign(selector, { assetStatus: assetStatusOpt });
    }
    if (assignedStatus) {
      let assignedStatusOpt: boolean;
      if(assignedStatus === 'true'){
        assignedStatusOpt = true;
      } else {
        assignedStatusOpt = false;
      }
      Object.assign(selector, { assignedStatus: assignedStatusOpt });
    }
    if (limit) {
      Object.assign(options, { limit });
    }
    if (page) {
      Object.assign(options, { page });
    }
    const assetsInfo = await Asset.paginate(selector, options);
    const assets = assetsInfo.docs;

    if (assetID && !assets.length) {
      return res.status(404).json({
        success: false,
        message: 'Asset does not exist',
      });
    }

    return res.status(200).json({
      success: true,
      message: 'Roles request successful',
      data: {
        asset: assetID ? assets[0] : assets,
        limit: assetsInfo.limit,
        hasPrevPage: assetsInfo.hasPrevPage,
        hasNextPage: assetsInfo.hasNextPage,
        totalData: assetsInfo.totalDocs,
        currentPage: assetsInfo.page,
        totalPages: assetsInfo.totalPages,
      },
    });
  } catch (err: any) {
    return res.status(500).json({
      success: false,
      message: err.message,
    });
  }
};
