package com.liquidnet.service.goblin.controller;

import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import com.liquidnet.commons.lang.util.CurrentUtil;
import com.liquidnet.commons.lang.util.DESUtils;
import com.liquidnet.commons.lang.util.DateUtil;
import com.liquidnet.service.base.ErrorMapping;
import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.goblin.constant.GoblinStatusConst;
import com.liquidnet.service.goblin.dto.GoblinUserNftAccInfoVo;
import com.liquidnet.service.goblin.dto.GoblinUserSafeConfigDto;
import com.liquidnet.service.goblin.dto.vo.*;
import com.liquidnet.service.goblin.service.IGoblinUserDigitalArtworkService;
import com.liquidnet.service.goblin.util.GoblinRedisUtils;
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.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.constraints.NotBlank;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;

@ApiSupport(order = 142000)
@Api(tags = "我的藏品管理")
@Slf4j
@Validated
@RestController
@RequestMapping("artwork")
public class GoblinUserDigitalArtworkController {
    @Autowired
    GoblinRedisUtils goblinRedisUtils;
    @Autowired
    IGoblinUserDigitalArtworkService goblinUserDigitalArtworkService;

    @ApiOperationSupport(order = 1)
    @ApiOperation(value = "藏品列表")
    @ApiImplicitParams({
            @ApiImplicitParam(type = "form", required = false, dataType = "Integer", name = "pageNum", value = "索引页数"),
            @ApiImplicitParam(type = "form", required = false, dataType = "Integer", name = "pageSize", value = "显示记录数[默认5，暂定最大也为5]"),
    })
    @PostMapping("list")
    public ResponseDto<GoblinUserDigitalArtworkPageVo> list(@RequestParam(required = false, defaultValue = "1") Integer pageNum,
                                                            @RequestParam(required = false, defaultValue = "5") Integer pageSize) {
        pageNum = pageNum < 1 ? 1 : pageNum;
        pageSize = pageSize < 1 ? 5 : (pageSize > 5 ? 5 : pageSize);
        String currentUid = CurrentUtil.getCurrentUid();
        GoblinUserDigitalArtworkPageVo page = goblinUserDigitalArtworkService.page(currentUid, pageNum, pageSize);
        List<GoblinUserDigitalArtworkTransferListVo> artworkListFromTransfer = goblinUserDigitalArtworkService.getArtworkListFromTransfer(currentUid);
        return ResponseDto.success(page.setSystime(LocalDateTime.now()).setReceivedList(artworkListFromTransfer));
    }

    @ApiOperationSupport(order = 2)
    @ApiOperation(value = "藏品详情")
    @ApiImplicitParams({
            @ApiImplicitParam(type = "form", required = true, dataType = "String", name = "artworkId", value = "藏品ID"),
    })
    @PostMapping("info")
    public ResponseDto<GoblinUserDigitalArtworkInfoVo> info(@NotBlank(message = "藏品ID不能为空") @RequestParam String artworkId) {
        return ResponseDto.success(goblinUserDigitalArtworkService.info(CurrentUtil.getCurrentUid(), artworkId));
    }

    @ApiOperationSupport(order = 3)
    @ApiOperation(value = "开启盲盒")
    @ApiImplicitParams({
            @ApiImplicitParam(type = "form", required = true, dataType = "String", name = "artworkId", value = "藏品ID"),
    })
    @PostMapping("unboxing")
    public ResponseDto<GoblinUserDigitalArtworkListVo> unboxing(@NotBlank(message = "藏品ID不能为空") @RequestParam String artworkId) {
        String currentUid = CurrentUtil.getCurrentUid();
        GoblinUserDigitalArtworkVo userDigitalArtworkVo = goblinRedisUtils.getUserDigitalArtworkVo(artworkId);
        if (null == userDigitalArtworkVo || !currentUid.equals(userDigitalArtworkVo.getUid()) || userDigitalArtworkVo.getDelFlg().equals("1")) {
            return ResponseDto.failure(ErrorMapping.get("140100"));
        }
        GoblinGoodsSkuInfoVo goodsSkuInfoVo = goblinRedisUtils.getGoodsSkuInfoVo(userDigitalArtworkVo.getSkuId());
        if (null == goodsSkuInfoVo || !"1".equals(goodsSkuInfoVo.getUnbox())) {
            return ResponseDto.failure(ErrorMapping.get("140100"));
        }
        if (LocalDateTime.now().isBefore(goodsSkuInfoVo.getOpeningTime())) {
            return ResponseDto.failure(ErrorMapping.get("140101"));
        }
        if (1 == userDigitalArtworkVo.getState()) {// 盲盒已开启
            GoblinNftOrderVo goblinNftOrder = goblinRedisUtils.getGoblinNftOrder(userDigitalArtworkVo.getOrderId());
            GoblinGoodsSkuInfoVo unboxSkuInfoVo = goblinRedisUtils.getGoodsSkuInfoVo(goblinNftOrder.getBoxSkuId());
            GoblinUserDigitalArtworkListVo unboxDigitalArtworkListVo = GoblinUserDigitalArtworkListVo.getNew();
            unboxDigitalArtworkListVo.setArtworkId(userDigitalArtworkVo.getHitArtworkId());
            unboxDigitalArtworkListVo.setName(unboxSkuInfoVo.getName());
            unboxDigitalArtworkListVo.setSubtitle(unboxSkuInfoVo.getSubtitle());
            unboxDigitalArtworkListVo.setCoverPic(unboxSkuInfoVo.getSkuPic());
            return ResponseDto.success(unboxDigitalArtworkListVo);
        }

        if (!goblinRedisUtils.lockUserDigitalArtworkVoOperate(artworkId)) return ResponseDto.failure(ErrorMapping.get("140000"));
        try {
            GoblinUserDigitalArtworkListVo unboxingRstVo = null;
            try {
                switch (userDigitalArtworkVo.getSource()) {
                    case 1:
                    case 2:
                    case 31:
                        unboxingRstVo = goblinUserDigitalArtworkService.unboxingForBuyOrExchange(currentUid, userDigitalArtworkVo);
                        break;
                    case 3:
                    default:
                        log.warn("Invalid operation[UID={},artworkId={}]", currentUid, artworkId);
                }
            } catch (Exception e) {
                log.error("Ex.开启盲盒异常[artworkId={},uid={}]", artworkId, currentUid);
            }
            return null == unboxingRstVo ? ResponseDto.failure(ErrorMapping.get("140102")) : ResponseDto.success(unboxingRstVo);
        } finally {
            goblinRedisUtils.unlockUserDigitalArtworkVoOperate(artworkId);
        }
    }

    @ApiOperationSupport(order = 4)
    @ApiOperation(value = "收取藏品", notes = "空投藏品，收下后执行上链操作。<br />响应【data】值描述：藏品状态 0-生成中|1-已生成|2-生成失败")
    @ApiImplicitParams({
            @ApiImplicitParam(type = "form", required = true, dataType = "String", name = "artworkId", value = "藏品ID"),
    })
    @PostMapping("accept")
    public ResponseDto<Integer> accept(@NotBlank(message = "藏品ID不能为空") @RequestParam String artworkId) {
        String currentUid = CurrentUtil.getCurrentUid();
        GoblinUserDigitalArtworkVo userDigitalArtworkVo = goblinRedisUtils.getUserDigitalArtworkVo(artworkId);
        if (null == userDigitalArtworkVo || !currentUid.equals(userDigitalArtworkVo.getUid())
                || userDigitalArtworkVo.getDelFlg().equals("1") || userDigitalArtworkVo.getSource() != 31) {
            return ResponseDto.failure(ErrorMapping.get("140105"));
        }
        Integer acceptState = userDigitalArtworkVo.getState();
        if (5 != acceptState) return ResponseDto.success(acceptState);// 非待收取状态，直接返回藏品状态

        if (!goblinRedisUtils.lockUserDigitalArtworkVoOperate(artworkId)) return ResponseDto.failure(ErrorMapping.get("140000"));
        try {
            boolean acceptRstFlg = goblinUserDigitalArtworkService.accept(currentUid, userDigitalArtworkVo);
            return acceptRstFlg ? ResponseDto.success(0) : ResponseDto.failure(ErrorMapping.get("140002"));
        } finally {
            goblinRedisUtils.unlockUserDigitalArtworkVoOperate(artworkId);
        }
    }

    @ApiOperationSupport(order = 5)
    @ApiOperation(value = "藏品转赠", notes = "<br />响应【data】值描述：转赠状态[PENDING|SUCCESS]")
    @ApiImplicitParams({
            @ApiImplicitParam(type = "form", required = true, dataType = "String", name = "safePasswd", value = "安全密码:MD5(******)"),
            @ApiImplicitParam(type = "form", required = true, dataType = "String", name = "artworkId", value = "藏品ID"),
            @ApiImplicitParam(type = "form", required = true, dataType = "String", name = "receiver", value = "受赠人"),
    })
    @PostMapping("transfer")
    public ResponseDto<String> transfer(@NotBlank(message = "安全密码不能为空") @RequestParam String safePasswd,
                                        @NotBlank(message = "藏品ID不能为空") @RequestParam String artworkId,
                                        @NotBlank(message = "受赠人不能为空") @RequestParam String receiver) {
        String currentUid = CurrentUtil.getCurrentUid();
        GoblinUserSafeConfigDto userSafeConfigDto = goblinRedisUtils.getUserSafeConfigDto(currentUid);
        if (null == userSafeConfigDto) return ResponseDto.failure(ErrorMapping.get("140021"));// 未设置安全密码
        ResponseDto<String> validUserSafePasswdResponseDto = goblinRedisUtils.validUserSafePasswd(safePasswd, userSafeConfigDto, currentUid);
        if (!validUserSafePasswdResponseDto.isSuccess()) return validUserSafePasswdResponseDto;// 安全密码验证不通过

        String[] receiverArr;
        try {
            receiverArr = DESUtils.DES().decrypt(receiver).split(",");
        } catch (Exception e) {
            log.error("Ex.藏品转赠受赠人解析异常[artworkId={},receiver={}]", artworkId, receiver);
            return ResponseDto.failure(ErrorMapping.get("140108"));// 受赠人信息有误
        }
        if (CurrentUtil.getCurrentUid().equals(receiverArr[0])) return ResponseDto.failure(ErrorMapping.get("140109"));// 受赠人不能是本人
        GoblinUserNftAccInfoVo receiverAcctInfo = goblinRedisUtils.getOpenAccountInfo(receiverArr[0]);
        if (null == receiverAcctInfo || !"2000".equals(receiverAcctInfo.getCode())) return ResponseDto.failure(ErrorMapping.get("140110"));// 未开通数字账户

        if (!goblinRedisUtils.lockUserDigitalArtworkVoOperate(artworkId)) return ResponseDto.failure(ErrorMapping.get("140000"));
        try {
            GoblinUserDigitalArtworkVo userDigitalArtworkVo = goblinRedisUtils.getUserDigitalArtworkVo(artworkId);
            if (null == userDigitalArtworkVo || !currentUid.equals(userDigitalArtworkVo.getUid()) || userDigitalArtworkVo.getDelFlg().equals("1")) {
                return ResponseDto.failure(ErrorMapping.get("140105"));
            }
            GoblinGoodsSkuInfoVo goodsSkuInfoVo = goblinRedisUtils.getGoodsSkuInfoVo(userDigitalArtworkVo.getSkuId());
            if ("1".equals(goodsSkuInfoVo.getUnbox())) return ResponseDto.failure(ErrorMapping.get("140106"));// 盲盒
            if (1 != userDigitalArtworkVo.getState()) return ResponseDto.failure(ErrorMapping.get("140107"));// 未上链
            Map<String, Long> transferConfMap = goblinRedisUtils.getUserDigitalArtworkTransferConfMap(userDigitalArtworkVo.getSource());
            LocalDateTime transferAllowTime = DateUtil.Formatter.yyyyMMddHHmmss.parse(userDigitalArtworkVo.getTradingAt()).plusSeconds(transferConfMap.get(goodsSkuInfoVo.getRouteType()));
            if (!transferConfMap.containsKey(goodsSkuInfoVo.getRouteType())) return ResponseDto.failure(ErrorMapping.get("140111"));// 区块链路由未开放转赠
            if (transferAllowTime.isAfter(LocalDateTime.now())) return ResponseDto.failure(ErrorMapping.get("140112"));// 转赠过渡期内不可转赠
            if (StringUtils.isNotEmpty(userDigitalArtworkVo.getTransferState())) return ResponseDto.failure(ErrorMapping.get("140121"));// 转赠状态不为空，标记已转赠或转赠中
            boolean transferRstFlg = goblinUserDigitalArtworkService.transfer(userDigitalArtworkVo, goodsSkuInfoVo.getRouteType(), receiverArr);
            return transferRstFlg ? ResponseDto.success(GoblinStatusConst.TransferState.WAITING.name()) : ResponseDto.failure(ErrorMapping.get("140002"));
        } finally {
            goblinRedisUtils.unlockUserDigitalArtworkVoOperate(artworkId);
        }
    }

    @ApiOperationSupport(order = 6)
    @ApiOperation(value = "转赠领取")
    @ApiImplicitParams({
            @ApiImplicitParam(type = "form", required = true, dataType = "String", name = "artworkId", value = "藏品ID"),
    })
    @PostMapping("transfer/receive")
    public ResponseDto<String> transferReceive(@NotBlank(message = "藏品ID不能为空") @RequestParam String artworkId) {
        String currentUid = CurrentUtil.getCurrentUid();
        GoblinUserDigitalArtworkVo userDigitalArtworkVo = goblinRedisUtils.getUserDigitalArtworkVo(artworkId);
        if (null == userDigitalArtworkVo || userDigitalArtworkVo.getDelFlg().equals("1") || !currentUid.equals(userDigitalArtworkVo.getReceiverUid())) {
            return ResponseDto.failure(ErrorMapping.get("140105"));// 藏品不存在
        }
        if (userDigitalArtworkVo.getTransferAt().plusDays(1).isBefore(LocalDateTime.now())) {
            return ResponseDto.failure(ErrorMapping.get("140118"));// 已过转赠领取有效期
        }
        if (!GoblinStatusConst.TransferState.WAITING.name().equals(userDigitalArtworkVo.getTransferState())) {
            return ResponseDto.failure(ErrorMapping.get(null == userDigitalArtworkVo.getTransferState() ? "140120" : "140119"));// 藏品已领取或已退还
        }
        if (!goblinRedisUtils.lockUserDigitalArtworkVoOperate(artworkId)) return ResponseDto.failure(ErrorMapping.get("140000"));
        try {
            boolean transferReceiveRstFlg = goblinUserDigitalArtworkService.transferConfirmReceive(artworkId);
            return transferReceiveRstFlg ? ResponseDto.success() : ResponseDto.failure(ErrorMapping.get("140002"));
        } finally {
            goblinRedisUtils.unlockUserDigitalArtworkVoOperate(artworkId);
        }
    }

    @ApiOperationSupport(order = 6)
    @ApiOperation(value = "转赠退还")
    @ApiImplicitParams({
            @ApiImplicitParam(type = "form", required = true, dataType = "String", name = "artworkId", value = "藏品ID"),
    })
    @PostMapping("transfer/return")
    public ResponseDto<String> transferReturn(@NotBlank(message = "藏品ID不能为空") @RequestParam String artworkId) {
        String currentUid = CurrentUtil.getCurrentUid();
        GoblinUserDigitalArtworkVo userDigitalArtworkVo = goblinRedisUtils.getUserDigitalArtworkVo(artworkId);
        if (null == userDigitalArtworkVo || userDigitalArtworkVo.getDelFlg().equals("1") || !currentUid.equals(userDigitalArtworkVo.getReceiverUid())) {
            return ResponseDto.failure(ErrorMapping.get("140105"));// 藏品不存在
        }
        if (!GoblinStatusConst.TransferState.WAITING.name().equals(userDigitalArtworkVo.getTransferState())) {
            return ResponseDto.failure(ErrorMapping.get(null == userDigitalArtworkVo.getTransferState() ? "140120" : "140119"));// 藏品已领取
        }
        if (!goblinRedisUtils.lockUserDigitalArtworkVoOperate(artworkId)) return ResponseDto.failure(ErrorMapping.get("140000"));
        try {
            boolean transferReceiveRstFlg = goblinUserDigitalArtworkService.transferConfirmReturn(artworkId);
            return transferReceiveRstFlg ? ResponseDto.success() : ResponseDto.failure(ErrorMapping.get("140002"));
        } finally {
            goblinRedisUtils.unlockUserDigitalArtworkVoOperate(artworkId);
        }
    }
}
