package com.liquidnet.service.goblin.controller.manage;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import com.liquidnet.common.exception.constant.ErrorCode;
import com.liquidnet.commons.lang.util.CurrentUtil;
import com.liquidnet.commons.lang.util.DateUtil;
import com.liquidnet.commons.lang.util.JsonUtils;
import com.liquidnet.service.base.ErrorMapping;
import com.liquidnet.service.base.PagedResult;
import com.liquidnet.service.base.ResponseDto;
import com.liquidnet.service.goblin.dto.GoblinStoreMgtCouponListVoExcel;
import com.liquidnet.service.goblin.dto.GoblinStoreMgtGoodsListVoExcel;
import com.liquidnet.service.goblin.dto.manage.GoblinStoreMgtCouponActionParam;
import com.liquidnet.service.goblin.dto.manage.GoblinStoreMgtCouponAddParam;
import com.liquidnet.service.goblin.dto.manage.GoblinStoreMgtCouponFilterParam;
import com.liquidnet.service.goblin.dto.manage.vo.GoblinStoreMgtCouponInfoVo;
import com.liquidnet.service.goblin.dto.manage.vo.GoblinStoreMgtCouponListVo;
import com.liquidnet.service.goblin.dto.vo.GoblinGoodsInfoVo;
import com.liquidnet.service.goblin.dto.vo.GoblinStoreCouponBasicVo;
import com.liquidnet.service.goblin.dto.vo.GoblinStoreCouponVo;
import com.liquidnet.service.goblin.service.manage.IGoblinstoreMgtCouponService;
import com.liquidnet.service.goblin.util.GoblinMongoUtils;
import com.liquidnet.service.goblin.util.GoblinRedisUtils;
import com.liquidnet.service.goblin.util.ObjectUtil;
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.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.Iterator;
import java.util.List;

@ApiSupport(order = 149006)
@Api(tags = "商铺活动:优惠券管理")
@Slf4j
@Validated
@RestController
@RequestMapping("store/mgt/coupon")
public class GoblinStoreMgtCouponController {
    @Autowired
    GoblinRedisUtils goblinRedisUtils;
    @Autowired
    GoblinMongoUtils goblinMongoUtils;
    @Autowired
    IGoblinstoreMgtCouponService goblinstoreMgtCouponService;

    @ApiOperationSupport(order = 1)
    @ApiOperation(value = "优惠券列表")
    @PostMapping("list")
    public ResponseDto<PagedResult<GoblinStoreMgtCouponListVo>> list(@Valid @RequestBody GoblinStoreMgtCouponFilterParam mgtCouponFilterParam) {
        String currentUid = CurrentUtil.getCurrentUid();
        if (!goblinRedisUtils.hasStoreId(currentUid, mgtCouponFilterParam.getStoreId())) {
            return ResponseDto.success();
        }
        if (log.isDebugEnabled()) {
            log.debug("商铺活动:优惠券列表:[mgtCouponFilterParam={}]", JsonUtils.toJson(mgtCouponFilterParam));
        }
        return ResponseDto.success(goblinstoreMgtCouponService.couponList(mgtCouponFilterParam));
    }

    @ApiOperationSupport(order = 2)
    @ApiOperation(value = "优惠券导出")
    @PostMapping("export")
    public void export(@Valid @RequestBody GoblinStoreMgtCouponFilterParam mgtCouponFilterParam, HttpServletResponse response) {
        String currentUid = CurrentUtil.getCurrentUid();
        ServletOutputStream servletOutputStream = null;
        try {
            if (!goblinRedisUtils.hasStoreId(currentUid, mgtCouponFilterParam.getStoreId())) {
                log.warn("商铺活动:优惠券导出:无权操作该店铺，请核实[UID={},GoblinStoreMgtCouponFilterParam={}]", currentUid, JsonUtils.toJson(mgtCouponFilterParam));
                return;
            }
            if (log.isDebugEnabled()) {
                log.debug("商铺活动:优惠券导出:[mgtCouponFilterParam={}]", JsonUtils.toJson(mgtCouponFilterParam));
            }
            response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=".concat(DateUtil.Formatter.ddHHmmssTrim.format(LocalDateTime.now()))
                    .concat(new String(("优惠券数据").getBytes("gb2312"), StandardCharsets.ISO_8859_1)).concat(ExcelTypeEnum.XLSX.getValue()));
            response.setContentType(MediaType.MULTIPART_FORM_DATA_VALUE);
            response.setCharacterEncoding(StandardCharsets.UTF_8.name());
            servletOutputStream = response.getOutputStream();

            mgtCouponFilterParam.setPageNum(1);
            mgtCouponFilterParam.setPageSize(5000);
            PagedResult<GoblinStoreMgtCouponListVo> pagedResult = goblinstoreMgtCouponService.couponList(mgtCouponFilterParam);
            List<GoblinStoreMgtCouponListVo> rows = pagedResult.getList();
            List<GoblinStoreMgtCouponListVoExcel> rowsToExcels = ObjectUtil.getGoblinStoreMgtCouponListVoExcelArrayList();
            rows.forEach(row -> rowsToExcels.add(GoblinStoreMgtCouponListVoExcel.getNew().copy(row)));

            EasyExcel.write(servletOutputStream, GoblinStoreMgtGoodsListVoExcel.class).sheet("优惠券数据").doWrite(rowsToExcels);
        } catch (IOException e) {
            log.error("商品管理:SPU导出:异常[UID={},ex.msg={}]", currentUid, e.getLocalizedMessage());
        } finally {
            if (null != servletOutputStream) {
                try {
                    servletOutputStream.close();
                } catch (Exception ignored) {
                }
            }
        }
    }

    @ApiOperationSupport(order = 3)
    @ApiOperation(value = "优惠券管理")
    @PostMapping("action")
    public ResponseDto<Object> action(@Valid @RequestBody GoblinStoreMgtCouponActionParam mgtCouponActionParam) {
        String currentUid = CurrentUtil.getCurrentUid(), storeId = mgtCouponActionParam.getStoreId();
        if (!goblinRedisUtils.hasStoreId(currentUid, storeId)) {
            return ResponseDto.failure(ErrorMapping.get("149002"));
        }
        List<String> storeCouponIdList = mgtCouponActionParam.getStoreCouponIdList();
        if (CollectionUtils.isEmpty(storeCouponIdList)) {
            return ResponseDto.failure(ErrorCode.HTTP_PARAM_ERROR.getCode(), "请选择优惠券操作");
        }
        if (log.isDebugEnabled()) {
            log.debug("商铺活动:优惠券管理:[GoblinStoreMgtCouponActionParam={}]", JsonUtils.toJson(mgtCouponActionParam));
        }

        switch (mgtCouponActionParam.getAction()) {//ENABLED|DISABLED|REMOVE
            case "ENABLED":
                for (String storeCouponId : storeCouponIdList) {
                    GoblinStoreCouponVo storeCouponVo = goblinRedisUtils.getStoreCouponVo(storeCouponId);
                    if (null == storeCouponVo) {
                        return ResponseDto.failure(ErrorCode.HTTP_PARAM_ERROR.getCode(), "参数有误:优惠券不存在");
                    }
                    if (!storeCouponVo.getStoreId().equals(storeId)) {
                        log.warn("商铺活动:优惠券管理:启用警告:非本店铺活动，无权操作[UID={},storeCouponId={}]", currentUid, storeCouponId);
                        return ResponseDto.failure(ErrorCode.HTTP_PARAM_ERROR.getCode(), "非本店铺活动，无权操作");
                    }
                    if (!storeCouponVo.getState().equals("3")) {// 只针对停用的优惠券
                        return ResponseDto.failure(ErrorCode.HTTP_PARAM_ERROR.getCode(), "只限已停用状态执行该操作");
                    }
                }
                goblinstoreMgtCouponService.couponActivityProcessing(mgtCouponActionParam, currentUid);
                break;
            case "DISABLED":
                for (String storeCouponId : storeCouponIdList) {
                    GoblinStoreCouponVo storeCouponVo = goblinRedisUtils.getStoreCouponVo(storeCouponId);
                    if (null == storeCouponVo) {
                        return ResponseDto.failure(ErrorCode.HTTP_PARAM_ERROR.getCode(), "参数有误:优惠券不存在");
                    }
                    if (!storeCouponVo.getStoreId().equals(storeId)) {
                        log.warn("商铺活动:优惠券管理:停用警告:非本店铺活动，无权操作[UID={},storeCouponId={}]", currentUid, storeCouponId);
                        return ResponseDto.failure(ErrorCode.HTTP_PARAM_ERROR.getCode(), "非本店铺活动，无权操作");
                    }
//                    if (storeCouponVo.getState().equals("1")) {// 该优惠券活动中
//                        return ResponseDto.failure(ErrorCode.HTTP_PARAM_ERROR.getCode(), "该优惠券活动中不可停用");
//                    }
                    if (storeCouponVo.getState().equals("3")) {// 该优惠券已停用
                        return ResponseDto.failure(ErrorCode.HTTP_PARAM_ERROR.getCode(), "该优惠券已停用");
                    }
                }
                goblinstoreMgtCouponService.couponActivityProcessing(mgtCouponActionParam, currentUid);
                break;
            case "REMOVE":
                for (String storeCouponId : storeCouponIdList) {
                    GoblinStoreCouponVo storeCouponVo = goblinRedisUtils.getStoreCouponVo(storeCouponId);
                    if (null == storeCouponVo) {
                        return ResponseDto.failure(ErrorCode.HTTP_PARAM_ERROR.getCode(), "参数有误:优惠券不存在");
                    }
                    if (!storeCouponVo.getStoreId().equals(storeId)) {
                        log.warn("商铺活动:优惠券管理:删除警告:非本店铺活动，无权操作[UID={},storeCouponId={}]", currentUid, storeCouponId);
                        return ResponseDto.failure(ErrorCode.HTTP_PARAM_ERROR.getCode(), "非本店铺活动，无权操作");
                    }
                    if (storeCouponVo.getState().equals("1")) {// 活动中不可删除
                        return ResponseDto.failure(ErrorCode.HTTP_PARAM_ERROR.getCode(), "活动中不允许删除，请停用或活动结束后操作");
                    }
                }
                goblinstoreMgtCouponService.couponRemove(mgtCouponActionParam, currentUid);
                break;
            default:
                log.warn("商铺活动:优惠券管理:Invalid operation[UID={},storeMgtGoodsActionParam={}]", currentUid, JsonUtils.toJson(mgtCouponActionParam));
                return ResponseDto.failure(ErrorMapping.get("149001"));
        }
        return ResponseDto.success();
    }

    @ApiOperationSupport(order = 4)
    @ApiOperation(value = "新增优惠券")
    @PutMapping("add")
    public ResponseDto<Object> add(@Valid @RequestBody GoblinStoreMgtCouponAddParam mgtCouponAddParam) {
        String currentUid = CurrentUtil.getCurrentUid(), storeId = mgtCouponAddParam.getStoreId();
        if (!goblinRedisUtils.hasStoreId(currentUid, storeId)) {
            return ResponseDto.failure(ErrorMapping.get("149002"));
        }
        if (log.isDebugEnabled()) {
            log.debug("商铺活动:新增优惠券:[mgtCouponAddParam={}]", JsonUtils.toJson(mgtCouponAddParam));
        }

        GoblinStoreCouponBasicVo storeCouponBasicVo = mgtCouponAddParam.initStoreCouponBasicInfo();
        switch (storeCouponBasicVo.getType()) {
            case "1":// 代金
                if (null == mgtCouponAddParam.getValFace()) {
                    return ResponseDto.failure(ErrorCode.HTTP_PARAM_ERROR.getCode(), "减免金额不能为空");
                }
                storeCouponBasicVo.setValFace(mgtCouponAddParam.getValFace());
                storeCouponBasicVo.setDeduction(mgtCouponAddParam.getValFace());
                break;
            case "2":// 折扣
                if (null == mgtCouponAddParam.getDiscount()) {
                    return ResponseDto.failure(ErrorCode.HTTP_PARAM_ERROR.getCode(), "折扣额度不能为空");
                }
                storeCouponBasicVo.setDiscount(mgtCouponAddParam.getDiscount());
                BigDecimal deduction = mgtCouponAddParam.getDeduction();
                storeCouponBasicVo.setDeduction(null == deduction ? BigDecimal.ZERO : deduction);
                break;
            case "3":// 满减
                if (null == mgtCouponAddParam.getValOver() || null == mgtCouponAddParam.getValMinus()) {
                    return ResponseDto.failure(ErrorCode.HTTP_PARAM_ERROR.getCode(), "满减额度不能为空");
                }
                storeCouponBasicVo.setTriggers(mgtCouponAddParam.getValOver());
                storeCouponBasicVo.setValOver(mgtCouponAddParam.getValOver());
                storeCouponBasicVo.setValMinus(mgtCouponAddParam.getValMinus());
                storeCouponBasicVo.setDeduction(mgtCouponAddParam.getValMinus());
                break;
        }
        LocalDateTime startTime = storeCouponBasicVo.getStartTime(), endTime = storeCouponBasicVo.getEndTime();
        if (startTime.isEqual(endTime) || startTime.isAfter(endTime) || endTime.isBefore(LocalDateTime.now())) {
            return ResponseDto.failure(ErrorCode.HTTP_PARAM_ERROR.getCode(), "活动开始、结束时间无效");
        }

        List<String> spuIdList = storeCouponBasicVo.getSpuIdList();
        if (storeCouponBasicVo.getUseScope().equals("1") && !CollectionUtils.isEmpty(spuIdList)) {
            Iterator<String> iterator = spuIdList.iterator();
            while (iterator.hasNext()) {
                GoblinGoodsInfoVo goodsInfoVo = goblinRedisUtils.getGoodsInfoVo(iterator.next());
                if (null == goodsInfoVo || !goodsInfoVo.getDelFlg().equals("0")) {
                    iterator.remove();
                }
            }
//            spuIdList.removeIf(spuId -> null == goblinRedisUtils.getGoodsInfoVo(spuId));
            storeCouponBasicVo.setSpuIdList(spuIdList);
        }

        goblinstoreMgtCouponService.couponAdd(currentUid, storeCouponBasicVo);

        return ResponseDto.success(storeCouponBasicVo.getStoreCouponId());
    }

    @ApiOperationSupport(order = 5)
    @ApiOperation(value = "优惠券详情")
    @ApiImplicitParams({
            @ApiImplicitParam(type = "form", required = true, dataType = "String", name = "storeId", value = "店铺ID"),
            @ApiImplicitParam(type = "form", required = true, dataType = "String", name = "storeCouponId", value = "优惠券ID"),
    })
    @GetMapping("info")
    public ResponseDto<GoblinStoreMgtCouponInfoVo> info(@NotBlank(message = "店铺ID不能为空") @RequestParam String storeId,
                                                        @NotBlank(message = "优惠券ID不能为空") @RequestParam String storeCouponId) {
        if (!goblinRedisUtils.hasStoreId(CurrentUtil.getCurrentUid(), storeId)) {
            return ResponseDto.failure(ErrorMapping.get("149002"));
        }
        if (log.isDebugEnabled()) {
            log.debug("商铺活动:优惠券详情:[storeId={},storeCouponId={}]", storeId, storeCouponId);
        }
        return ResponseDto.success(goblinstoreMgtCouponService.couponInfo(storeId, storeCouponId));
    }

    @ApiOperationSupport(order = 6)
    @ApiOperation(value = "优惠券编辑", notes = "只修改基本信息，不包含发放设置修改")
    @PostMapping("edit")
    public ResponseDto<Object> edit(@Valid @RequestBody GoblinStoreMgtCouponAddParam mgtCouponEditParam) {
        String currentUid = CurrentUtil.getCurrentUid(), storeId = mgtCouponEditParam.getStoreId();
        if (!goblinRedisUtils.hasStoreId(currentUid, storeId)) {
            return ResponseDto.failure(ErrorMapping.get("149002"));
        }
        String storeCouponId = mgtCouponEditParam.getStoreCouponId();
        GoblinStoreCouponVo storeCouponVo;
        if (StringUtils.isBlank(storeCouponId)
                || null == (storeCouponVo = goblinRedisUtils.getStoreCouponVo(storeCouponId))
                || !storeId.equals(storeCouponVo.getStoreId())) {
            return ResponseDto.failure(ErrorCode.HTTP_PARAM_ERROR.getCode(), "参数无效:优惠券ID");
        }
        if (!storeCouponVo.getType().equals(mgtCouponEditParam.getType())) {
            return ResponseDto.failure(ErrorCode.HTTP_PARAM_ERROR.getCode(), "卡券类型不可变更");
        }
        if (log.isDebugEnabled()) {
            log.debug("商铺活动:优惠券编辑:[mgtCouponEditParam={}]", JsonUtils.toJson(mgtCouponEditParam));
        }
        GoblinStoreCouponBasicVo storeCouponBasicVo = mgtCouponEditParam.initStoreCouponBasicInfo();

        LocalDateTime startTime = storeCouponBasicVo.getStartTime(), endTime = storeCouponBasicVo.getEndTime();
        if (startTime.isEqual(endTime) || startTime.isAfter(endTime) || endTime.isBefore(LocalDateTime.now())) {
            return ResponseDto.failure(ErrorCode.HTTP_PARAM_ERROR.getCode(), "活动开始、结束时间无效");
        }
        LocalDateTime befStartTime = storeCouponVo.getStartTime();
        if (befStartTime.minusMinutes(10).isAfter(storeCouponBasicVo.getStartTime())) {
            storeCouponBasicVo.setStartTime(startTime);
        }
        storeCouponBasicVo.setType(storeCouponVo.getType());
        storeCouponBasicVo.setState(storeCouponVo.getState());
        storeCouponBasicVo.setStock(storeCouponVo.getStock());// 这里库存不允许编辑修改，只可在列表页编辑'增减库存'
        switch (storeCouponBasicVo.getType()) {
            case "1":// 代金
                if (null == mgtCouponEditParam.getValFace()) {
                    return ResponseDto.failure(ErrorCode.HTTP_PARAM_ERROR.getCode(), "减免金额不能为空");
                }
                storeCouponBasicVo.setValFace(mgtCouponEditParam.getValFace());
                storeCouponBasicVo.setDeduction(mgtCouponEditParam.getValFace());
                break;
            case "2":// 折扣
                if (null == mgtCouponEditParam.getDiscount()) {
                    return ResponseDto.failure(ErrorCode.HTTP_PARAM_ERROR.getCode(), "折扣额度不能为空");
                }
                storeCouponBasicVo.setDiscount(mgtCouponEditParam.getDiscount());
                BigDecimal deduction = mgtCouponEditParam.getDeduction();
                storeCouponBasicVo.setDeduction(null == deduction ? BigDecimal.ZERO : deduction);
                break;
            case "3":// 满减
                if (null == mgtCouponEditParam.getValOver() || null == mgtCouponEditParam.getValMinus()) {
                    return ResponseDto.failure(ErrorCode.HTTP_PARAM_ERROR.getCode(), "满减额度不能为空");
                }
                storeCouponBasicVo.setTriggers(mgtCouponEditParam.getValOver());
                storeCouponBasicVo.setValOver(mgtCouponEditParam.getValOver());
                storeCouponBasicVo.setValMinus(mgtCouponEditParam.getValMinus());
                storeCouponBasicVo.setDeduction(mgtCouponEditParam.getValMinus());
                break;
        }
        storeCouponBasicVo.setStoreCouponId(storeCouponId);
        storeCouponBasicVo.setStoreCouponNo(storeCouponVo.getStoreCouponNo());

        List<String> spuIdList = storeCouponBasicVo.getSpuIdList();
        if (storeCouponBasicVo.getUseScope().equals("1") && null != spuIdList) {
            Iterator<String> iterator = spuIdList.iterator();
            while (iterator.hasNext()) {
                GoblinGoodsInfoVo goodsInfoVo = goblinRedisUtils.getGoodsInfoVo(iterator.next());
                if (null == goodsInfoVo || !goodsInfoVo.getDelFlg().equals("0")) {
                    iterator.remove();
                }
            }
//            spuIdList.removeIf(spuId -> null == goblinRedisUtils.getGoodsInfoVo(spuId));
            storeCouponBasicVo.setSpuIdList(spuIdList);
        }

        boolean resultFlg = goblinstoreMgtCouponService.couponEdit(currentUid, storeCouponBasicVo);
        return resultFlg ? ResponseDto.success() : ResponseDto.failure();
    }

    @ApiOperationSupport(order = 7)
    @ApiOperation(value = "优惠券库存编辑")
    @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 = "Integer", name = "operStock", value = "增减库存"),
    })
    @PostMapping("edit_stock")
    public ResponseDto<Object> editStock(@NotBlank(message = "店铺ID不能为空") @RequestParam String storeId,
                                         @NotBlank(message = "优惠券ID不能为空") @RequestParam String storeCouponId,
                                         @NotNull(message = "增减库存值不能为空") @RequestParam Integer operStock) {
        String currentUid = CurrentUtil.getCurrentUid();
        if (!goblinRedisUtils.hasStoreId(currentUid, storeId)) {
            return ResponseDto.failure(ErrorMapping.get("149002"));
        }
        GoblinStoreCouponVo storeCouponVo;
        if (null == (storeCouponVo = goblinRedisUtils.getStoreCouponVo(storeCouponId))) {
            return ResponseDto.failure(ErrorCode.HTTP_PARAM_ERROR.getCode(), "参数无效:优惠券ID");
        }
        if (!storeId.equals(storeCouponVo.getStoreId())) {
            return ResponseDto.failure(ErrorCode.HTTP_PARAM_ERROR.getCode(), "参数有误:无权编辑优惠券");
        }
        if (operStock == 0) {
            return ResponseDto.failure(ErrorCode.HTTP_PARAM_ERROR.getCode(), "参数无效:增减库存不能为0");
        }
        int operStockVal = Math.abs(operStock), surplusStock = goblinRedisUtils.getStoreCouponStock(storeCouponId);
        if (operStock < 0 && (operStockVal > surplusStock || operStockVal > storeCouponVo.getStock())) {
            return ResponseDto.failure(ErrorCode.HTTP_PARAM_ERROR.getCode(), String.format("参数无效:该优惠券总库存%s,剩余库存%s", storeCouponVo.getStock(), surplusStock));
        }
        boolean resultFlg = goblinstoreMgtCouponService.couponEditStock(storeCouponVo, currentUid, operStock);
        return resultFlg ? ResponseDto.success() : ResponseDto.failure();
    }
}
