package cn.iocoder.yudao.module.member.service.activitypay;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.member.api.activitypay.dto.MenuDTO;
import cn.iocoder.yudao.module.member.controller.admin.activitypay.vo.*;
import cn.iocoder.yudao.module.member.controller.app.activity.vo.AppActivityPayRespVO;
import cn.iocoder.yudao.module.member.controller.app.activity.vo.AppCancelVO;
import cn.iocoder.yudao.module.member.dal.dataobject.activity.ActivityDO;
import cn.iocoder.yudao.module.member.dal.dataobject.activityawardsuser.ActivityAwardsUserDO;
import cn.iocoder.yudao.module.member.dal.dataobject.activitymenu.ActivityMenuDO;
import cn.iocoder.yudao.module.member.dal.dataobject.activitypay.ActivityPayDO;
import cn.iocoder.yudao.module.member.dal.dataobject.activitypaytable.ActivityPayTableDO;
import cn.iocoder.yudao.module.member.dal.dataobject.user.MemberUserDO;
import cn.iocoder.yudao.module.member.dal.mysql.activitypay.ActivityPayMapper;
import cn.iocoder.yudao.module.member.service.activitymenu.ActivityMenuService;
import cn.iocoder.yudao.module.member.service.activitypaytable.ActivityPayTableService;
import cn.iocoder.yudao.module.member.service.activityvoucher.ActivityVoucherService;
import cn.iocoder.yudao.module.member.service.activityvoucheruser.ActivityVoucherUserService;
import cn.iocoder.yudao.module.member.service.user.MemberUserService;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.*;

/**
 * 活动付款 Service 实现类
 *
 * @author 我是秦俊旗
 */
@Service
@Validated
public class ActivityPayServiceImpl implements ActivityPayService {

    @Resource
    private ActivityPayMapper activityPayMapper;

    @Resource
    private ActivityPayTableService activityPayTableService;

    @Resource
    @Lazy
    private MemberUserService memberUserService;

    @Resource
    private ActivityVoucherUserService activityVoucherUserService;

    @Resource
    private ActivityMenuService activityMenuService;

    @Resource
    private ActivityVoucherService activityVoucherService;

    @Override
    public Long createActivityPay(ActivityPaySaveReqVO createReqVO) {
        // 插入
        ActivityPayDO activityPay = BeanUtils.toBean(createReqVO, ActivityPayDO.class);
        activityPayMapper.insert(activityPay);
        // 返回
        return activityPay.getId();
    }

    @Override
    public void updateActivityPay(ActivityPaySaveReqVO updateReqVO) {
        // 校验存在
        validateActivityPayExists(updateReqVO.getId());
        // 更新
        ActivityPayDO updateObj = BeanUtils.toBean(updateReqVO, ActivityPayDO.class);
        activityPayMapper.updateById(updateObj);
    }

    @Override
    public void deleteActivityPay(Long id) {
        // 校验存在
        validateActivityPayExists(id);
        // 删除
        activityPayMapper.deleteById(id);
    }

    private void validateActivityPayExists(Long id) {
        if (activityPayMapper.selectById(id) == null) {
            throw exception(ACTIVITY_PAY_NOT_EXISTS);
        }
    }

    @Override
    public ActivityPayDO getActivityPay(Long id) {
        return activityPayMapper.selectById(id);
    }

    @Override
    public PageResult<ActivityPayDO> getActivityPayPage(ActivityPayPageReqVO pageReqVO) {
        return activityPayMapper.selectPage(pageReqVO);
    }

    @Override
    public Map<Long, ActivityPayCountVO> countByActivityIds(List<Long> activityIds) {
        List<ActivityPayCountVO> activityPayCountVOS = activityPayMapper.countByActivityIds(activityIds);
        if (activityPayCountVOS.isEmpty()) {
            return Collections.emptyMap();
        }
        return activityPayCountVOS.stream().collect(Collectors.toMap(ActivityPayCountVO::getActivityId, v -> v));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addActivityPay(ActivityPaySaveReqVO createReqVO) {

        ActivityPayDO activityPayDO = new ActivityPayDO();
        BeanUtil.copyProperties(createReqVO, activityPayDO, "reserveTime");
        MemberUserDO user = memberUserService.getUser(createReqVO.getUserId());
        activityPayDO.setMobile(user.getMobile());
        activityPayDO.setNickName(user.getNickname());

        String reserveTime = createReqVO.getReserveTime();
        LocalDate localDate = null;
        if (StrUtil.isNotBlank(reserveTime)) {
            //转化成date
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
            localDate = LocalDate.parse(reserveTime, formatter);
        }
        activityPayDO.setReserveTime(localDate);
        List<MenuDTO> menu = createReqVO.getMenu();
        if (CollectionUtil.isNotEmpty(menu)) {
            String result = createReqVO.getMenu().stream()
                    .map(MenuDTO::getSerialNumbers)
                    .filter(Objects::nonNull) // 过滤可能的 null 值
                    .collect(Collectors.joining(","));
            activityPayDO.setSerialNumbers(result);
        }

        if (StrUtil.isBlank(createReqVO.getDish())) {
            List<Long> collect = menu.stream().map(MenuDTO::getMenuId).collect(Collectors.toList());
            activityPayDO.setMenuIds(collect.stream().map(String::valueOf).collect(Collectors.joining(",")));
            List<String> menuNames = new ArrayList<>();
            for(MenuDTO menuDTO : createReqVO.getMenu()){
                ActivityMenuDO activityMenu = activityMenuService.getActivityMenu(menuDTO.getMenuId());
                menuNames.add(activityMenu.getMenuName());
            }
            activityPayDO.setMenuNames(String.join(",", menuNames));
        }

        if (StrUtil.isNotBlank(createReqVO.getVoucherId())) {
            activityPayDO.setVoucher(createReqVO.getVoucherId());
        }


        activityPayMapper.insert(activityPayDO);

        if (StrUtil.isBlank(createReqVO.getDish())) {
            List<Long> collect = menu.stream().map(MenuDTO::getMenuId).collect(Collectors.toList());
            List<ActivityMenuDO> listByIds = activityMenuService.getListByIds(collect);
            Map<Long, ActivityMenuDO> menuMap = listByIds.stream().collect(Collectors.toMap(ActivityMenuDO::getId, vo -> vo));


            boolean notBlank = StrUtil.isNotBlank(createReqVO.getVoucherId());
            int size = 0;
            if(notBlank){
                String voucherId = createReqVO.getVoucherId();
                String[] split = voucherId.split(",");
                List<String> list = Arrays.asList(split);
                size = list.size();
            }

            List<ActivityPayTableDO> activityPayTableDOS = new ArrayList<>();
//            boolean type2DiscountApplied = false;
            for (MenuDTO menuDTO : menu) {
                ActivityMenuDO activityMenuDO = menuMap.get(menuDTO.getMenuId());

                ActivityPayTableDO activityPayTableDO = new ActivityPayTableDO();
                activityPayTableDO.setActivityId(activityPayDO.getActivityId());
                activityPayTableDO.setSerialNumbers(menuDTO.getSerialNumbers());
                activityPayTableDO.setPrice(activityMenuDO.getDishPrice());
                if (notBlank ) {
                    BigDecimal dishPrice = activityMenuDO.getDishPrice();
                    if(size >= 2){
                        dishPrice= dishPrice.subtract(new BigDecimal(176));
                        size= size-2;
                    }else if(size == 1){
                        dishPrice= dishPrice.subtract(new BigDecimal(88));
                        size= 0;

                    }
                    activityPayTableDO.setPrice(dishPrice);
                }

                activityPayTableDO.setUserId(activityPayDO.getUserId());
                activityPayTableDO.setReserveTime(activityPayDO.getReserveTime());
                activityPayTableDO.setNickName(activityPayDO.getNickName());
                activityPayTableDO.setMobile(activityPayDO.getMobile());
                activityPayTableDOS.add(activityPayTableDO);
            }
            if (!activityPayTableDOS.isEmpty()) {
                activityPayTableService.insertBatch(activityPayTableDOS);
            }

        } else {
            List<ActivityPayTableDO> activityPayTableDOS = new ArrayList<>();
            MenuDTO menuDTO1 = menu.get(0);
            ActivityPayTableDO activityPayTableDO = new ActivityPayTableDO();
            activityPayTableDO.setActivityId(activityPayDO.getActivityId());
            activityPayTableDO.setSerialNumbers(menuDTO1.getSerialNumbers());
            activityPayTableDO.setPrice(activityPayDO.getPrice());
            activityPayTableDO.setUserId(activityPayDO.getUserId());
            activityPayTableDO.setReserveTime(activityPayDO.getReserveTime());
            activityPayTableDO.setNickName(activityPayDO.getNickName());
            activityPayTableDO.setMobile(activityPayDO.getMobile());
            activityPayTableDOS.add(activityPayTableDO);
            activityPayTableService.insertBatch(activityPayTableDOS);
        }

        if (StrUtil.isNotBlank(createReqVO.getVoucherId())) {
            String voucherId = createReqVO.getVoucherId();
            String[] split = voucherId.split(",");
            List<String> list = Arrays.asList(split);
            activityVoucherUserService.updateByIds(list);
        }

    }

    @Override
    public PageResult<AppActivityPayRespVO> getUserActivityPayPage(ActivityPayPageReqVO pageReqVO) {

        Page<AppActivityPayRespVO> activityAwardsUserRespVOPage = activityPayMapper.selectJoinPage(new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize()), AppActivityPayRespVO.class,
                new MPJLambdaWrapper<ActivityPayDO>()
                        .selectAll(ActivityPayDO.class)
                        .select(ActivityDO::getActivityName)
                        .leftJoin(ActivityDO.class, ActivityDO::getId, ActivityAwardsUserDO::getActivityId)
                        .eq(pageReqVO.getActivityId() != null, ActivityAwardsUserDO::getActivityId, pageReqVO.getActivityId())
                        .eq(pageReqVO.getUserId() != null, ActivityPayDO::getUserId, pageReqVO.getUserId())
                        .isNotNull(pageReqVO.getIsDish(), ActivityPayDO::getDish)
                        .eq(pageReqVO.getStatus() != null, ActivityPayDO::getStatus, pageReqVO.getStatus())
                        .in(CollectionUtil.isNotEmpty(pageReqVO.getSerialNumberList()), ActivityPayDO::getSerialNumbers, pageReqVO.getSerialNumberList())
                        .orderByDesc(ActivityPayDO::getCreateTime)
        );
        return new PageResult<>(activityAwardsUserRespVOPage.getRecords(), activityAwardsUserRespVOPage.getTotal());
    }

    @Override
    public PageResult<AppActivityPayRespVO> getMerchantActivityPayPage(ActivityPayPageReqVO pageReqVO) {

        Page<ActivityPayPageReqVO> queryDTOPage = new Page<>();
        queryDTOPage.setCurrent(pageReqVO.getPageNo());
        queryDTOPage.setSize(pageReqVO.getPageSize());

        Page<AppActivityPayRespVO> activityAwardsUserRespVOPage = activityPayMapper.getPage(queryDTOPage,  pageReqVO);
        return new PageResult<>(activityAwardsUserRespVOPage.getRecords(), activityAwardsUserRespVOPage.getTotal());
    }

    @Override
    public Boolean reserveCancel(AppCancelVO vo) {
        ActivityPayDO activityPayDO = activityPayMapper.selectById(vo.getActivityPayId());
        if (!"0".equals(activityPayDO.getStatus())) {
            throw exception(ACTIVITY_PAY_USE);
        }

        if (StrUtil.isEmpty(activityPayDO.getDish())) {
            //获取当天日期
            LocalDate now = LocalDate.now();
            //比较日期是否相等
            if (!now.isEqual(activityPayDO.getReserveTime())) {
                throw exception(ACTIVITY_PAY_EXPIRE);
            }
        }
        activityPayDO.setStatus("1");
        int i = activityPayMapper.updateById(activityPayDO);
        return i > 0;
    }

    @Override
    public List<ActivityPayDO> getListByTime() {
        LocalDate localDate = LocalDate.now().minusDays(1);

        return activityPayMapper.selectList(Wrappers.<ActivityPayDO>lambdaQuery()
                .le(ActivityPayDO::getReserveTime, localDate)
                .eq(ActivityPayDO::getStatus, "0")
        );
    }

    @Override
    public void updateBatch(List<ActivityPayDO> list) {
        activityPayMapper.updateBatch(list);
    }

    @Override
    public void insertOne(ActivityPayDO activityPayDO) {
        activityPayMapper.insert(activityPayDO);
    }

    @Override
    public ActivityPayDO getOneByActivityIdAndTimeAndNum(Long activityId, LocalDate time, Integer num) {
        return activityPayMapper.selectOne(Wrappers.<ActivityPayDO>lambdaQuery()
                .eq(ActivityPayDO::getActivityId, activityId)
                .eq(ActivityPayDO::getReserveTime, time)
                .eq(ActivityPayDO::getSerialNumbers, num)
                .last("limit 1")
        );
    }

    @Override
    public void updateOne(ActivityPayDO activityPayDO) {
        activityPayMapper.updateById(activityPayDO);
    }

    @Override
    public PageResult<ActivityPayPageRVO> getPage(ActivityPayPageVO pageVO) {
        Page<ActivityPayPageVO> queryDTOPage = new Page<>();
        queryDTOPage.setCurrent(pageVO.getPageNo());
        queryDTOPage.setSize(pageVO.getPageSize());

        Page<ActivityPayPageRVO> activityAwardsUserRespVOPage = activityPayMapper.getPage1(queryDTOPage,  pageVO);

        activityAwardsUserRespVOPage.getRecords().forEach(activityPayPageRVO -> {
            if(StringUtils.isNotBlank(activityPayPageRVO.getVoucher())){
                int length = activityPayPageRVO.getVoucher().split(",").length;
                activityPayPageRVO.setVoucherNum(length);
            }else{
                activityPayPageRVO.setVoucherNum(0);
            }
        });
        return new PageResult<>(activityAwardsUserRespVOPage.getRecords(), activityAwardsUserRespVOPage.getTotal());
    }
}