import {Request, Response} from 'express';
import {getAllUsersSvc, getAllAdminsSvc} from './auth.service';
import {adminRes} from './auth.dto';
import {responseJSON} from '../../helpers/response-handler';
import {CustomException} from '../../exceptions/CustomException';
import {EXCEPTION_MESSAGE} from '../../exceptions/EXCEPTION_MESSAGE';
import {createUserSvc} from '../users/user.service';
import {getUserByEmailRpo} from '../users/user.repository';
import {verifyPassword} from '../../helpers/tools';
import {userRes} from '../users/user.dto';

import {getTokenSvc, operatorSignUpSvc, profileSvc} from '../auth/auth.service';
import {loginSchema, registerSchema, profileSchema} from './auth.validation';

const {JWT_SECRET, JWT_EXPIRES_IN, REFRESH_JWT_SECRET, REFRESH_JWT_EXPIRES_IN} =
  process.env;
const jwt = require('jsonwebtoken');

// TEMPLATE START
export const register = async (req: Request, res: Response) => {
  try {
    const validation = registerSchema.validate(req.body, {
      allowUnknown: true,
    });

    if (validation.error) {
      throw new CustomException(
        EXCEPTION_MESSAGE.MISSING_REQUIRED_DATA,
        validation.error,
      );
    }

    if (await getUserByEmailRpo(validation.value.email)) {
      throw new CustomException(EXCEPTION_MESSAGE.EMAIL_ALREADY_EXISTS);
    }

    const user = await createUserSvc(req.body);
    return responseJSON(req, res, {data: userRes(user)});
  } catch (error) {
    return responseJSON(req, res, error, true);
  }
};

export const login = async (req: Request, res: Response) => {
  const validation = loginSchema.validate(req.body, {
    allowUnknown: true,
  });

  if (validation.error) {
    throw new CustomException(
      EXCEPTION_MESSAGE.MISSING_REQUIRED_DATA,
      validation.error,
    );
  }

  try {
    const user = await getUserByEmailRpo(validation.value.email);
    if (!user) {
      throw new CustomException(EXCEPTION_MESSAGE.USER_NOT_FOUND);
    }

    const isPasswordValid = verifyPassword(
      validation.value.password,
      user.password,
      validation.value.email,
    );
    if (!isPasswordValid) {
      throw new CustomException(EXCEPTION_MESSAGE.NOT_AUTHORIZED);
    }

    const token = jwt.sign(
      {
        userId: user.id,
        email: user.email,
      },
      JWT_SECRET,
      {expiresIn: JWT_EXPIRES_IN},
    );

    const refreshToken = jwt.sign(
      {
        userId: user.id,
        email: user.email,
      },
      REFRESH_JWT_SECRET,
      {expiresIn: REFRESH_JWT_EXPIRES_IN},
    );

    return responseJSON(req, res, {token, refreshToken});
  } catch (error) {
    return responseJSON(req, res, error, true);
  }
};

export const refreshToken = async (req: Request, res: Response) => {
  try {
    const refreshToken = req.body.refreshToken;
    const decoded = jwt.verify(refreshToken, REFRESH_JWT_SECRET);
    const token = jwt.sign(
      {
        userId: decoded.userId,
        email: decoded.email,
      },
      JWT_SECRET,
      {expiresIn: JWT_EXPIRES_IN},
    );
    return responseJSON(req, res, {token});
  } catch (error) {
    return responseJSON(req, res, error, true);
  }
};

// TEMPLATE END

//V1 ================================================================
export const getToken = async (req: Request, res: Response) => {
  const validation = loginSchema.validate(req.body, {
    allowUnknown: true,
  });

  if (validation.error) {
    return responseJSON(
      req,
      res,
      {
        obj: {
          code: 400,
          message: 'Bad Request',
        },
      },
      true,
    );
  }

  try {
    const {username, key} = req.body;
    const data = await getTokenSvc(username, key);

    if ('error' in data) {
      const {message, code} = data.error;
      return responseJSON(
        req,
        res,
        {
          obj: {
            code: 400,
            message: message,
          },
        },
        true,
        code, // Cek Dokumentasi GG halaman terakhir
      );
    }

    return responseJSON(req, res, data);
  } catch (error) {
    return responseJSON(req, res, error, true);
  }
};

export const operatorSignUp = async (req: Request, res: Response) => {
  const validation = registerSchema.validate(req.body, {
    allowUnknown: true,
  });

  if (validation.error) {
    return responseJSON(
      req,
      res,
      {
        obj: {
          code: 400,
          message: 'Bad Request',
        },
      },
      true,
    );
  }

  try {
    const {appid, username, email, key} = req.body;
    const data = await operatorSignUpSvc(appid, username, email, key);

    if ('error' in data) {
      const {message, code} = data.error;
      return responseJSON(
        req,
        res,
        {
          obj: {
            code: 400,
            message: message,
          },
        },
        true,
        code, // Cek Dokumentasi GG halaman terakhir
      );
    }

    return responseJSON(req, res, data);
  } catch (error) {
    return responseJSON(req, res, error, true);
  }
};

// V1 ================================================================

export const profile = async (req: Request, res: Response) => {
  const authHeader = req.header('Authorization');
  const token = authHeader && authHeader.replace('Bearer ', '');

  try {
    const decoded = jwt.verify(token, process.env.ADMIN_CLIENT_SECRET || '');
    const data = {
      username: decoded.username,
      email: decoded.email,
    };
    return responseJSON(req, res, {data});
  } catch (error) {
    return responseJSON(req, res, error, true);
  }
};
