package com.iformall.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.iformall.common.ErrorCode;
import com.iformall.common.IdWorker;
import com.iformall.common.ResultData;
import com.iformall.domain.dto.WxCouponMerchantDto;
import com.iformall.domain.po.WxCoupon;
import com.iformall.domain.po.WxCouponChannel;
import com.iformall.domain.po.WxCouponMerchant;
import com.iformall.domain.vo.WxCouponCVo;
import com.iformall.domain.vo.WxCouponStatisVo;
import com.iformall.domain.vo.WxMerchantVo;
import com.iformall.enums.*;
import com.iformall.exception.MallinkException;
import com.iformall.mapper.WxCouponChannelMapper;
import com.iformall.mapper.WxCouponMapper;
import com.iformall.mapper.WxCouponMerchantMapper;
import com.iformall.mapper.WxMerchantMapper;
import com.iformall.service.*;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


@Service
public class WxCouponServiceImpl implements WxCouponService {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    WxCouponMapper wxCouponMapper;

    @Autowired
    WxCouponMerchantMapper wxCouponMerchantMapper;

    @Autowired
    WxMerchantMapper wxMerchantMapper;

    @Autowired
    WxCouponChannelService wxCouponChannelService;

    @Autowired
    WxCouponSendService wxCouponSendService;

    @Autowired
    WxOrderService wxOrderService;

    @Autowired
    WxScreenAdService wxScreenAdService;


    @Autowired
    WxCouponChannelMapper wxCouponChannelMapper;


    @Override
    public ResultData list(WxCoupon wxCoupon, Integer pageNum, Integer pageSize) {
        if (null == wxCoupon) wxCoupon = new WxCoupon();
        wxCoupon.setSortColumns(WxCoupon.Field.Id_DESC);
        PageInfo<WxCoupon> page = null;
        if (wxCoupon.getStatus() != null && wxCoupon.getStatus() == -1)
            wxCoupon.setStatus(null);
        page = listAsPage(wxCoupon, pageNum, pageSize);

        List<WxCoupon> wxCouponList = page.getList();

        if (wxCouponList.isEmpty() || wxCoupon.getTargetAd() != null) {
            return new ResultData(page);
        }

        List<Long> ids = wxCouponList.stream().map(p -> p.getId()).collect(Collectors.toList());
        WxCouponChannel wxCouponChannel = new WxCouponChannel();
        wxCouponChannel.setTenantId(wxCoupon.getTenantId());
        wxCouponChannel.setCouponIds(ids);
        wxCouponChannel.setStatus(EnumCouponChannelStatus.STATUS_THROW_IN.getCode());
        //上架状态
        List<WxCouponChannel> list = wxCouponChannelMapper.findList(wxCouponChannel);
        if (!list.isEmpty()) {
            Map<Long, List<WxCouponChannel>> groupBy = list.stream().collect(Collectors.groupingBy(WxCouponChannel::getCouponId));
            for (WxCoupon temp : wxCouponList) {

                if (groupBy.get(temp.getId()) != null) {
                    List<Integer> channels = new ArrayList<>();
                    for (WxCouponChannel tempchannel : groupBy.get(temp.getId())) {
                        if (!channels.contains(tempchannel.getTargetAd())) {
                            channels.add(tempchannel.getTargetAd());
                        }
                    }
                    String sss = JSON.toJSONString(channels);
                    temp.setChannels(sss);
                } else {
                    temp.setChannels("");
                }

            }
        } else {
            for (WxCoupon temp : wxCouponList) {
                temp.setChannels("");
            }

        }
        return new ResultData(page);
    }



    @Override
    public PageInfo<WxCoupon> listAsPage(WxCoupon record, Integer pageIndex, Integer pageSize) {
        return PageHelper.startPage(pageIndex, pageSize).doSelectPageInfo(() -> wxCouponMapper.findCouponList(record));
    }


    @Override
    public PageInfo<WxCouponStatisVo> findCountData(WxCoupon record,Integer pageNum, Integer pageSize) {
        return PageHelper.startPage(pageNum, pageSize).doSelectPageInfo(() -> wxCouponMapper.findCountData(record));
    }

    @Override
    public WxCoupon getById(Long id) {
        return wxCouponMapper.selectByPrimaryKey(id);
    }

    @Override
    public WxCouponCVo getVoById(Long id) {
        WxCouponCVo wxCouponCVo = wxCouponMapper.findVoDetail(id);
        List<WxMerchantVo> merchantList = wxCouponCVo.getMerchantVoList();
        if (merchantList != null) {
            merchantList = merchantList.stream().filter(
                    m->m.getMerchantStatus().equals(EnumMerchantStatus.VALID.getCode()))
                    .collect(Collectors.toList());
        }
        wxCouponCVo.setMerchantVoList(merchantList);
        return wxCouponCVo;
    }


    private Long parseMerchantId(JSONObject merchantParam){
        return Long.valueOf(merchantParam.getString("id"));
    }
    private String parseParameter(JSONObject merchantParam){
        return merchantParam.getString("parameter");
    }
    private Integer parseBusiness(JSONObject merchantParam){
        String businessIdStr = merchantParam.getString("businessId");
        return Integer.valueOf(businessIdStr);

    }
    private Integer parseSubBusiness(JSONObject merchantParam){
        String subBusinessIdStr = merchantParam.getString("subBusinessId");
        if (subBusinessIdStr != null)
            return Integer.valueOf(subBusinessIdStr);
        return null;
    }

    private WxCouponMerchantDto parseMerchantParam(JSONObject merchantParam){
        WxCouponMerchantDto wxCouponMerchantDto = new WxCouponMerchantDto();
        try {
            wxCouponMerchantDto.setMerchantId(parseMerchantId(merchantParam));
            wxCouponMerchantDto.setParameter(parseParameter(merchantParam));
            wxCouponMerchantDto.setBusiness(parseBusiness(merchantParam));
            wxCouponMerchantDto.setSubBusiness(parseSubBusiness(merchantParam));
        }catch (Exception e) {
            throw new MallinkException(ErrorCode.SYS_PARAMETER_ERROR);
        }
        if (wxCouponMerchantDto.getBusiness()==null || wxCouponMerchantDto.getMerchantId()==null) {
            throw new MallinkException(ErrorCode.SYS_PARAMETER_ERROR);
        }
        return wxCouponMerchantDto;
    }


    @Override
    @Transactional(isolation=Isolation.SERIALIZABLE, propagation = Propagation.REQUIRED, rollbackFor = {Exception.class})
    public ResultData saveOrUpdate(WxCoupon record) {

        if (StringUtils.isNotEmpty(record.getSalePriceStr())) {
            record.setSalePrice(new BigDecimal(record.getSalePriceStr()).multiply(new BigDecimal(100)).intValue());
        }
        if (StringUtils.isNotEmpty(record.getUsePriceStr())) {
            record.setUsePrice(new BigDecimal(record.getUsePriceStr()).multiply(new BigDecimal(100)).intValue());
        }
        if (StringUtils.isNotEmpty(record.getPriceStr())) {
            record.setPrice(new BigDecimal(record.getPriceStr()).multiply(new BigDecimal(100)).intValue());
        }
        if (StringUtils.isNotEmpty(record.getSubsidyNumStr())) {
            record.setSubsidyNum(new BigDecimal(record.getSubsidyNumStr()).multiply(new BigDecimal(100)).intValue());
        }

        if (record.getValidType() != null) {
            if (record.getValidType().equals(EnumCouponValidType.DAYS_AFTER_RECEIVING.getCode())) {
                record.setValidStartDate(null);
                record.setValidEndDate(null);
            } else if (record.getValidType().equals(EnumCouponValidType.BETWEEN_TWO_TIME.getCode())) {
                record.setValidDays(null);
            } else {
                return new ResultData(ErrorCode.SYS_PARAMETER_ERROR.getCode(), "请填写有效时间类型");
            }
        }

        final IdWorker idWorker = IdWorker.get();
        List<JSONObject> merchantParamList = JSONObject.parseArray(record.getMerchantParams(), JSONObject.class);
        if (record.getId() == null) {

            // check 卡券补贴设置
            Integer subsidyType = record.getSubsidyType();
            Integer subsidyNum = record.getSubsidyNum();
            if(subsidyType != null && subsidyNum != null) {
                if (subsidyType.equals(EnumCouponSubsidyType.WECHAT_COUPON.getCode())) {
                    // 微信 立减
                    if (subsidyNum > record.getSalePrice()) {
                        return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(), "补贴额大于售价");
                    }
                } else if (subsidyType.equals(EnumCouponSubsidyType.OFFLINE_SUBSIDY.getCode())) {
                    // 线下补贴
                    int subsidy_num = record.getPrice() - record.getSalePrice();
                    if (subsidyNum > subsidy_num) {
                        return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(), "补贴额大于面额与售价的差值");
                    }
                } else if (subsidyType.equals(EnumCouponSubsidyType.WECHAT_MCHPAY.getCode())) {
                    // TODO 微信转账到银行卡

                }
            } else if ((subsidyType == null && subsidyNum != null)
                    || (subsidyType != null && subsidyNum == null)){
                return new ResultData(ErrorCode.SYS_PARAMETER_ERROR);
            }

            record.setId(idWorker.nextId());

            if (merchantParamList != null && merchantParamList.size() > 0) {
                List<WxCouponMerchantDto> wxCouponMerchantDtoList = new ArrayList<>();
                merchantParamList.forEach(merchantParam -> {
                    WxCouponMerchant cm = new WxCouponMerchant();
                    WxCouponMerchantDto wxCouponMerchantDto = parseMerchantParam(merchantParam);
                    cm.setId(idWorker.nextId());
                    cm.setMerchantId(wxCouponMerchantDto.getMerchantId());
                    cm.setParameter(wxCouponMerchantDto.getParameter());
                    cm.setProductId(record.getId());
                    cm.setCreateDate(new Date());
                    cm.setUpdateDate(new Date());
                    cm.setStatus(EnumCouponMerchantStatus.COUPON_MERCHANT_STATUS_VALID.getCode());
                    wxCouponMerchantDtoList.add(wxCouponMerchantDto);
                    wxCouponMerchantMapper.insertSelective(cm);
                });
                if (wxCouponMerchantDtoList.stream()
                        .mapToInt(WxCouponMerchantDto::getBusiness).distinct().count() > 1) {
                    record.setBusiness(EnumBusiness.BUSINESS_ID6.getCode());
                } else if (wxCouponMerchantDtoList.size() > 1){
                    record.setBusiness(wxCouponMerchantDtoList.get(0).getBusiness());
                } else {
                    record.setBusiness(wxCouponMerchantDtoList.get(0).getBusiness());
                    record.setSubBusiness(wxCouponMerchantDtoList.get(0).getSubBusiness());
                }

            } else{
                return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL);
            }

            record.setCreateDate(new Date());
            record.setUpdateDate(new Date());
            wxCouponMapper.insertSelective(record);

        } else {
            if (merchantParamList != null && merchantParamList.size() > 0) {
                WxCouponMerchant cmParam = new WxCouponMerchant();
                cmParam.setProductId(record.getId());
                List<WxCouponMerchant> oldList = wxCouponMerchantMapper.findList(cmParam);
                List<WxCouponMerchantDto> wxCouponMerchantDtoList = new ArrayList<>();
                merchantParamList.stream().forEach(merchantParam -> {
                    WxCouponMerchant cm = new WxCouponMerchant();
                    WxCouponMerchantDto wxCouponMerchantDto = parseMerchantParam(merchantParam);
                    cm.setMerchantId(wxCouponMerchantDto.getMerchantId());
                    cm.setProductId(record.getId());
                    WxCouponMerchant rcm = wxCouponMerchantMapper.selectOne(cm);
                    if (rcm != null) {
                        rcm.setParameter(wxCouponMerchantDto.getParameter());
                        rcm.setStatus(EnumCouponMerchantStatus.COUPON_MERCHANT_STATUS_VALID.getCode());
                        rcm.setUpdateDate(new Date());
                        wxCouponMerchantMapper.updateByPrimaryKeySelective(rcm);
                    }else {
                        cm.setId(idWorker.nextId());
                        cm.setStatus(EnumCouponMerchantStatus.COUPON_MERCHANT_STATUS_VALID.getCode());
                        cm.setParameter(wxCouponMerchantDto.getParameter());
                        cm.setCreateDate(new Date());
                        cm.setUpdateDate(new Date());
                        wxCouponMerchantMapper.insertSelective(cm);
                    }
                    wxCouponMerchantDtoList.add(wxCouponMerchantDto);
                    oldList.removeIf(
                            old->old.getProductId().equals(record.getId()) &&
                             old.getMerchantId().equals(wxCouponMerchantDto.getMerchantId()));
                });

                oldList.stream().forEach(old->{
                    old.setStatus(EnumCouponMerchantStatus.COUPON_MERCHANT_STATUS_INVALID.getCode());
                    old.setUpdateDate(new Date());
                    wxCouponMerchantMapper.updateByPrimaryKeySelective(old);
                });

                if (wxCouponMerchantDtoList.stream()
                        .mapToInt(WxCouponMerchantDto::getBusiness).distinct().count() > 1) {
                    record.setBusiness(EnumBusiness.BUSINESS_ID6.getCode());
                } else if (wxCouponMerchantDtoList.size() > 1){
                    record.setBusiness(wxCouponMerchantDtoList.get(0).getBusiness());
                } else {
                    record.setBusiness(wxCouponMerchantDtoList.get(0).getBusiness());
                    record.setSubBusiness(wxCouponMerchantDtoList.get(0).getSubBusiness());
                }
            }

            if (record.getStatus() != null &&
                    (record.getStatus().equals(EnumCouponStatus.COUPON_STATUS_TAKE_OFFF.getCode()))) {

                //下架所有投放频道
                wxCouponChannelService
                        .updateStatusByCouponId(record.getId(), record.getTenantId(), EnumCouponChannelStatus.STATUS_TAKE_OFFF.getCode());
                //下架所有场景投放
                wxCouponSendService
                        .updateStatusByCouponId(record.getId(), record.getTenantId(), EnumCouponSendStatus.INVALID.getCode());
                //下架所有已砍价券
                wxOrderService.updateStatusByPressCouponId(record.getId(), record.getTenantId(), EnumOrderStatus.ORDER_STATUS_PRESS_CANCEL.getCode());
                //下架所有相关广告
                wxScreenAdService.updateStatusByCouponId(record.getId(), record.getTenantId(), EnumScreenAdStatus.INVALID.getCode());
                //下架拼团券
                wxOrderService.updateOrderGroupStatusByCouponId(record.getId(), record.getTenantId(), EnumOrderStatus.ORDER_STATUS_COOPERATING_CANCEL.getCode());

            }
            record.setUpdateDate(new Date());
            wxCouponMapper.updateByPrimaryKeySelective(record);
        }
        return new ResultData(record.getId());
    }

    @Override
    public void deleteById(Long id) {
        wxCouponMapper.deleteByPrimaryKey(id);
    }

    @Override
    public List<WxCouponStatisVo> findSaleMoneyByDate(WxCoupon wxCoupon) {
        return wxCouponMapper.findSaleMoneyByDate(wxCoupon);
    }

    @Override
    public List<WxCouponStatisVo> findPaymentByDate(WxCoupon wxCoupon) {
        return wxCouponMapper.findPaymentByDate(wxCoupon);
    }

    @Override
    public Long findSaleCardCount(WxCoupon wxCoupon) {
        Long count = wxCouponMapper.findSaleCardCount(wxCoupon);
        return (count==null)?0l:count;
    }

    @Override
    public Long findTranCardCount(WxCoupon wxCoupon) {
        Long count = wxCouponMapper.findTranCardCount(wxCoupon);
        return (count==null)?0l:count;
    }

    @Override
    public String findSubsidyMoney(WxCoupon wxCoupon) {
        String count = wxCouponMapper.findSubsidyMoney(wxCoupon);
        return (count==null)?"0":count;
    }

    @Override
    public PageInfo<WxCouponStatisVo> findCouponData(WxCoupon record, Integer pageNum, Integer pageSize) {
        return PageHelper.startPage(pageNum, pageSize).doSelectPageInfo(() -> wxCouponMapper.findCouponData(record));
    }

    @Override
    public List<WxCouponStatisVo> findCouponOrderCount(WxCoupon wxCoupon) {
        return wxCouponMapper.findCouponOrderCount(wxCoupon);
    }


    @Override
    public List<WxCouponStatisVo> findCouponPaymentCount(WxCoupon wxCoupon) {
        return wxCouponMapper.findCouponPaymentCount(wxCoupon);
    }

    @Override
    public List<WxCouponStatisVo> priceCouponSaleCount(WxCoupon wxCoupon) {
        return wxCouponMapper.priceCouponSaleCount(wxCoupon);
    }

    @Override
    public List<WxCouponStatisVo> priceCouponPaymentCount(WxCoupon wxCoupon) {
        return wxCouponMapper.priceCouponPaymentCount(wxCoupon);
    }

    @Override
    public String findSumPriceSaleMoney(WxCoupon wxCoupon) {
        String count = wxCouponMapper.findSumPriceSaleMoney(wxCoupon);
        return (count==null)?"0":count;
    }

    @Override
    public String findSumPricePayMent(WxCoupon wxCoupon) {
        String count = wxCouponMapper.findSumPricePayMent(wxCoupon);
        return (count==null)?"0":count;
    }

    @Override
    public String findSumSubsidyMoney(WxCoupon wxCoupon) {
        String count = wxCouponMapper.findSumSubsidyMoney(wxCoupon);
        return (count==null)?"0":count;
    }

    @Override
    public PageInfo<WxCouponStatisVo> findPressData(WxCoupon record, Integer pageNum, Integer pageSize) {
        return PageHelper.startPage(pageNum, pageSize).doSelectPageInfo(() -> wxCouponMapper.findPressData(record));
    }

    @Override
    public List<WxCouponStatisVo> pressSendHistory(WxCoupon wxCoupon) {
        return wxCouponMapper.pressSendHistory(wxCoupon);
    }

    @Override
    public List<WxCouponStatisVo> pressSuccHistory(WxCoupon wxCoupon) {
        return wxCouponMapper.pressSuccHistory(wxCoupon);
    }

    @Override
    public List<WxCouponStatisVo> pressPaymentHistory(WxCoupon wxCoupon) {
        return wxCouponMapper.pressPaymentHistory(wxCoupon);
    }

    @Override
    public String pressSuccRate(WxCoupon wxCoupon) {
        String count = wxCouponMapper.pressSuccRate(wxCoupon);
        if (StringUtils.isBlank(count) || "0.00".equals(count)) {
            return "0%";
        } else {
            return count + "%";
        }
    }

    @Override
    public Long sumJoin(WxCoupon wxCoupon) {
        Long count = wxCouponMapper.sumJoin(wxCoupon);
        return (count==null)?0l:count;
    }
}
