package com.liquidnet.service.adam.controller.web.administration;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.liquidnet.common.exception.constant.ErrorCode;
import com.liquidnet.common.swagger.config.SwaggerApiVersion;
import com.liquidnet.commons.lang.util.JsonUtils;
import com.liquidnet.service.ResponseDto;
import com.liquidnet.service.adam.common.AdamErrorCode;
import com.liquidnet.service.adam.config.swagger.AdamSwaggerApiVersionConstant;
import com.liquidnet.service.adam.constant.AdamAdminisConstants;
import com.liquidnet.service.adam.constant.AdamUserConstants;
import com.liquidnet.service.adam.dto.AdamAdminisUserParam;
import com.liquidnet.service.adam.dto.base.AdamCurrentUser;
import com.liquidnet.service.adam.dto.query.AdamCommonQuery;
import com.liquidnet.service.adam.entity.AdamUser;
import com.liquidnet.service.adam.interceptor.annotation.RequiresPermissions;
import com.liquidnet.service.adam.service.*;
import com.liquidnet.service.adam.util.CurrentUserUtil;
import com.liquidnet.service.adam.vo.AdamInviteUserVo;
import com.liquidnet.service.adam.vo.AdamUserAdminisListVo;
import com.liquidnet.service.adam.vo.AdamUserProfileVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Map;

@Slf4j
@Api(tags = "User Administration")
@RestController
@RequestMapping("adam-user-adminis")
public class AdamUserAdminisController {
    @Autowired
    private IAdamUserService adamUserService;
    @Autowired
    private IAdamRoleService adamRoleService;
    @Autowired
    private IAdamRolePermissionService adamRolePermissionService;
    @Autowired
    private IAdamWalletAccessService adamWalletAccessService;
    @Autowired
    private IAdamUserEmailService adamUserEmailService;
    @Autowired
    private IAdamAdminisProcessHisService adamAdminisProcessHisService;

    @RequiresPermissions("B235B1CC")
    @ApiOperation(value = "List for user adminis")
    @SwaggerApiVersion(group = AdamSwaggerApiVersionConstant.WEB_1_2)
    @GetMapping("list_page")
    public ResponseDto<Page<AdamUserAdminisListVo>> getUserAdminisList(HttpServletRequest request, @ModelAttribute AdamCommonQuery queryParameter) {
        Page<AdamUserAdminisListVo> targetPage = new Page<>();
        try {
            AdamCurrentUser currentUser = CurrentUserUtil.getCurrentUser(request);
            queryParameter.setComId(currentUser.getComId());
            Page<AdamUser> sourcePage = adamUserService.queryPageListForAdminis(queryParameter);
            List<AdamUser> sourceRecords = sourcePage.getRecords();

            List<AdamUserAdminisListVo> targetRecords = Lists.newArrayList();

            sourceRecords.forEach(r -> {
                targetRecords.add(AdamUserAdminisListVo.getNew().copy(r));
            });

            sourcePage.setRecords(null);
            BeanUtils.copyProperties(sourcePage, targetPage);
            targetPage.setRecords(targetRecords);
        } catch (Exception e) {
            log.error("err:adam-user-adminis/list_page:queryParameter:{}", JsonUtils.toJson(queryParameter), e);
        }
        return ResponseDto.success(targetPage);
    }

    @RequiresPermissions("B235B1CC")
    @ApiOperation(value = "Details for user profile")
    @SwaggerApiVersion(group = AdamSwaggerApiVersionConstant.WEB_1_2)
    @GetMapping("user_profile_details")
    public ResponseDto<AdamUserProfileVo> getUserProfileDetails(@RequestParam String userId) {
        AdamUserProfileVo vo = new AdamUserProfileVo();
        try {
            vo = adamUserService.queryByUserId(userId, AdamAdminisConstants.ProcessHisTagEnum.USER_ADMINIS.val, 1, 5);
        } catch (Exception e) {
            log.error("err:adam-user-adminis/user_profile_details:user_id:{}", userId, e);
        }
        return ResponseDto.success(vo);
    }

    @RequiresPermissions("B235B1CC")
    @ApiOperation(value = "Invite user page")
    @SwaggerApiVersion(group = AdamSwaggerApiVersionConstant.WEB_1_2)
    @GetMapping("invite_user")
    public ResponseDto<AdamInviteUserVo> inviteUser(HttpServletRequest request) {
        AdamInviteUserVo vo = new AdamInviteUserVo();
        try {
            AdamCurrentUser currentUser = CurrentUserUtil.getCurrentUser(request);

            vo.setRoleMap(adamRoleService.query());
            vo.setRolePermissionsMap(adamRolePermissionService.queryRolePermissions());
            vo.setUserAllowedWallets(adamWalletAccessService.queryForUserProfileAdminis(currentUser.getComId(), currentUser.getId()));
        } catch (Exception e) {
            log.error("err:adam-user-adminis/invite_user", e);
        }
        return ResponseDto.success(vo);
    }

    @RequiresPermissions("B235B1CC")
    @ApiOperation(value = "Invite user to process")
    @SwaggerApiVersion(group = AdamSwaggerApiVersionConstant.WEB_1_2)
    @PostMapping("invite_user_do")
    public ResponseDto<?> inviteUserDo(HttpServletRequest request, @ModelAttribute AdamAdminisUserParam parameter) {
        try {
            if (StringUtils.isEmpty(parameter.getFirstName()) || StringUtils.isEmpty(parameter.getLastName())) {
                return ResponseDto.failure(AdamErrorCode.NAME_LOST.getCode(), AdamErrorCode.NAME_LOST.getVal());
            }
            if (StringUtils.isEmpty(parameter.getJobTitle())) {
                return ResponseDto.failure(AdamErrorCode.JOB_TITLE_LOST.getCode(), AdamErrorCode.JOB_TITLE_LOST.getVal());
            }
            if (StringUtils.isEmpty(parameter.getCompanyEmail())) {
                return ResponseDto.failure(AdamErrorCode.EMAIL_LOST.getCode(), AdamErrorCode.EMAIL_LOST.getVal());
            }
            Map<String, String> roleMap = adamRoleService.query();
            if (!roleMap.containsKey(parameter.getRoleId())) {
                return ResponseDto.failure(AdamErrorCode.ADAM001_ILLEGAL_PARAM.getCode(), AdamErrorCode.ADAM001_ILLEGAL_PARAM.getVal().concat(String.format(":roleId[%s]", parameter.getRoleId())));
            }
            if (CollectionUtils.isEmpty(parameter.getUserPermissionList())) {
                return ResponseDto.failure(AdamErrorCode.ADAM001_PARAM_ERROR.getCode(), AdamErrorCode.ADAM001_PARAM_ERROR.getVal().concat(":userPermissionList is empty"));
            }

            AdamCurrentUser currentUser = CurrentUserUtil.getCurrentUser(request);

            return adamUserService.inviteUserDo(currentUser, roleMap.get(parameter.getRoleId()), parameter);
        } catch (Exception e) {
            log.error("err:adam-user-adminis/invite_user_do:parameter:{}", parameter, e);
            return ResponseDto.failure(ErrorCode.RESPONSE_ERROE_SYSTEM);
        }
    }

    @RequiresPermissions("B235B1CC")
    @ApiOperation(value = "Update user invite to process")
    @SwaggerApiVersion(group = AdamSwaggerApiVersionConstant.WEB_1_2)
    @PostMapping("invite_user_up_do")
    public ResponseDto<?> inviteUserUpDo(HttpServletRequest request, @ModelAttribute AdamAdminisUserParam parameter) {
        try {
            if (StringUtils.isEmpty(parameter.getUserId())) {
                return ResponseDto.failure(AdamErrorCode.ADAM001_PARAM_ERROR.getCode(), AdamErrorCode.ADAM001_PARAM_ERROR.getVal().concat(":userId is empty"));
            }
            if (StringUtils.isEmpty(parameter.getFirstName()) || StringUtils.isEmpty(parameter.getLastName())) {
                return ResponseDto.failure(AdamErrorCode.NAME_LOST.getCode(), AdamErrorCode.NAME_LOST.getVal());
            }
            if (StringUtils.isEmpty(parameter.getJobTitle())) {
                return ResponseDto.failure(AdamErrorCode.JOB_TITLE_LOST.getCode(), AdamErrorCode.JOB_TITLE_LOST.getVal());
            }
            if (StringUtils.isEmpty(parameter.getCompanyEmail())) {
                return ResponseDto.failure(AdamErrorCode.EMAIL_LOST.getCode(), AdamErrorCode.EMAIL_LOST.getVal());
            }
            Map<String, String> roleMap = adamRoleService.query();
            if (!roleMap.containsKey(parameter.getRoleId())) {
                return ResponseDto.failure(AdamErrorCode.ADAM001_ILLEGAL_PARAM.getCode(), AdamErrorCode.ADAM001_ILLEGAL_PARAM.getVal().concat(String.format(":roleId[%s]", parameter.getRoleId())));
            }
            if (CollectionUtils.isEmpty(parameter.getUserPermissionList())) {
                return ResponseDto.failure(AdamErrorCode.ADAM001_PARAM_ERROR.getCode(), AdamErrorCode.ADAM001_PARAM_ERROR.getVal().concat(":userPermissionList is empty"));
            }
            AdamCurrentUser currentUser = CurrentUserUtil.getCurrentUser(request);
            if (parameter.getUserId().equals(currentUser.getId())) {
                return ResponseDto.failure(AdamErrorCode.ADAM_ADMINISTRATION_009004.getCode(), AdamErrorCode.ADAM_ADMINISTRATION_009004.getVal());
            }

            return adamUserService.updateInviteDo(currentUser, roleMap.get(parameter.getRoleId()), parameter);
        } catch (Exception e) {
            log.error("err:adam-user-adminis/update_invite_do:parameter:{}", JsonUtils.toJson(parameter), e);
            return ResponseDto.failure(ErrorCode.RESPONSE_ERROE_SYSTEM);
        }
    }

    @RequiresPermissions("B235B1CC")
    @ApiOperation(value = "Resend invite to process")
    @SwaggerApiVersion(group = AdamSwaggerApiVersionConstant.WEB_1_2)
    @ApiImplicitParams({
            @ApiImplicitParam(type = "query", dataType = "String", name = "userId", value = "Adam user ID [64]", required = true),
    })
    @PostMapping("invite_resend_do")
    public ResponseDto<?> inviteResendDo(HttpServletRequest request, @RequestParam String userId) {
        try {
            if (StringUtils.isEmpty(userId)) {
                return ResponseDto.failure(AdamErrorCode.ADAM001_PARAM_ERROR.getCode(), AdamErrorCode.ADAM001_PARAM_ERROR.getVal().concat(":userId is empty"));
            }
            AdamUser adamUser = adamUserService.selectById(userId);
            if (null == adamUser) {
                log.warn("warn:adam-user-adminis/resend_invite:[{} not exist]", userId);
                return ResponseDto.failure(AdamErrorCode.ADAM001_PARAM_ERROR.getCode(), AdamErrorCode.ADAM001_PARAM_ERROR.getVal().concat(":user id"));
            }
            if (!AdamUserConstants.UserStatusEnum.INVITED.getCode().equals(adamUser.getStatus())) {
                log.warn("warn:adam-user-adminis/resend_invite:Illegal operation:user[{}] status is {}", userId, AdamUserConstants.UserStatusEnum.byCode(adamUser.getStatus()).getDesc());
                return ResponseDto.failure(AdamErrorCode.ADAM001_PARAM_ERROR.getCode(), AdamErrorCode.ADAM001_PARAM_ERROR.getVal().concat(":user id"));
            }

            return ResponseDto.success(adamUserEmailService.userEmailAuthForInvite(adamUser, false));
        } catch (Exception e) {
            log.error("err:adam-user-adminis/resend_invite:user_id:{}", userId, e);
            return ResponseDto.failure(ErrorCode.RESPONSE_ERROE_SYSTEM);
        }
    }

    @RequiresPermissions("B235B1CC")
    @ApiOperation(value = "Remove user to process")
    @SwaggerApiVersion(group = AdamSwaggerApiVersionConstant.WEB_1_2)
    @ApiImplicitParams({
            @ApiImplicitParam(type = "query", dataType = "String", name = "userId", value = "Adam user ID [64]", required = true),
    })
    @PostMapping("remove_user_do")
    public ResponseDto<?> removeUserDo(HttpServletRequest request, @RequestParam String userId) {
        try {
            if (StringUtils.isEmpty(userId)) {
                return ResponseDto.failure(AdamErrorCode.ADAM001_PARAM_ERROR.getCode(), AdamErrorCode.ADAM001_PARAM_ERROR.getVal().concat(":userId is empty"));
            }
            AdamCurrentUser currentUser = CurrentUserUtil.getCurrentUser(request);
            if (userId.equals(currentUser.getId())) {
                return ResponseDto.failure(AdamErrorCode.ADAM_ADMINISTRATION_009004.getCode(), AdamErrorCode.ADAM_ADMINISTRATION_009004.getVal());
            }

            boolean rst = adamUserService.updateStatus(userId, AdamUserConstants.UserStatusEnum.REMOVED) > 0;

            if (rst) {// Record process history
                adamAdminisProcessHisService.record(AdamAdminisConstants.ProcessHisEnum.USER_ADMINIS_REMOVED, null,
                        new String[]{currentUser.getComId(), userId, currentUser.getId(), currentUser.getName()});
            }

            return rst ? ResponseDto.success() : ResponseDto.failure(ErrorCode.RESPONSE_ERROE_BIZ);
        } catch (Exception e) {
            log.error("err:adam-user-adminis/remove_user_do:user_id:{}", userId, e);
            return ResponseDto.failure(ErrorCode.RESPONSE_ERROE_SYSTEM);
        }
    }
}
