// IMPORT LIBRARY
import { Request } from 'express';
import { Controller, UseAuth, Req, Get, Res, Response, HeaderParams, Post, BodyParams } from '@tsed/common';
import Joi from '@hapi/joi';
import { Docs } from '@tsed/swagger';
import { MultipartFile } from '@tsed/multipartfiles';

// IMPORT CUSTOM
import { CustomerInsert } from './../../entity-request/CustomerInsert';
import { MailService } from './../../services/MailService';
import { Validator } from '../../middleware/validator/Validator';
import { VerificationJWT } from '../../middleware/auth/VerificationJWT';
import { Customer } from '../../entity/Customer';
import { CustomerService } from '../../services/CustomerService';
import JWT, { AuthType } from '../../middleware/auth/strategy/JWT';
import { CustomerUpdate } from '../../entity-request/CustomerUpdate';
import { Password } from '../../util/password';
import { randomString, getCurrentTimeInt } from '../../util/helper';
import CONFIG from '../../../config';

@Controller("/customer/customer")
@Docs("docs_customer")
export class CustomerController {

    constructor(
        private customerService: CustomerService,
        private mailService: MailService
    ) { }


    // =====================REGISTER=====================
    @Post('/register')
    @Validator({
        customer: Joi.required()
    })
    async register(
        @HeaderParams("version") version: string,
        @Res() res: Response,
        @Req() req: Request,
        @BodyParams('customer') customer: CustomerInsert,
    ) {
        const newCustomer = await customer.toCustomer()
        await this.customerService.checkDuplicate(newCustomer)
        await newCustomer.save()

        return res.sendOK(newCustomer)
    }


    // =====================LOGIN=====================
    @Post('/login')
    @Validator({
        phone: Joi.string().required(),
        password: Joi.string().required()
    })
    async login(
        @HeaderParams("version") version: string,
        @BodyParams('phone') phone: string,
        @BodyParams('password') password: string,
        @BodyParams('expoToken') expoToken: string,
        @Res() res: Response
    ) {
        const customer = await this.customerService.login(phone, password);

        customer.expoToken = expoToken
        await customer.save()

        const token = JWT.sign({ id: customer.id, type: AuthType.Customer });
        
        return res.sendOK({ token })
    }


    // =====================PROFILE=====================
    @Get('/profile')
    @UseAuth(VerificationJWT)
    async getInfo(
        @HeaderParams("version") version: string,
        @HeaderParams("token") token: string,
        @Req() req: Request,
        @Res() res: Response,
    ) {
        return res.sendOK(req.customer)
    }


    // =====================UPDATE PROFILE=====================
    @Post('/profile')
    @UseAuth(VerificationJWT)
    async updateInfo(
        @HeaderParams("token") token: string,
        @HeaderParams("version") version: string,
        @Req() req: Request,
        @Res() res: Response,
        @BodyParams("customer") customer: CustomerUpdate,
    ) {
        const modifiedCustomer = customer.toCustomer()
        modifiedCustomer.id = req.customer.id
        await modifiedCustomer.save()

        return res.sendOK(modifiedCustomer)
    }


    // =====================UPDATE PASSWORD=====================
    @Post('/profile/password/update')
    @UseAuth(VerificationJWT)
    @Validator({
        oldPassword: Joi.string().required(),
        newPassword: Joi.string().required()
    })
    async changePassword(
        @HeaderParams("version") version: string,
        @HeaderParams("token") token: string,
        @Req() req: Request,
        @Res() res: Response,
        @BodyParams('oldPassword') oldPassword: string,
        @BodyParams('newPassword') newPassword: string,
    ) {
        const { customer } = req;

        const isValidPass = await customer.isValidPassword(oldPassword)
        if (!isValidPass) {
            return res.sendClientError('Mật khẩu cũ không đúng')
        }

        if (oldPassword == newPassword) {
            return res.sendClientError('Mật khẩu mới không được trùng mật khẩu cũ')
        }

        // Update password
        customer.password = await Password.hash(newPassword);
        await customer.save();

        return res.sendOK({}, 'Cập nhật mật khẩu thành công');
    }


    // =====================FORGOT=====================
    @Post('/password/forgot')
    @Validator({
        email: Joi.required(),
    })
    async forgot(
        @HeaderParams("version") version: string,
        @BodyParams("email") email: string,
        @Req() req: Request,
        @Res() res: Response,
    ) {
        const customer = await Customer.findOne({ where: { email } })
        if (!customer) {
            return res.sendClientError('Email không tồn tại')
        }

        const token = JWT.sign({ id: customer.id, type: AuthType.Customer, ia: getCurrentTimeInt() })
        this.mailService.sendMailLinkReset(token, customer)

        return res.sendOK({}, 'Vui lòng kiểm tra email và truy cập vào đường link xác nhận.')
    }


    // =====================CONFIRM FORGOT=====================
    @Post('/password/forgot/confirm')
    @Validator({
        token: Joi.required(),
    })
    async reForgot(
        @HeaderParams("version") version: string,
        @BodyParams("token") token: string,
        @Req() req: Request,
        @Res() res: Response,
    ) {
        const customerId = new JWT().getAuthId(token, AuthType.Customer)

        const customer = await Customer.findOne({ where: { id: customerId } })
        if (!customer) {
            return res.sendClientError("Tài khoản không tồn tại")
        }

        const ia = JWT.getIa(token)
        if (ia < customer.dateUpdated) {
            return res.sendClientError("Yêu cầu đã hết hạn. Vui lòng gửi yêu cầu khác.")
        }

        const newPassword = randomString(6)
        customer.password = await Password.hash(newPassword)
        await customer.save()

        this.mailService.sendMailReset(newPassword, customer)

        return res.sendOK(customer)
    }


    // =====================UPLOAD IMAGE=====================
    @Post('/upload')
    @UseAuth(VerificationJWT)
    uploadFile(
        @HeaderParams("version") version: string,
        @HeaderParams('token') token: string,
        @Res() res: Response,
        @MultipartFile('file') file: Express.Multer.File,
    ) {
        file.path = file.path.replace(CONFIG.UPLOAD_DIR, '');
        return res.sendOK(file)
    }

} // END FILE
