package com.liquidnet.client.admin.web.controller.zhengzai.adam;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.liquidnet.client.admin.common.annotation.Log;
import com.liquidnet.client.admin.common.core.controller.BaseController;
import com.liquidnet.client.admin.common.core.domain.AjaxResult;
import com.liquidnet.client.admin.common.core.page.TableDataInfo;
import com.liquidnet.client.admin.common.enums.BusinessType;
import com.liquidnet.client.admin.common.utils.ShiroUtils;
import com.liquidnet.client.admin.common.utils.poi.ExcelUtil;
import com.liquidnet.client.admin.zhengzai.adam.dto.AdamMemberCodeExcelDto;
import com.liquidnet.client.admin.zhengzai.adam.service.IAdamMemberAdminService;
import com.liquidnet.client.admin.zhengzai.adam.service.IAdamMemberCodeAdminService;
import com.liquidnet.client.admin.zhengzai.adam.service.IAdamMemberPriceAdminService;
import com.liquidnet.client.admin.zhengzai.adam.service.IAdamMemberRightsAdminService;
import com.liquidnet.client.admin.zhengzai.candy.service.ICandyCouponAdminService;
import com.liquidnet.client.admin.zhengzai.candy.service.ICandyMgtCouponAdminService;
import com.liquidnet.common.cache.redis.util.RedisUtil;
import com.liquidnet.commons.lang.util.CollectionUtil;
import com.liquidnet.service.adam.constant.AdamRedisConst;
import com.liquidnet.service.adam.dto.admin.*;
import com.liquidnet.service.adam.dto.vo.AdamMemberCodeVo;
import com.liquidnet.service.adam.entity.AdamMember;
import com.liquidnet.service.adam.entity.AdamMemberCode;
import com.liquidnet.service.adam.entity.AdamMemberPrice;
import com.liquidnet.service.adam.entity.AdamMemberRights;
import com.liquidnet.service.candy.dto.admin.CandyCouponRuleBuildParam;
import com.liquidnet.service.candy.dto.admin.CandyMemberCouponBuildParam;
import com.liquidnet.service.candy.dto.admin.CandyMgtCouponMemberDto;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Api(tags = "会员管理")
@Controller
@RequestMapping("adam/member")
public class AdamMemberAdminController extends BaseController {
    private final String prefix = "zhengzai/adam/member";
    @Autowired
    IAdamMemberAdminService adamMemberService;
    @Autowired
    IAdamMemberPriceAdminService adamMemberPriceAdminService;
    @Autowired
    IAdamMemberRightsAdminService adamMemberRightsAdminService;
    @Autowired
    IAdamMemberCodeAdminService adamMemberCodeAdminService;
    @Autowired
    ICandyMgtCouponAdminService candyMgtCouponAdminService;
    @Autowired
    ICandyCouponAdminService candyCouponAdminService;

    @Autowired
    private RedisUtil redisUtil;

    @GetMapping()
    public String view() {
        return prefix + "/member";
    }

    @RequiresPermissions("adam:member:view:code")
    @GetMapping("code/{memberId}")
    public String viewCode(@PathVariable("memberId") String memberId, ModelMap mmap) {
        mmap.put("memberId", memberId);
        return prefix + "/code";
    }

    @RequiresPermissions("adam:member:view:list")
    @Log(title = "会员管理:会员卡:列表", businessType = BusinessType.LIST)
    @PostMapping("list")
    @ResponseBody
    public TableDataInfo list() {
        startPage();
        return getDataTable(adamMemberService.list(
                Wrappers.lambdaQuery(AdamMember.class).eq(AdamMember::getState, 1).select(
                        AdamMember::getMemberId, AdamMember::getIcon, AdamMember::getTitle, AdamMember::getSubTitle, AdamMember::getOnsale
                )
        ));
    }

    @RequiresPermissions("adam:member:view:edit")
    @Log(title = "会员管理:会员卡:详情", businessType = BusinessType.DETAIL)
    @GetMapping("info/{memberId}")
    public String info(@PathVariable("memberId") String memberId, ModelMap mmap) {
        AdamMember member = adamMemberService.getOne(Wrappers.lambdaQuery(AdamMember.class)
                .eq(AdamMember::getState, 1)
                .eq(AdamMember::getMemberId, memberId)
                .select(
                        AdamMember::getMemberId,
                        AdamMember::getName,
                        AdamMember::getTitle,
                        AdamMember::getSubTitle,
                        AdamMember::getAvatar,
                        AdamMember::getIcon,
                        AdamMember::getLimitation,
                        AdamMember::getLimitbAt,
                        AdamMember::getLimiteAt,
                        AdamMember::getInterestsDetail,
                        AdamMember::getNotes,
                        AdamMember::getType,
                        AdamMember::getIntegralRate
                )
        );
        mmap.put("member", member);

        if (null != member) {
            List<AdamMemberRights> memberRightsList = adamMemberRightsAdminService.list(Wrappers.lambdaQuery(AdamMemberRights.class)
                    .eq(AdamMemberRights::getState, 1)
                    .eq(AdamMemberRights::getMemberId, member.getMemberId())
                    .select(
                            AdamMemberRights::getMrightsId,
                            AdamMemberRights::getCover,
                            AdamMemberRights::getTitle,
                            AdamMemberRights::getSubTitle,
                            AdamMemberRights::getDetail
                    )
            );
            mmap.put("memberRightsList", memberRightsList);

            if (!CollectionUtils.isEmpty(memberRightsList)) {
                List<String> mrightsIdList = memberRightsList.stream().map(AdamMemberRights::getMrightsId).collect(Collectors.toList());

                List<CandyMgtCouponMemberDto> couponMemberDtoList = candyMgtCouponAdminService.listForMgtCouponMemberDto(mrightsIdList);

                Map<String, List<CandyMgtCouponMemberDto>> couponMemberDtoListMap = couponMemberDtoList.stream().collect(Collectors.groupingBy(CandyMgtCouponMemberDto::getMcouponId));

                mmap.put("couponMemberDtoListMap", couponMemberDtoListMap);
            }

            AdamMemberPrice memberPrice = adamMemberPriceAdminService.getOne(Wrappers.lambdaQuery(AdamMemberPrice.class)
                    .eq(AdamMemberPrice::getState, 1)
                    .eq(AdamMemberPrice::getMemberId, member.getMemberId())
                    .select(
                            AdamMemberPrice::getMemberPriceId,
                            AdamMemberPrice::getPrice,
                            AdamMemberPrice::getPriceFixed,
                            AdamMemberPrice::getPriceSpecial,
                            AdamMemberPrice::getDays
                    )
            );
            mmap.put("memberPrice", memberPrice);
        }
        return prefix + "/info";
    }

    @ApiOperation(value = "会员设置:基础信息编辑")
    @RequiresPermissions("adam:member:edit:basic")
    @Log(title = "会员管理:会员卡编辑:基础信息", businessType = BusinessType.UPDATE)
    @PostMapping("edit_basic")
    @ResponseBody
    public AjaxResult editBasic(@Validated AdamMemberBuildParam parameter) {
        return this.toAjax(adamMemberService.edit(parameter));
    }

    @ApiOperation(value = "会员套餐:价格编辑")
    @RequiresPermissions("adam:member:edit:price")
    @Log(title = "会员管理:会员卡编辑:价格配置", businessType = BusinessType.UPDATE)
    @PostMapping("edit_price")
    @ResponseBody
    public AjaxResult editPrice(@Validated AdamMemberPriceBuildParam parameter) {
        return this.toAjax(adamMemberPriceAdminService.edit(parameter));
    }

    @ApiOperation(value = "会员套餐:权益编辑")
    @RequiresPermissions("adam:member:edit:rights")
    @Log(title = "会员管理:会员卡编辑:权益", businessType = BusinessType.UPDATE)
    @PostMapping("edit_rights")
    @ResponseBody
    public AjaxResult editRights(@Validated AdamMemberRightsBuildParam parameter) {
        if (parameter.getState() != 2) {
            // 这里编辑包含新增、更新、删除分别对应state:1,1,2
            parameter.setState(1);
        } else if (StringUtils.isBlank(parameter.getMrightsId())) {
            return AjaxResult.warn("请指定要删除的权益ID");
        }
        if (null == parameter.getSeqNo()) {
            parameter.setSeqNo(0);
        }
        return this.toAjax(adamMemberRightsAdminService.edit(parameter));
    }

    @ApiOperation(value = "会员套餐:券编辑")
    @RequiresPermissions("adam:member:edit:coupon")
    @Log(title = "会员管理:会员卡编辑:权益券", businessType = BusinessType.UPDATE)
    @PostMapping("edit_coupon")
    @ResponseBody
    public AjaxResult editCoupon(@RequestBody @Validated CandyMemberCouponBuildParam parameter) {
        Integer busiType = parameter.getBusiType();// 业务类别[0-全场｜1-演出｜2-商品｜3-优先购]
//        if (busiType > 0) {
//            if (CollectionUtils.isEmpty(parameter.getCouponRuleList())) {
//                return AjaxResult.warn("适用范围无效");
//            }
//        } else {
//            parameter.setCouponRuleList(null);
//        }
        parameter.setCouponRuleList(Collections.singletonList(CandyCouponRuleBuildParam.getNew().setUseScope(100)));

        parameter.setOverlay(busiType < 3 ? 0 : parameter.getOverlay());
        switch (parameter.getCouType()) {// 券类型[1-代金券｜2-满减券]
            case 1:
                BigDecimal valFace = parameter.getValFace();
                if (null == valFace || valFace.compareTo(BigDecimal.ZERO) <= 0) {
                    return AjaxResult.warn("代金券金额无效");
                }
                parameter.setValOver(null);
                parameter.setValMinus(null);
                break;
            case 2:
                BigDecimal valOver = parameter.getValOver();
                BigDecimal valMinus = parameter.getValMinus();
                if (null == valOver || valOver.compareTo(BigDecimal.ZERO) <= 0
                        || null == valMinus || valMinus.compareTo(BigDecimal.ZERO) <= 0) {
                    return AjaxResult.warn("满减金额无效");
                }
                parameter.setValFace(valMinus);
                break;
            case 101:
                parameter.setValFace(null);
                parameter.setValOver(null);
                parameter.setValMinus(null);
                break;
            default:
                logger.warn("Invalid operation[buildParam.couType={}]", parameter.getCouType());
                return this.error(AjaxResult.Type.WARN, "券类型无效");
        }


        if (StringUtils.isEmpty(parameter.getCouponId())) {
            // 新增券
            return this.toAjax(candyMgtCouponAdminService.saveMgtCouponForMemberRights(parameter));
        } else {
            // 编辑券
            return this.toAjax(candyMgtCouponAdminService.editMgtCouponForMemberRights(parameter));
        }
    }

    @ApiOperation(value = "会员码:列表")
    @RequiresPermissions("adam:member:list:code")
    @Log(title = "会员管理:会员码:列表", businessType = BusinessType.LIST)
    @PostMapping("list_code")
    @ResponseBody
    public TableDataInfo listCode(AdamMemberCodeListParam parameter) {
        return getDataTable(codeListQuery(parameter));
    }

    private List<AdamMemberCode> codeListQuery(AdamMemberCodeListParam parameter) {
        LambdaQueryWrapper<AdamMemberCode> queryWrapper = Wrappers.lambdaQuery(AdamMemberCode.class).orderByDesc(AdamMemberCode::getCreatedAt);
        queryWrapper.eq(AdamMemberCode::getMemberId, parameter.getMemberId());
        queryWrapper.eq(AdamMemberCode::getType, 2);
        queryWrapper.ne(AdamMemberCode::getState, 2);
        if (null != parameter.getState()) {
            queryWrapper.eq(AdamMemberCode::getState, parameter.getState());
        }
        queryWrapper.select(
                AdamMemberCode::getCode,
                AdamMemberCode::getState,
                AdamMemberCode::getOperator,
                AdamMemberCode::getCreatedAt,
                AdamMemberCode::getValidity,
                AdamMemberCode::getEffectAt,
                AdamMemberCode::getExpireAt,
                AdamMemberCode::getUseOrderNo,
                AdamMemberCode::getUseUid,
                AdamMemberCode::getUseAt
        );
        queryWrapper.orderByDesc(AdamMemberCode::getMemberNo);

        return adamMemberCodeAdminService.list(queryWrapper);
    }

    @ApiOperation(value = "会员码:导出")
    @RequiresPermissions("adam:member:export:code")
    @Log(title = "会员管理:会员码:导出", businessType = BusinessType.EXPORT)
    @PostMapping("export_code")
    @ResponseBody
    public AjaxResult exportCode(AdamMemberCodeListParam parameter) {
        List<AdamMemberCode> list = codeListQuery(parameter);

        ExcelUtil<AdamMemberCodeExcelDto> excelUtil = new ExcelUtil<>(AdamMemberCodeExcelDto.class);
        List<AdamMemberCodeExcelDto> excelList = new ArrayList<>();
        list.forEach(r -> {
            excelList.add(AdamMemberCodeExcelDto.getNew().copy(r));
        });
        return excelUtil.exportExcel(excelList, "会员码数据");
    }

    @ApiOperation(value = "会员码:生成")
    @RequiresPermissions("adam:member:gen:code")
    @Log(title = "会员管理:会员码:生成", businessType = BusinessType.INSERT)
    @PostMapping("gen_code")
    @ResponseBody
    public AjaxResult genCode(@Validated AdamMemberCodeGenParam parameter) {
        int count = adamMemberPriceAdminService.count(
                Wrappers.lambdaQuery(AdamMemberPrice.class)
                        .eq(AdamMemberPrice::getMemberPriceId, parameter.getMemberPriceId())
                        .eq(AdamMemberPrice::getMemberId, parameter.getMemberId())
                        .eq(AdamMemberPrice::getState, 1)
        );
        if (count <= 0) {
            logger.warn("会员卡ID/价格ID无效[{}]", parameter);
            return this.error("会员卡ID/价格ID无效");
        }
        return this.toAjax(adamMemberCodeAdminService.createGiftCode(parameter));
    }

    @RequiresPermissions("adam:member:invalid:code")
    @Log(title = "会员管理:会员码:失效", businessType = BusinessType.UPDATE)
    @PostMapping("invalid_code")
    @ResponseBody
    public AjaxResult invalid(AdamMemberCodeOptParam optParam) {
        return toAjax(this.invalidRecoverCode(optParam, 4));
    }

    /**
     * 失效｜退回会员兑换码
     *
     * @param optParam AdamMemberCodeOptParam
     * @param state    状态[0-可用|1-已用|2-无效|3-过期｜4-失效｜5-退回]
     * @return boolean
     */
    private boolean invalidRecoverCode(AdamMemberCodeOptParam optParam, int state) {
        String loginName = ShiroUtils.getLoginName();
        LocalDateTime now = LocalDateTime.now();
        logger.info("by:{},optParam:{},state:{}", loginName, optParam, state);

        int beforeState = state == 4 ? 0 : (state == 5 ? 1 : -1);
        ArrayList<String> updateCodeList = CollectionUtil.arrayListString();
        optParam.getCodes().forEach(r -> {
            String key = AdamRedisConst.INFO_MEMBER_CODE.concat(r);
            AdamMemberCodeVo vo = (AdamMemberCodeVo) redisUtil.get(key);
            if (null != vo && vo.getState() == beforeState) {
                redisUtil.del(key);

                updateCodeList.add(vo.getCode());
            }
        });

        if (!CollectionUtils.isEmpty(updateCodeList)) {
            LambdaUpdateWrapper<AdamMemberCode> memberCodeUpdateWrapper = Wrappers.lambdaUpdate(AdamMemberCode.class);
            memberCodeUpdateWrapper.eq(AdamMemberCode::getMemberId, optParam.getMemberId());
            memberCodeUpdateWrapper.eq(AdamMemberCode::getState, beforeState);
            memberCodeUpdateWrapper.in(AdamMemberCode::getCode, updateCodeList);

            memberCodeUpdateWrapper.set(AdamMemberCode::getState, state);
            memberCodeUpdateWrapper.set(AdamMemberCode::getOperator, loginName);
            memberCodeUpdateWrapper.set(AdamMemberCode::getUpdatedAt, now);

            return adamMemberCodeAdminService.update(memberCodeUpdateWrapper);
        }
        return false;
    }

    @RequiresPermissions("adam:member:recover:code")
    @Log(title = "会员管理:会员码:退回", businessType = BusinessType.UPDATE)
    @PostMapping("recover_code")
    @ResponseBody
    public AjaxResult recover(AdamMemberCodeOptParam optParam) {
        return toAjax(this.invalidRecoverCode(optParam, 5));
    }
}
