import httpStatus from 'http-status';
import { Request, Response } from 'express';
import { Types } from 'mongoose';

import catchAsync from '@/shared/utils/catchAsync';

import { sendResetPasswordEmail } from '@/shared/email/email.service';
import responseCodes from '@/shared/utils/responseCode/responseCode';

import * as tokenService from '@/modules/token/token.service';
import * as authService from '@/modules/auth/auth.service';
import * as userService from '@/modules/user/user.service';
import { pick } from '@/shared/utils';
import { isCompanyUserMetaConnected } from '../meta/meta.helper';

const { UserResponseCodes } = responseCodes;

export const register = catchAsync(async (req: Request, res: Response) => {
  const user = await userService.createUser(req.body);
  const tokens = await tokenService.generateAuthTokens({
    id: user._id as Types.ObjectId,
    companyId: user.company.id._id as Types.ObjectId,
  });
  res.success(
    { user, tokens },
    UserResponseCodes.SUCCESS,
    'User Created Successfully',
  );
});

export const login = catchAsync(async (req: Request, res: Response) => {
  const { devicetoken } = req.headers;
  const { email, password } = req.body;
  const { user, permissions } = await authService.loginUserWithEmailAndPassword(
    email,
    password,
    devicetoken as string,
  );
  const tokens = await tokenService.generateAuthTokens({
    id: user.id as Types.ObjectId,
    companyId: user.companyId as Types.ObjectId,
  });

  const isMetaConnected = await isCompanyUserMetaConnected(
    user.id,
    user.companyId,
  );
  res.success(
    { user, tokens, permissions, isMetaConnected },
    UserResponseCodes.SUCCESS,
    'User Logged In Successfully',
  );
});

export const logout = catchAsync(async (req: Request, res: Response) => {
  await authService.logout(req.user.id, req.body.deviceToken);
  res.success(true, UserResponseCodes.SUCCESS, 'User Logged Out Successfully');
});

export const refreshTokens = catchAsync(async (req: Request, res: Response) => {
  const userWithTokens = await authService.refreshAuth(req.body.refreshToken);
  res.send({ ...userWithTokens });
});

export const forgotPassword = catchAsync(
  async (req: Request, res: Response) => {
    const resetPasswordToken = await tokenService.generateResetPasswordToken(
      req.body.email,
    );
    await sendResetPasswordEmail(req.body.email, resetPasswordToken);
    res.success(true, UserResponseCodes.SUCCESS, 'Email Sent Successfully');
  },
);

export const resetPassword = catchAsync(async (req: Request, res: Response) => {
  await authService.resetPassword(
    req.query['token'] as string,
    req.body.password,
  );
  res.success(true, UserResponseCodes.SUCCESS, 'Password Reset Successfully');
});

export const sendPasswordEmail = catchAsync(
  async (req: Request, res: Response) => {
    const { userId } = pick(req.params, ['userId', 'type']);
    const { type } = pick(req.query, ['type']);
    await authService.sendPasswordEmail(userId, type);
    res.success(true, UserResponseCodes.SUCCESS, 'Resend Email Successfully');
  },
);

export const verifyEmail = catchAsync(async (req: Request, res: Response) => {
  await authService.verifyEmail((req.query['token'] as string) || '');
  res.status(httpStatus.NO_CONTENT).send();
});

export const generateOtp = catchAsync(async (req: Request, res: Response) => {
  const orderId = await authService.generateAppUserOTP(req.body);

  return res.success(
    { orderId },
    UserResponseCodes.SUCCESS,
    'Otp sent successfully',
  );
});

export const resendOtp = catchAsync(async (req: Request, res: Response) => {
  const orderId = await authService.resendOtpToPhone(req.body);
  return res.success(
    { orderId },
    UserResponseCodes.SUCCESS,
    'Otp resend successfully',
  );
});

export const verifyOtp = catchAsync(async (req: Request, res: Response) => {
  const { user, permissions } = await authService.verifyPhoneOtp(req.body);
  const tokens = await tokenService.generateAuthTokens(user);

  return res.success(
    { user: user, tokens, permissions },
    UserResponseCodes.SUCCESS,
    'Otp Verified successfully',
  );
});
