package com.mcwl.communityCenter.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mcwl.common.constant.HttpStatus;
import com.mcwl.common.core.domain.R;
import com.mcwl.common.core.domain.entity.SysUser;
import com.mcwl.common.core.page.TableDataInfo;
import com.mcwl.common.core.redis.RedisCache;
import com.mcwl.common.exception.ServiceException;
import com.mcwl.common.utils.SecurityUtils;
import com.mcwl.common.utils.StringUtils;
import com.mcwl.communityCenter.constant.AdviceConstant;
import com.mcwl.communityCenter.domain.*;
import com.mcwl.communityCenter.domain.dto.*;
import com.mcwl.communityCenter.domain.vo.CommunityDetailVo;
import com.mcwl.communityCenter.domain.vo.CommunityVo;
import com.mcwl.communityCenter.mapper.CommunityAdviceMapper;
import com.mcwl.communityCenter.mapper.CommunityMapper;
import com.mcwl.communityCenter.mapper.CommunityUserMapper;
import com.mcwl.communityCenter.service.CommunityService;
import com.mcwl.communityCenter.service.IncomeInfoService;
import com.mcwl.communityCenter.service.PublishService;
import com.mcwl.myInvitation.domain.CommissionRatio;
import com.mcwl.myInvitation.domain.Consume;
import com.mcwl.myInvitation.mapper.ConsumeMapper;
import com.mcwl.myInvitation.service.CommissionRatioService;
import com.mcwl.system.service.ISysUserService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class CommunityServiceImpl extends ServiceImpl<CommunityMapper, Community> implements CommunityService {

    private final CommunityUserMapper communityUserMapper;

    private final ISysUserService sysUserService;

    private final RedisCache redisCache;

    private final CommunityAdviceMapper communityAdviceMapper;

    private final PublishService publishService;

    private final ConsumeMapper consumeMapper;

    private final IncomeInfoService incomeInfoService;

    private final CommissionRatioService commissionRatioService;



    @Override
    public TableDataInfo listByPage(CommunityListPageRes communityListPageRes) {

        Page<Community> page = new Page<>(communityListPageRes.getPageNum(), communityListPageRes.getPageSize());
        OrderItem orderItem = new OrderItem("create_time", false);
        page.addOrder(orderItem);

        List<Community> communityList;
        if (Objects.isNull(communityListPageRes.getUserId())) {
            communityList = baseMapper.selectPageByCommunityTag(page, communityListPageRes.getCommunityTag(), communityListPageRes.getSearchContent());
        } else {
            baseMapper.selectPage(page, new LambdaQueryWrapper<Community>()
                    .like(StringUtils.isNotBlank(communityListPageRes.getSearchContent()), Community::getCommunityName, communityListPageRes.getSearchContent())
                    .like(StringUtils.isNotBlank(communityListPageRes.getSearchContent()), Community::getDescription, communityListPageRes.getSearchContent()));
            communityList = page.getRecords();
        }

        return this.getCommunityVoTableDataInfo(communityList, page.getTotal());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addCommunity(AddCommunityRes addCommunityRes) {
        try {
            Community community = new Community();
            BeanUtil.copyProperties(addCommunityRes, community);
            if (Objects.equals(addCommunityRes.getType(), 0)) {
                community.setPrice(0.0);
            }
            baseMapper.insert(community);

            communityUserMapper.insert(CommunityUser
                    .builder()
                    .tenantId(SecurityUtils.getUserId())
                    .communityId(community.getId())
                    .userId(SecurityUtils.getUserId())
                    .userType(2)
                    .build());
            redisCache.deleteObject("communityJoinNumMap");

        } catch (Exception e) {
            throw new ServiceException(e.getMessage(), HttpStatus.SHOW_ERROR_MSG);
        }

    }

    /**
     * 加入社区
     *
     * @param joinCommunityRes 加入社区请求参数
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R<Object> joinCommunity(JoinCommunityRes joinCommunityRes) {
        Long tenantId = joinCommunityRes.getTenantId();
        Long communityId = joinCommunityRes.getCommunityId();
        Community community = baseMapper.getByTenantIdAndCommunityId(tenantId, communityId);
        if (Objects.isNull(community)) {
            return R.fail(HttpStatus.SHOW_ERROR_MSG,"社区不存在，请重新加入");
        }

        CommunityUser communityUser = communityUserMapper.selectByTenantIdAndCommunityIdAndUserId(tenantId,
                communityId,
                SecurityUtils.getUserId());

        if (Objects.nonNull(communityUser)) {
            return R.fail(HttpStatus.SHOW_ERROR_MSG,"您已加入该社区,不能重复加入");
        }

        SysUser user = sysUserService.selectUserById(SecurityUtils.getUserId());
        Double wallet = user.getWallet();
        Double price = community.getPrice();
        if (wallet < price) {
            return R.fail(HttpStatus.SHOW_ERROR_MSG,"钱包余额不足，请充值");
        }
        // 扣费
        BigDecimal priceBigDecimal = new BigDecimal(price.toString());
        BigDecimal walletBigDecimal = new BigDecimal(wallet.toString());
        user.setWallet(walletBigDecimal.subtract(priceBigDecimal).doubleValue());

        sysUserService.updateUser(user);



        // 从redis获取提成比例
        // 抽取社区比例
        String commissionRationCommunity = redisCache.getCacheObject("CommissionRationCommunity");
        if (Objects.isNull(commissionRationCommunity)) {
            CommissionRatio commissionRatio = commissionRatioService.lambdaQuery()
                    .eq(CommissionRatio::getType, 2)
                    .one();
            commissionRationCommunity = commissionRatio.getRatio().toString();
            redisCache.setCacheObject("CommissionRationCommunity", commissionRationCommunity);
        }

        SysUser tenantUser = sysUserService.selectUserById(tenantId);
        BigDecimal getWallet = priceBigDecimal
                .multiply(new BigDecimal("1").subtract(new BigDecimal(commissionRationCommunity)));
        tenantUser.setWallet(getWallet
                .add(new BigDecimal(tenantUser.getWallet().toString()))
                .setScale(2, RoundingMode.HALF_UP)
                .doubleValue());
        sysUserService.updateUser(tenantUser);


        Calendar now = Calendar.getInstance();
        Date startTime = now.getTime();
        now.add(Calendar.YEAR, community.getValidityDay());
        Date endTime = now.getTime();

        CommunityUser cu = CommunityUser.builder()
                .tenantId(tenantId)
                .communityId(communityId)
                .userId(SecurityUtils.getUserId())
                .userType(0)
                .communityPrice(price)
                .startTime(startTime)
                .endTime(endTime)
                .build();

        communityUserMapper.insert(cu);

        if (price <= 0) {
            return R.ok("加入成功");
        }

        CommunityAdvice communityAdvice = new CommunityAdvice();
        communityAdvice.setTenantId(tenantId);
        communityAdvice.setCommunityId(communityId);
        communityAdvice.setSendUserId(SecurityUtils.getUserId());
        communityAdvice.setAdviceType(AdviceConstant.COMMUNITY_NOTICE);
        communityAdvice.setUserId(tenantId);
        communityAdvice.setContent(StringUtils.format("{}加入{}社区，金币+{}",
                SecurityUtils.getLoginUser().getUser().getNickName(), community.getCommunityName(), getWallet));
        communityAdviceMapper.insert(communityAdvice);

        Consume consume = new Consume();
        consume.setUserId(SecurityUtils.getUserId());
        consume.setAmount(-price);
        consume.setProductId(communityId);
        consume.setType(3);
        consume.setWallet(user.getWallet());
        consumeMapper.insert(consume);

        consume = new Consume();
        consume.setUserId(community.getTenantId());
        consume.setAmount(getWallet.doubleValue());
        consume.setProductId(communityId);
        consume.setType(3);
        consume.setWallet(sysUserService.selectUserById(community.getTenantId()).getWallet());
        consumeMapper.insert(consume);

        IncomeInfo incomeInfo = new IncomeInfo();
        incomeInfo.setTenantId(tenantId);
        incomeInfo.setCommunityId(communityId);
        incomeInfo.setUserId(tenantId);
        incomeInfo.setType(0);
        incomeInfo.setAmount(getWallet.doubleValue());
        incomeInfoService.save(incomeInfo);

        redisCache.deleteObject("communityJoinNumMap");


        return R.ok("加入成功");
    }

    @Override
    public TableDataInfo getMyJoinCommunity(JoinCommunityListPageRes joinCommunityListPageRes) {
        Page<Community> page = new Page<>(joinCommunityListPageRes.getPageNum(), joinCommunityListPageRes.getPageSize());
        page.addOrder(new OrderItem("create_time", false));

        List<Community> communityList = baseMapper.getMyJoinCommunity(page, SecurityUtils.getUserId(), joinCommunityListPageRes);


        return this.getCommunityVoTableDataInfo(communityList, page.getTotal());
    }

    @Override
    public Community getByTenantIdAndCommunityId(Long userId, Long communityId) {
        return baseMapper.getByTenantIdAndCommunityId(userId, communityId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public R<Object> quitCommunity(Long tenantId, Long communityId) {

        Long userId = SecurityUtils.getUserId();

        Community community = baseMapper.getByTenantIdAndCommunityId(tenantId, communityId);

        if (Objects.isNull(community)) {
            return R.fail(HttpStatus.SHOW_ERROR_MSG, "社区不存在");
        }

        CommunityUser communityUser = communityUserMapper.selectCommunityUser(tenantId, communityId, userId);
        if (Objects.isNull(communityUser)) {
            return R.fail(HttpStatus.SHOW_ERROR_MSG, "您不是该社区成员");
        }

        Integer communityJoinNum = communityUserMapper.getJoinNum(tenantId, communityId);

        if (communityUser.getUserType() == 2 && communityJoinNum > 1) {
            return R.fail(HttpStatus.SHOW_ERROR_MSG, "社区还有成员，无法退出");
        }

        baseMapper.quitCommunity(tenantId, communityId, userId);

        if (communityJoinNum == 1) {
            baseMapper.deleteCommunity(tenantId, communityId);
        } else {
            redisCache.deleteObject("communityJoinNumMap");
        }

        return R.ok();
    }

    @Override
    public R<Object> isJoinCommunity(JoinCommunityRes joinCommunityRes) {
        int isJoinCommunity = communityUserMapper.isJoinCommunity(joinCommunityRes.getTenantId(), joinCommunityRes.getCommunityId(), SecurityUtils.getUserId());
        return R.ok(isJoinCommunity);
    }

    @Override
    public CommunityDetailVo getCommunityDetail(Long tenantId, Long communityId) {
//        Community community = baseMapper.selectById(communityId);

        Community community = baseMapper.getCommunity(tenantId, communityId);

        CommunityDetailVo communityDetailVo = BeanUtil.toBean(community, CommunityDetailVo.class);

        communityDetailVo.setUserNum(getCommunityJoinNum(communityId));
        communityDetailVo.setUpdateNum(getCommunityPublishNum(communityId));


        // 当前时间和创建时间差
        LocalDate currentLocalDate = LocalDate.now(ZoneId.systemDefault());
        LocalDate createLocalDate = community.getCreateTime().toInstant()
                .atZone(ZoneId.systemDefault())
                .toLocalDate();
        long daysBetween = ChronoUnit.DAYS.between(createLocalDate, currentLocalDate);

        communityDetailVo.setCreateDay(daysBetween);

        Publish lastPublish = publishService.getLastPublish(tenantId, communityId);
        if (Objects.nonNull(lastPublish)) {
            communityDetailVo.setLastUpdateTime(lastPublish.getCreateTime());
        } else {
            communityDetailVo.setLastUpdateTime(community.getCreateTime());
        }

        List<String> avatarList = communityUserMapper.getCommunityUserAvatar(tenantId, communityId);
        communityDetailVo.setAvatarList(avatarList);

        // 获取当前用户到期时间
        communityDetailVo.setExpireTime(communityUserMapper.getExpireTime(tenantId, communityId, SecurityUtils.getUserId()));


        return communityDetailVo;
    }

    @Override
    public void editCommunity(EditCommunityRes editCommunityRes) {
        Community community = BeanUtil.toBean(editCommunityRes, Community.class);
        baseMapper.updateById(community);
    }

    private TableDataInfo getCommunityVoTableDataInfo(List<Community> communityList, Long total) {

        List<Community> myJoinCommunityList = baseMapper.getMyJoinCommunity(new Page<>(1, 100),
                SecurityUtils.getUserId(),
                JoinCommunityListPageRes.builder().isMyCreate(1).build());

        Map<Long, Community> myJoinCommunityMap = myJoinCommunityList.stream()
                .collect(Collectors.toMap(Community::getId, Function.identity()));


        List<CommunityVo> communityVoList = new ArrayList<>();

        LocalDate currentLocalDate = LocalDate.now(ZoneId.systemDefault());
        for (Community community : communityList) {
            CommunityVo communityVo = BeanUtil.toBean(community, CommunityVo.class);
            // 当前时间和创建时间差
            Date createTime = community.getCreateTime();
            LocalDate createLocalDate = createTime.toInstant()
                    .atZone(ZoneId.systemDefault())
                    .toLocalDate();
            long daysBetween = ChronoUnit.DAYS.between(createLocalDate, currentLocalDate);
            SysUser sysUser = sysUserService.selectUserById(community.getTenantId());
            CommunityUser communityUser = communityUserMapper.selectCommunityUser(community.getTenantId(), community.getId(), SecurityUtils.getUserId());
            if (Objects.nonNull(communityUser)) {
                communityVo.setUserType(communityUser.getUserType());
            }
            communityVo.setUserId(community.getTenantId());
            communityVo.setAvatar(sysUser.getAvatar());
            communityVo.setNickName(sysUser.getNickName());
            communityVo.setCreateDay(daysBetween);
            communityVo.setJoinNum(this.getCommunityJoinNum(community.getId()));
//            communityVo.setPublishNum(this.getCommunityPublishNum(community.getId()));
            if (myJoinCommunityMap.get(community.getId()) != null) {
                communityVo.setIsJoin(1);
            } else {
                communityVo.setIsJoin(0);
            }


            communityVoList.add(communityVo);
        }

        TableDataInfo tableDataInfo = new TableDataInfo();
        tableDataInfo.setRows(communityVoList);
        tableDataInfo.setTotal(total);
        tableDataInfo.setCode(HttpStatus.SUCCESS);
        tableDataInfo.setMsg("查询成功");

        return tableDataInfo;
    }


    private int getCommunityJoinNum(Long communityId) {
        // 查询社区加入人数，以map形式返回，key为社区id，value为加入人数
        Map<String, Object> communityJoinNumMap = redisCache.getCacheMap("communityJoinNumMap");
        if (communityJoinNumMap.isEmpty()) {
            Map<Long, Map<String, Object>> joinMap = baseMapper.selectCommunityJoinNum();
            if (joinMap != null && !joinMap.isEmpty()) {
                joinMap.forEach((key, value) -> {
                    communityJoinNumMap.put(key.toString(), Integer.valueOf(value.get("joinNum").toString()));
                });
                redisCache.setCacheMap("communityJoinNumMap", communityJoinNumMap);
            } else {
                redisCache.setCacheMap("communityJoinNumMap", new HashMap<>());
            }
            redisCache.expire("communityJoinNumMap", 1, TimeUnit.HOURS);
        }
        return Integer.parseInt(communityJoinNumMap.getOrDefault(communityId.toString(), 0).toString());

    }

    private int getCommunityPublishNum(Long communityId) {
        // 查询社区发布数，以map形式返回，key为社区id，value为发布数
        Map<String, Object> communityPublishNumMap = redisCache.getCacheMap("communityPublishNumMap");
        if (communityPublishNumMap.isEmpty()) {
            Map<Long, Map<String, Object>> publishMap = baseMapper.selectCommunityPublishNum();
            if (publishMap != null && !publishMap.isEmpty()) {
                publishMap.forEach((key, value) -> {
                    communityPublishNumMap.put(key.toString(), Integer.valueOf(value.get("publishNum").toString()));
                });
                redisCache.setCacheMap("communityPublishNumMap", communityPublishNumMap);
            } else {
                redisCache.setCacheMap("communityPublishNumMap", new HashMap<>());
            }
            redisCache.expire("communityPublishNumMap", 1, TimeUnit.HOURS);
        }
        return Integer.parseInt(communityPublishNumMap.getOrDefault(communityId.toString(), 0).toString());

    }


}
