package com.liquidnet.service.goblin.controller;

import com.liquidnet.commons.lang.util.CurrentUtil;
import com.liquidnet.service.base.ErrorMapping;
import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.goblin.dto.vo.GoblinStoreCouponVo;
import com.liquidnet.service.goblin.dto.vo.GoblinUseResultVo;
import com.liquidnet.service.goblin.dto.vo.GoblinUserCouponVo;
import com.liquidnet.service.goblin.param.*;
import com.liquidnet.service.goblin.service.GoblinCouponService;
import com.liquidnet.service.goblin.util.GoblinRedisUtils;
import com.liquidnet.service.goblin.util.ObjectUtil;
import io.swagger.annotations.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Slf4j
@Api(tags = "店铺券")
@RestController
@RequestMapping("/store/coupon")
public class GoblinCouponController {
    @Autowired
    GoblinRedisUtils goblinRedisUtils;
    @Autowired
    GoblinCouponService goblinCouponService;

    @PostMapping("type")
    @ApiOperation("商品可参与券类型")
    @ApiResponse(code = 200, message = "接口返回对象参数")
    @ApiImplicitParams({
            @ApiImplicitParam(type = "form", required = true, dataType = "String", name = "spuId", value = "spuId"),
            @ApiImplicitParam(type = "form", required = true, dataType = "String", name = "storeId", value = "店铺id"),
    })
    public ResponseDto<ArrayList<String>> getSpuType(@RequestParam("spuId") @Valid String spuId,
                                                     @RequestParam("storeId") @Valid String storeId) {
        return ResponseDto.success(goblinCouponService.getSpuType(spuId, storeId));
    }

    @PostMapping("type/list")
    @ApiOperation("券列表[根据类型]")
    @ApiResponse(code = 200, message = "接口返回对象参数")
    @ApiImplicitParams({
            @ApiImplicitParam(type = "form", required = true, dataType = "String", name = "spuId", value = "spuId"),
            @ApiImplicitParam(type = "form", required = true, dataType = "String", name = "storeId", value = "店铺id"),
            @ApiImplicitParam(type = "form", required = true, dataType = "String", name = "type", value = "券类型[0-全部|1-代金券|2-折扣券|3-满减券]"),
    })
    public ResponseDto<ArrayList<GoblinStoreCouponVo>> getSpuByType(@RequestParam("spuId") @Valid String spuId,
                                                                    @RequestParam("storeId") @Valid String storeId,
                                                                    @RequestParam("type") @Valid String type) {
        ArrayList<GoblinStoreCouponVo> storeCouponVos = goblinCouponService.getSpuByType(spuId, storeId, type);
        if (!CollectionUtils.isEmpty(storeCouponVos)) {
            String currentUid = CurrentUtil.getCurrentUid();
            if (StringUtils.isNotEmpty(currentUid)) {
                List<GoblinUserCouponVo> userCouponVos = goblinRedisUtils.getUserCouponVos(currentUid);
                if (!CollectionUtils.isEmpty(userCouponVos))
                    for (GoblinStoreCouponVo storeCouponVo : storeCouponVos)
                        for (GoblinUserCouponVo userCouponVo : userCouponVos)
                            if (storeCouponVo.getStoreCouponId().equals(userCouponVo.getStoreCouponId()))
                                storeCouponVo.setReceiveCount(storeCouponVo.getReceiveCount() + 1);
            }
        }
        return ResponseDto.success(storeCouponVos);
    }

    @PostMapping("receive")
    @ApiOperation("领取券")
    @ApiImplicitParams({
            @ApiImplicitParam(type = "form", required = true, dataType = "String", name = "storeCouponId", value = "平台券ID"),
//            @ApiImplicitParam(type = "form", required = true, dataType = "Integer", name = "number", value = "数量"),
    })
    public ResponseDto<Boolean> receive(@NotBlank(message = "平台券ID不能为空") @RequestParam("storeCouponId") String storeCouponId) {
//    public ResponseDto<Boolean> checkOrderResult(@RequestParam("storeCouponId") @Valid String storeCouponId,
//                                                 @RequestParam("number") @Valid Integer number) {
        String uid = CurrentUtil.getCurrentUid();
        GoblinStoreCouponVo storeCouponVo = goblinRedisUtils.getStoreCouponVo(storeCouponId);
        if (null == storeCouponVo) {
            log.warn("商城:用户领取优惠券:优惠券不存在:[uid={},storeCouponId={}]", uid, storeCouponId);
            return ResponseDto.failure(ErrorMapping.get("140050"));
        }
        if (!storeCouponVo.getState().equals("1")) {
            return ResponseDto.failure(ErrorMapping.get("140051"));
        }
        List<GoblinUserCouponVo> userCouponVos = goblinRedisUtils.getUserCouponVos(uid);
        if (!CollectionUtils.isEmpty(userCouponVos)) {
            ArrayList<GoblinUserCouponVo> userCouponVosTmp = ObjectUtil.getGoblinUserCouponVo();
            userCouponVosTmp.addAll(userCouponVos);
            userCouponVosTmp.removeIf(vo -> vo.getStoreCouponId().equals(storeCouponId));
            if ((userCouponVos.size() - userCouponVosTmp.size()) >= storeCouponVo.getReceiveLimit()) {
                return ResponseDto.failure(ErrorMapping.get("140052"));
            }
        }
        if (storeCouponVo.getStock().equals(0) || goblinRedisUtils.getStoreCouponStock(storeCouponId) > 0) {
            Boolean resultFlg = goblinCouponService.receiveCoupon(uid, userCouponVos, storeCouponVo);
            return resultFlg ? ResponseDto.success() : ResponseDto.failure();
        }
        return ResponseDto.failure(ErrorMapping.get("140053"));
    }

    @PostMapping("fetched")
    @ApiOperation(value = "POS机代领券", notes = "返回当前领取的可用券信息")
    @ApiImplicitParams({
            @ApiImplicitParam(type = "form", required = true, dataType = "String", name = "storeId", value = "店铺ID"),
            @ApiImplicitParam(type = "form", required = true, dataType = "String", name = "storeCouponId", value = "平台券ID"),
            @ApiImplicitParam(type = "form", required = true, dataType = "String", name = "uid", value = "UID"),
    })
    public ResponseDto<GoblinUserCouponVo> fetched(@NotBlank(message = "店铺ID不能为空") @RequestParam("storeId") String storeId,
                                                   @NotBlank(message = "平台券ID不能为空") @RequestParam("storeCouponId") String storeCouponId,
                                                   @NotBlank(message = "UID不能为空") @RequestParam("uid") String uid) {
//        if (!goblinRedisUtils.hasStoreId(CurrentUtil.getCurrentUid(), storeId)) {
//            return ResponseDto.failure(ErrorMapping.get("149002"));
//        }
        // TODO: 2022/3/5 ==zhanggb.UID校验真实性

        GoblinStoreCouponVo storeCouponVo = goblinRedisUtils.getStoreCouponVo(storeCouponId);
        if (null == storeCouponVo) {
            log.warn("商城:用户领取优惠券:优惠券不存在:[uid={},storeCouponId={}]", uid, storeCouponId);
            return ResponseDto.failure(ErrorMapping.get("140050"));
        }
        if (null != storeId && !storeId.equals(storeCouponVo.getStoreId())) {
            log.warn("商城:POS机代领优惠券:非法请求，非本店铺优惠券:[uid={},storeCouponId={}]", uid, storeCouponId);
            return ResponseDto.failure(ErrorMapping.get("140050"));
        }
        if (!storeCouponVo.getState().equals("1")) {
            return ResponseDto.failure(ErrorMapping.get("140051"));
        }
        List<GoblinUserCouponVo> userCouponVos = goblinRedisUtils.getUserCouponVos(uid);
        if (!CollectionUtils.isEmpty(userCouponVos)) {
            List<GoblinUserCouponVo> userCouponVoList = userCouponVos.stream().filter(vo -> vo.getStoreCouponId().equals(storeCouponId)).collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(userCouponVoList) && userCouponVoList.size() >= storeCouponVo.getReceiveLimit()) {
                // 用户已领取该券且领取数量已达上限时，根据已领取券的状态判断返回（如果已使用提示用，未使用则正常返回）
                Optional<GoblinUserCouponVo> userCouponVoOptional = userCouponVoList.stream().filter(vo -> vo.getState().equals(1)).findAny();
//                return userCouponVoOptional.map(ResponseDto::success).orElseGet(() -> ResponseDto.failure(ErrorMapping.get("140054")));
                if (userCouponVoOptional.isPresent()) {
                    GoblinUserCouponVo userCouponVo = userCouponVoOptional.get();
                    if (StringUtils.equals("1", userCouponVo.getUseScope())) {
                        userCouponVo.setSpuIds(goblinRedisUtils.getStoreCouponSpuIds(storeCouponId));
                    }
                    return ResponseDto.success(userCouponVo);
                } else {
                    return ResponseDto.failure(ErrorMapping.get("140054"));
                }
            }
        }
        if (storeCouponVo.getStock().equals(0) || goblinRedisUtils.getStoreCouponStock(storeCouponId) > 0) {
            if (goblinCouponService.receiveCoupon(uid, userCouponVos, storeCouponVo)) {
                List<GoblinUserCouponVo> userCouponVoList = userCouponVos.stream()
                        .filter(vo -> vo.getStoreCouponId().equals(storeCouponId) && vo.getState().equals(1)).collect(Collectors.toList());
//                return ResponseDto.success(userCouponVoList.get(0));
                GoblinUserCouponVo userCouponVo = userCouponVoList.get(0);
                if (StringUtils.equals("1", userCouponVo.getUseScope())) {
                    userCouponVo.setSpuIds(goblinRedisUtils.getStoreCouponSpuIds(storeCouponId));
                }
                return ResponseDto.success(userCouponVo);
            }
            return ResponseDto.failure(ErrorMapping.get("140053"));
        }
        return ResponseDto.failure(ErrorMapping.get("140053"));
    }

    @PostMapping("my/list")
    @ApiOperation("我的券券列表[根据类型]")
    @ApiResponse(code = 200, message = "接口返回对象参数")
    @ApiImplicitParams({
            @ApiImplicitParam(type = "form", required = true, dataType = "String", name = "type", value = "类型 1可用 2过期/已使用"),
    })
    public ResponseDto<List<GoblinUserCouponVo>> getList(@RequestParam("type") @Valid String type) {
        return ResponseDto.success(goblinCouponService.getList(type));
    }

    @PostMapping("can/use")
    @ApiOperation("是否可用券[计算价格最高并返回vo]")
    @ApiResponse(code = 200, message = "接口返回对象参数")
    @ApiImplicitParams({
            @ApiImplicitParam(type = "form", required = true, dataType = "Number", name = "totalPrice", value = "spuId"),
            @ApiImplicitParam(type = "form", required = true, dataType = "String", name = "spuId", value = "逗号隔开"),
            @ApiImplicitParam(type = "form", required = true, dataType = "String", name = "uid", value = "用户id"),
            @ApiImplicitParam(type = "form", required = true, dataType = "String", name = "storeId", value = "店铺id"),
    })
    public ResponseDto<GoblinUserCouponVo> canUse(@RequestParam("totalPrice") @Valid BigDecimal totalPrice,
                                                  @RequestParam("spuId") @Valid String spuId,
                                                  @RequestParam("storeId") @Valid String storeId,
                                                  @RequestParam(value = "uid", required = false) @Valid String uid) {
        if (uid == null) {
            uid = CurrentUtil.getCurrentUid();
        }
        return ResponseDto.success(goblinCouponService.canUse(totalPrice, spuId, uid, storeId));
    }

    @PostMapping("useList")
    @ApiOperation("可用券列表[不判断部分商品]")
    @ApiResponse(code = 200, message = "接口返回对象参数")
    @ApiImplicitParams({
            @ApiImplicitParam(type = "form", required = true, dataType = "Number", name = "totalPrice", value = "应付价格"),
            @ApiImplicitParam(type = "form", required = true, dataType = "String", name = "spuId", value = "逗号隔开"),
            @ApiImplicitParam(type = "form", required = false, dataType = "String", name = "uid", value = "用户id")
    })
    public ResponseDto<List<GoblinUserCouponVo>> useList(@RequestParam("totalPrice") @Valid BigDecimal totalPrice,
                                                         @RequestParam("spuId") @Valid String spuId,
                                                         @RequestParam(value = "uid", required = false) String uid) {
        if (uid == null) {
            uid = CurrentUtil.getCurrentUid();
        }
        return ResponseDto.success(goblinCouponService.useList(totalPrice, spuId, uid));
    }

    @PostMapping("useList2")
    @ApiOperation("可用券列表[判断部分商品]")
    @ApiResponse(code = 200, message = "接口返回对象参数")
    public ResponseDto<List<GoblinUserCouponVo>> useList2(@RequestBody CouponCanUseParam param) {
        if (param.getUid() == null) {
            param.setUid(CurrentUtil.getCurrentUid());
        }
        return ResponseDto.success(goblinCouponService.useList2(param));
    }

    @PostMapping("useList3")
    @ApiOperation("可用券列表[返回商品下所有券]")
    @ApiResponse(code = 200, message = "接口返回对象参数")
    public ResponseDto<List<GoblinUserCouponVo>> useList3(@RequestBody CouponCanUseAllParam param) {
        if (param.getUid() == null) {
            param.setUid(CurrentUtil.getCurrentUid());
        }
        return ResponseDto.success(goblinCouponService.useList3(param));
    }

//    @PostMapping("useCoupon")
//    @ApiOperation("用券")
//    @ApiResponse(code = 200, message = "接口返回对象参数")
//    @ApiImplicitParams({
//            @ApiImplicitParam(type = "form", required = true, dataType = "String", name = "ucouponId", value = "券id"),
//            @ApiImplicitParam(type = "form", required = true, dataType = "String", name = "content", value = "消费内容"),
//            @ApiImplicitParam(type = "form", required = true, dataType = "Number", name = "totalPrice", value = "总价格"),
//            @ApiImplicitParam(type = "form", required = true, dataType = "String", name = "spuId", value = "spuId逗号隔开"),
//            @ApiImplicitParam(type = "form", required = true, dataType = "String", name = "uid", value = "uid"),
//    })
//    public ResponseDto<GoblinUseResultVo> checkOrderResult(@RequestParam("ucouponId") @Valid String ucouponId,
//                                                           @RequestParam("content") @Valid String content,
//                                                           @RequestParam("totalPrice") @Valid BigDecimal totalPrice,
//                                                           @RequestParam("spuId") @Valid String spuId,
//                                                           @RequestParam("uid") @Valid String uid) {
//        return ResponseDto.success(goblinCouponService.useCoupon(ucouponId, content, totalPrice, spuId, uid));
//    }

    @PostMapping("backCoupon")
    @ApiOperation("退券")
    @ApiResponse(code = 200, message = "接口返回对象参数")
    public ResponseDto<Boolean> checkOrderResult(@RequestBody @Valid List<BackCouponParam> backCouponParam) {
        if (backCouponParam.size() > 100) {
            return ResponseDto.failure("数据量不得大于100");
        }
        return ResponseDto.success(goblinCouponService.backCoupon(backCouponParam));
    }

    @PostMapping("helpUseCoupon")
    @ApiOperation("帮助用券")
    @ApiResponse(code = 200, message = "接口返回对象参数")
    public ResponseDto<CouponHelpUseVo> helpUseCoupon(@RequestBody CouponHelpUseParam param) {
        if (param.getUid() == null || param.getUid().equals("")) {
            param.setUid(CurrentUtil.getCurrentUid());
        }
        CouponHelpUseVo vo = goblinCouponService.helpUseCoupon(param);
        if(vo==null){
            return ResponseDto.failure("券不存在");
        }
        return ResponseDto.success(vo);
    }
}
