package com.izouma.nineth.web.mobile.v1;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

import com.izouma.nineth.aspect.CipherParam;
import com.izouma.nineth.aspect.RequestCipher;
import com.izouma.nineth.config.Constants;
import com.izouma.nineth.config.SysConstants;
import com.izouma.nineth.domain.*;
import com.izouma.nineth.dto.InviteDataDTO;
import com.izouma.nineth.dto.UserDTO;
import com.izouma.nineth.dto.pay.UniformBindBank;
import com.izouma.nineth.enums.*;
import com.izouma.nineth.exception.BusinessException;
import com.izouma.nineth.repo.*;
import com.izouma.nineth.service.*;
import com.izouma.nineth.service.pay.UniformPayConstants;
import com.izouma.nineth.service.pay.UniformPayUtil;
import com.izouma.nineth.service.sms.AliSmsService;
import com.izouma.nineth.service.sms.SmsService;
import com.izouma.nineth.utils.SecurityUtils;
import com.izouma.nineth.utils.SensitiveFilterUtil;
import com.izouma.nineth.web.BaseController;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

@AllArgsConstructor
@RestController
@RequestMapping("/user/v1")
public class UserControllerV1 extends BaseController {
    private UserRepo userRepo;
    private UserService userService;
    private UserBankCardRepo userBankCardRepo;
    private UniformPayUtil uniformPayUtil;
    private SysConfigService sysConfigService;
    private ActivityInviteService activityInviteService;
    private AliSmsService aliSmsService;
    private ActivityInviteRepo activityInviteRepo;
    private InviteDateRepo inviteDateRepo;
    private SmsService smsService;
    private AssetRepo assetRepo;
    private UserWareHouseRepo userWareHouseRepo;
    private UserFundAccountForLianlianpayService userFundAccountForLianlianpayService;
    private LianlianPayService lianlianPayService;


    @PostMapping("/save")
    public User save(@RequestBody User user) {
        Long userId = currentUser().getId();
        user.setId(userId);//安全控制，设置当前用户ID

        //过滤敏感词
        user.setNickname(SensitiveFilterUtil.sensitiveReplace(user.getNickname()));
        //过滤敏感词
        user.setIntro(SensitiveFilterUtil.sensitiveReplace(user.getIntro()));
        user = userService.update(user);
        return user;
    }

    @GetMapping("/my")
    public User my() {
        User user = userRepo.findById(SecurityUtils.getAuthenticatedUser().getId()).orElseThrow(new BusinessException("用户不存在"));
        user.setPassword(null);
        return user;

    }

    @PostMapping("/preEmptionPrivilege")
    public UserDTO preEmptionPrivilege(@RequestParam Integer projectId) {
        User user = currentUser();
        if (user == null) return null;
        List<UserWareHouse> userWareHouses = userWareHouseRepo.findUserIdItem(user.getId(),projectId);
        int count = 0;//白名单优先购次数
        for (UserWareHouse userWareHouse : userWareHouses) {
            if (userWareHouse.getAssetId() == null || userWareHouse.getAssetId() == 0) {
                LocalDateTime overdueTime  = userWareHouse.getOverdueTime();
                //判断白名单是否过期了
                if (overdueTime!=null && LocalDateTime.now().isAfter(overdueTime)){
                    userWareHouseRepo.softDelete(userWareHouse.getId());
                }else {
                    count += userWareHouse.getAdvancePurchaseCount();
                }
            }
        }
        UserDTO userDTO = userService.toDTO(user, false);
        if (count > 0) {
            userDTO.setPreEmptionPrivilege(new PreEmptionPrivilege(count, 0));//白名单
        }
        userDTO.setCount(count);
        user.setPassword(null);
        return  userDTO;
    }


    @PostMapping("/changePassword")
    @ApiOperation("修改密码")
    @RequestCipher
    public String changePassword(@CipherParam @RequestParam String encrytorData) {
        JSONObject jsonObject = JSON.parseObject(encrytorData);
        String password = jsonObject.getString("password");
        String code = jsonObject.getString("code");
        return userService.setPassword(SecurityUtils.getAuthenticatedUser().getId(), code, password);
    }

    @PostMapping("/forgotPassword")
    @ApiOperation("忘记密码")
    @RequestCipher
    public String forgotPassword(@CipherParam @RequestParam String encrytorData) {
        JSONObject jsonObject = JSON.parseObject(encrytorData);
        String password = jsonObject.getString("password");
        String code = jsonObject.getString("code");
        String phone = jsonObject.getString("phone");
        return userService.forgotPassword(phone, password, code);
    }

    @PostMapping("/setTradeCode")
    @ApiOperation("修改交易密码")
    @RequestCipher
    public void setTradeCode(@CipherParam @RequestParam String encrytorData,@RequestParam String code) {
        JSONObject jsonObject = JSON.parseObject(encrytorData);
        String tradeCode = jsonObject.getString("tradeCode");
        userService.setTradeCode(SecurityUtils.getAuthenticatedUser().getId(), currentUser().getPhone(), code, tradeCode);
    }

    @GetMapping("/tradeCodeStatus")
    public Object tradeCodeStatus() {
        return new HashMap<String, Object>() {{
            put("set", StringUtils.isNotBlank(
                    userRepo.findById(SecurityUtils.getAuthenticatedUser().getId()).map(User::getTradeCode).orElse(null)
            ));
        }};
    }

    @GetMapping("/myBankCard")
    public List<UserBankCard> myBankCard() {
        User user = currentUser();
        //限定查询当前支付平台关联的卡
        List<UserBankCard> dataList = userBankCardRepo.findByUserId(user.getId());

        //是否存在钱包
        UserFundAccount lianlianAccount = userFundAccountForLianlianpayService.getAccount(user.getId());
        if(lianlianAccount != null && lianlianAccount.getAccountStatus() == AccountStatus.NORMAL){
            dataList.forEach((item) -> {
                item.setHasWallet(true);
            });
        }

        return dataList;
    }

    /**
     * 新的绑卡发短信方法
     * @param phone
     * @param bankNo
     * @param password
     * @param randomKey
     * @return
     */
    @PostMapping("/addBankCardSendVerify")
    public JSONObject addBankCardSendVerify(@RequestParam String phone, @RequestParam String bankNo,
                                            String password, String randomKey) {
        User user = currentUser();
        if (!Pattern.matches(Constants.Regex.PHONE, phone)) {
            throw new BusinessException("请输入正确的手机号");
        }

        JSONObject result = new JSONObject();
        //兼容钱包绑卡申请
        UserFundAccount lianlianAccount = userFundAccountForLianlianpayService.getAccount(user.getId());
        if(lianlianAccount != null && lianlianAccount.getAccountStatus() == AccountStatus.NORMAL){
            if(StringUtils.isEmpty(password) || StringUtils.isEmpty(randomKey)){
                throw new BusinessException("用户已开通钱包，需要提供支付密码进行绑卡");
            }
            //钱包绑卡逻辑
            JSONObject res = lianlianPayService.bindCardApply(user.getId(), bankNo, phone, password, randomKey);
            String bindOrderNo = res.getString("txn_seqno");
            String token = res.getString("token");
            result.put("token", token);
            result.put("bindOrderNo", bindOrderNo);
        }else{
            String subject = smsService.sendVerify(phone);
            result.put("subject", subject);
        }

        return result;
    }


    @PostMapping("/addBankCard")
    public UserBankCard addBankCard(@RequestParam String bankNo, @RequestParam String phone,
                            @RequestParam String code, @RequestParam int projectId
                            ,String bindOrderNo, String token) throws Exception {
        Long userId = SecurityUtils.getAuthenticatedUser().getId();

        //卡号不能重复 查询有没有其他人绑定了IdentityAuthService
        if (userBankCardRepo.findByBankNo(bankNo, userId) >= sysConfigService.getInt(SysConstants.BANK_CARD_CAN_BE_BOUND)) {
            throw new BusinessException("银行卡已经被其他用户绑定");
        }

        Integer holdCount = userBankCardRepo.countByUserIdAndBankNo(userId, bankNo);
        if(holdCount > 0){
            throw new BusinessException("用户已绑定过该卡，请勿重复绑定");
        }

        UniformBindBank.UniformBindBankBuilder builder = UniformBindBank.builder();
        builder.userId(userId).bankNo(bankNo).phone(phone).smsCode(code)
        .bindOrderNo(bindOrderNo)
        .token(token);
        UniformBindBank bindBank = builder.build();

        //如果开通了钱包，走钱包绑卡逻辑
        UserFundAccount lianlianAccount = userFundAccountForLianlianpayService.getAccount(userId);
        if(lianlianAccount != null && lianlianAccount.getAccountStatus() == AccountStatus.NORMAL){
            bindBank.setPayPlatform(UniformPayConstants.LIANLIANPAY_PLATFORM);
        }

        UserBankCard userBankCard = uniformPayUtil.addBankCard(bindBank);

        activityInviteService.risingStar(userId, bankNo, InviteeQualificationsType.BIND_BANK_CARD);
        return userBankCard;
    }


    @PostMapping("/removeBankCardSendVerify")
    public String removeBankCardSendVerify() {
        User user = SecurityUtils.getAuthenticatedUser();
        List<UserBankCard> cardList = userBankCardRepo.findByUserId(user.getId());
        if (cardList.isEmpty()) {
            throw new BusinessException("你没有绑定银行卡");
        }
        String phone = cardList.get(0).getPhone();
        if (!Pattern.matches(Constants.Regex.PHONE, phone)) {
            throw new BusinessException("请输入正确的手机号");
        }

        if (!assetRepo.findAllByUserIdAndStatus(user.getId(), AssetStatus.TRADING).isEmpty()) {
            throw new BusinessException("有藏品正在交易中，请稍后在试");
        }
        if (!assetRepo.findAllByUserIdAndStatus(user.getId(), AssetStatus.GIFTING).isEmpty()) {
            throw new BusinessException("有藏品正在赠送中，请稍后在试");
        }
        List<Asset> assets = assetRepo.findAllByUserIdAndStatus(user.getId(), AssetStatus.NORMAL);
        if (!assets.isEmpty() && assets.stream().anyMatch(Asset::isConsignment)) {
            throw new BusinessException("有藏品正在寄售中，请先取消寄售");
        }

        UserFundAccount lianlianAccount = userFundAccountForLianlianpayService.getAccount(user.getId());
        if(lianlianAccount != null && lianlianAccount.getAccountStatus() == AccountStatus.NORMAL) {
            throw new BusinessException("用户已开通钱包，只允许换绑银行卡");
        }

        return smsService.sendVerify(phone);
    }

    @PostMapping("/removeBankCard")
    public void removeBankCard(@RequestParam String code, @RequestParam String password, @RequestParam Integer projectId) throws Exception {
        User user = SecurityUtils.getAuthenticatedUser();
        UserFundAccount lianlianAccount = userFundAccountForLianlianpayService.getAccount(user.getId());
        if(lianlianAccount != null && lianlianAccount.getAccountStatus() == AccountStatus.NORMAL) {
            throw new BusinessException("用户已开通钱包，只允许换绑银行卡");
        }

        userService.verifyTradeCode(user.getId(), password);//验证交易密码

        List<UserBankCard> cardList = userBankCardRepo.findByUserId(user.getId());
        if (cardList.isEmpty()) {
            throw new BusinessException("你没有绑定银行卡");
        }
        if (!assetRepo.findAllByUserIdAndStatus(user.getId(), AssetStatus.TRADING).isEmpty()) {
            throw new BusinessException("有藏品正在交易中，请稍后在试");
        }
        if (!assetRepo.findAllByUserIdAndStatus(user.getId(), AssetStatus.GIFTING).isEmpty()) {
            throw new BusinessException("有藏品正在赠送中，请稍后在试");
        }
        List<Asset> assets = assetRepo.findAllByUserIdAndStatus(user.getId(), AssetStatus.NORMAL);
        if (!assets.isEmpty() && assets.stream().anyMatch(Asset::isConsignment)) {
            throw new BusinessException("有藏品正在寄售中，请先取消寄售");
        }

        String phone = cardList.get(0).getPhone();
        aliSmsService.verify(phone, code);//验证交易手机验证码
        uniformPayUtil.removeBankCard(user.getId());
    }



    @PostMapping("/getUserInviteData")
    public Map<String, Object> getUserInviteData(@RequestParam int projectId) {
        Long userId = SecurityUtils.getAuthenticatedUser().getId();
        Map<String, Object> result = new HashMap<>();

        ActivityInvite activityInvite = activityInviteRepo.findRecent();
        if (activityInvite == null) {
            return result;
        }
        List<User> users = userRepo.getUserInviteData(userId, activityInvite.getInviteStartdatetime());
        List<InviteDataDTO> list1 = new ArrayList<>();
        List<InviteDataDTO> list2 = new ArrayList<>();
        List<InviteDataDTO> list3 = new ArrayList<>();
        users.forEach(user -> {
            InviteDataDTO inviteDataDTO = new InviteDataDTO();
            inviteDataDTO.phone = user.getPhone() == null ? "" : user.getPhone().substring(0, 3) + "****" + user.getPhone().substring(7);
            inviteDataDTO.authStatus = AuthStatus.SUCCESS.equals(user.getAuthStatus());
            inviteDataDTO.bankCard = uniformPayUtil.isBindBankCard(user.getId());
            if (inviteDataDTO.authStatus && inviteDataDTO.bankCard) {
                list1.add(inviteDataDTO);
            } else if (inviteDataDTO.authStatus) {
                list2.add(inviteDataDTO);
            } else {
                list3.add(inviteDataDTO);
            }
        });
        list1.addAll(list2);
        list1.addAll(list3);
        //邀请数量
        Integer inviteNum = inviteDateRepo.findinviterUserIdCount(activityInvite.getId(), userId, InvitationNote.SUCCESSFULLY.ordinal());
        //邀请新人空投数量
        Integer airDropAwardCount = inviteDateRepo.findinviterAirDropAward(activityInvite.getId(), userId);
        result.put("inviteData", list1);
        result.put("airdropcount", airDropAwardCount);
        result.put("inviteNum", inviteNum);
        return result;
    }

}


