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

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
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.AdamAccountConstants;
import com.liquidnet.service.adam.constant.AdamAdminisConstants;
import com.liquidnet.service.adam.constant.AdamUserConstants;
import com.liquidnet.service.adam.dto.AdamAccountWalletParam;
import com.liquidnet.service.adam.dto.AdamAdminisWalletParam;
import com.liquidnet.service.adam.dto.base.AdamCurrentUser;
import com.liquidnet.service.adam.entity.AdamAccountWallet;
import com.liquidnet.service.adam.entity.AdamComProfile;
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.AdamAdminisProcessHisVo;
import com.liquidnet.service.adam.vo.AdamWalletAccessVo;
import com.liquidnet.service.adam.vo.AdamWalletPermissionVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

@Slf4j
@Api(tags = "Wallet Access Administration")
@RestController
@RequestMapping("adam-wallet-adminis")
public class AdamWalletAdminisController {
    @Autowired
    private IAdamWalletAccessService adamWalletAccessService;
    @Autowired
    private IAdamAdminisProcessHisService adamAdminisProcessHisService;
    @Autowired
    private IAdamComProfileService adamComProfileService;
    @Autowired
    private IAdamAccountWalletService adamAccountWalletService;
    @Autowired
    private IAdamUserService adamUserService;

    @RequiresPermissions("BDCB8E7F")
    @ApiOperation(value = "Wallet access permission")
    @SwaggerApiVersion(group = AdamSwaggerApiVersionConstant.WEB_1_2)
    @GetMapping("permission")
    public ResponseDto<AdamWalletPermissionVo> getPermission(HttpServletRequest request) {
        AdamWalletPermissionVo vo = new AdamWalletPermissionVo();
        try {
            AdamCurrentUser currentUser = CurrentUserUtil.getCurrentUser(request);
            log.info("currentUser:" + JsonUtils.toJson(currentUser));

            // Wallet Access Permission
            List<AdamWalletAccessVo> walletAccessVoList = adamWalletAccessService.queryForWalletPermission(currentUser.getComId());

            // Special Setting
            Map<String, String> specialSttingMap = Maps.newHashMap();
            AdamComProfile adamComProfile = adamComProfileService.query("newWalletAssignToAllUser", currentUser.getComId());
            boolean notExist = null == adamComProfile;
            if (notExist) {
                notExist = adamComProfileService.initial(currentUser.getComId());
            }
            specialSttingMap.put("newWalletAssignToAllUser", notExist ? "No" : adamComProfile.getItemVal());

            // Process History
            Page<AdamAdminisProcessHisVo> adminisProcessHisVoPage =
                    adamAdminisProcessHisService.queryPageListForProcessHis(AdamAdminisConstants.ProcessHisTagEnum.WALLET_ACCESS_ADMINIS.val, 1, 5);

            vo.setWalletAccessVoList(walletAccessVoList);
            vo.setSpecialSettingMap(specialSttingMap);
            vo.setProcessHis(adminisProcessHisVoPage.getRecords());
        } catch (Exception e) {
            log.error("err:adam-wallet-adminis/permission", e);
        }
        return ResponseDto.success(vo);
    }

    @RequiresPermissions("BDCB8E7F")
    @ApiOperation(value = "Update wallet access permission")
    @SwaggerApiVersion(group = AdamSwaggerApiVersionConstant.WEB_1_2)
    @PostMapping("permission_up_do")
    public ResponseDto<?> permissionDo(HttpServletRequest request, @RequestParam("jStr") String paramStr) {
        try {
            log.info("paramStr:{}", paramStr);
            AdamAdminisWalletParam parameter = JsonUtils.fromJson(paramStr, AdamAdminisWalletParam.class);
//            AdamAdminisWalletParam parameter = JSON.parseObject(paramStr, AdamAdminisWalletParam.class);
            log.info("paramStr convert to parameter.AdamAdminisWalletParam:{}", JsonUtils.toJson(parameter));
            if (!Lists.newArrayList("Yes", "No").contains(parameter.getNewWalletAssignToAllUser())) {
                return ResponseDto.failure(AdamErrorCode.ADAM001_PARAM_ERROR.getCode(), AdamErrorCode.ADAM001_PARAM_ERROR.getVal().concat(":newWalletAssignToAllUser"));
            }
            AdamCurrentUser currentUser = CurrentUserUtil.getCurrentUser(request);

            Map<String, List<String>> walletAccessListMap = parameter.getWalletAccessListMap();
            Set<String> userIdSet = Sets.newHashSet();
            walletAccessListMap.forEach((k, v) -> {
                userIdSet.addAll(v);
            });
            AdamAccountWalletParam accountWalletParam = new AdamAccountWalletParam();
            accountWalletParam.setComId(currentUser.getComId());
            accountWalletParam.setState(AdamAccountConstants.StateEnum.S2.getCode());
            List<AdamAccountWallet> walletList = adamAccountWalletService.selectList(accountWalletParam);
            List<AdamAccountWallet> unionWalletList = walletList.stream().filter(r -> walletAccessListMap.containsKey(r.getFinWalletNo())).collect(Collectors.toList());
            if (walletAccessListMap.size() != unionWalletList.size()) {
                return ResponseDto.failure(AdamErrorCode.ADAM001_PARAM_ERROR.getCode(), AdamErrorCode.ADAM001_PARAM_ERROR.getVal().concat(":wallet no"));
            }
            List<AdamUser> userList = adamUserService.queryListForAdminis(currentUser.getComId());
            List<AdamUser> unionUserList = userList.stream().filter(r -> userIdSet.contains(r.getId())).collect(Collectors.toList());
            if (userIdSet.size() > unionUserList.size()) {
                return ResponseDto.failure(AdamErrorCode.ADAM001_PARAM_ERROR.getCode(), AdamErrorCode.ADAM001_PARAM_ERROR.getVal().concat(":user id"));
            }
            // Verify role:Administrator must select all by default
            for(AdamUser user : userList) {
                if (AdamUserConstants.UserRoleEnum.Administrator.name().equals(user.getRole())) {
                    for(Map.Entry<String, List<String>> entry : walletAccessListMap.entrySet()){
                        List<String> walletNoSelectUserIdList = entry.getValue();
                        if (!walletNoSelectUserIdList.contains(user.getId())) {
                            log.warn("warn:adam-wallet-adminis/permission_up_do:user[{}] is Administrator, wallet[{}] is not selected", user.getId(), entry.getKey());
                            return ResponseDto.failure(AdamErrorCode.ADAM_ADMINISTRATION_009005.getCode(), AdamErrorCode.ADAM_ADMINISTRATION_009005.getVal());
                        }
                    }
                }
            }

            boolean rst = adamWalletAccessService.saveUserAccessWithSpecialSetting(parameter, currentUser);

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

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