/*
 *      Copyright (c) 2018-2028, Chill Zhuang All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 *  Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the dreamlu.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: Chill 庄骞 (smallchill@163.com)
 */
package org.springblade.modules.groupon.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springblade.common.base.BaseEntity;
import org.springblade.common.enums.AuditStatusEnum;
import org.springblade.common.enums.StatusEnum;
import org.springblade.common.enums.YesOrNoEnum;
import org.springblade.common.utils.DistanceUtils;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.tool.api.R;
import org.springblade.modules.api.response.GroupStatisResponse;
import org.springblade.modules.finance.entity.Order;
import org.springblade.modules.finance.entity.OrderGroupon;
import org.springblade.modules.finance.service.IOrderGrouponService;
import org.springblade.modules.finance.service.IOrderService;
import org.springblade.modules.groupon.entity.*;
import org.springblade.modules.groupon.service.*;
import org.springblade.modules.groupon.vo.GrouponGoodsVO;
import org.springblade.modules.groupon.vo.GrouponVO;
import org.springblade.modules.groupon.mapper.GrouponMapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springblade.modules.groupon.vo.SelfTakeVO;
import org.springblade.modules.groupon.wrapper.GrouponWrapper;
import org.springblade.modules.mall.entity.GoodsInfo;
import org.springblade.modules.mall.vo.GoodsInfoVO;
import org.springblade.modules.mall.wrapper.GoodsInfoWrapper;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.temporal.TemporalField;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 团购表 服务实现类
 *
 * @author BladeX
 * @since 2023-06-02
 */
@Service
public class GrouponServiceImpl extends ServiceImpl<GrouponMapper, Groupon> implements IGrouponService {

	@Resource
	private IGrouponImageService grouponImageService;
	@Resource
	private IGrouponGoodsService grouponGoodsService;
	@Resource
	private IGrouponUserService grouponUserService;
	@Resource
	private ISelfTakeService selfTakeService;
	@Resource
	private IGrouponSelfTakeService grouponSelfTakeService;
	@Resource
	private IOrderGrouponService orderGrouponService;
	@Resource
	private IOrderService orderService;

	@Override
	public IPage<GrouponVO> selectGrouponPage(IPage<GrouponVO> page, GrouponVO groupon) {
		return page.setRecords(baseMapper.selectGrouponPage(page, groupon));
	}

	@Override
	public IPage<GrouponVO> latestGroupon(String address, Double longitude, Double latitude, IPage<GrouponVO> page) {
		LocalDateTime now = LocalDateTime.now();
		IPage<GrouponVO> iPage = page.setRecords(baseMapper.selectGroupon(page, 1, address));
		return this.convert(longitude, latitude, iPage, now);
	}

	/**
	 * 获取发布时间描述
	 * @param start
	 * @param end
	 * @return
	 */
	private String getPublishTimeDesc(LocalDateTime start, LocalDateTime end) {
		Duration between = LocalDateTimeUtil.between(start, end);
		long days = between.toDays();
		long hour = (between.toHours() - (days * 24));
		long minutes = between.toMinutes() - (between.toHours() * 60);
		return String.format("%s天%s小时%s分钟前", days, hour, minutes);
	}

	/**
	 * 获取最近自提点
	 * @param longitude 经度
	 * @param latitude 纬度
	 * @param selfTakes 自提点集合
	 * @return
	 */
	private SelfTakeVO getRecentlySelfTake(Double longitude, Double latitude, List<SelfTakeVO> selfTakes) {
		for (SelfTakeVO selfTake : selfTakes) {
			if (longitude == null || latitude == null) {
				selfTake.setDistance(0);
			} else {
				double distance = DistanceUtils.getDistance(longitude, latitude, selfTake.getLongitude(), selfTake.getLatitude());
				selfTake.setDistance(distance);
			}
		}
		selfTakes.sort((o1, o2) -> (int) (o1.getDistance() - o2.getDistance()));
		return selfTakes.get(0);
	}

	@Override
	public IPage<GrouponVO> historyGroupon(String address, Double longitude, Double latitude, IPage<GrouponVO> page) {
		LocalDateTime now = LocalDateTime.now();
		IPage<GrouponVO> iPage = page.setRecords(baseMapper.selectGroupon(page, 2, address));
		return this.convert(longitude, latitude, iPage, now);
	}


	private IPage<GrouponVO> convert(Double longitude, Double latitude, IPage<GrouponVO> pages, LocalDateTime now ) {
		if (CollUtil.isNotEmpty(pages.getRecords())) {
			List<GrouponVO> grouponVOS = pages.getRecords();
			List<Long> groupIds = grouponVOS.stream().map(Groupon::getId).collect(Collectors.toList());
			// 查询团购轮播图
			Map<Long, List<String>> imageMaps = grouponImageService.getByGroupIds(groupIds, 1);
			// 查询商品图片
			Map<Long, List<GrouponGoodsVO>> goodsMap = grouponGoodsService.getGoodsCover(groupIds);
			// 查询参团人员
			Map<Long, List<GrouponUser>> userMaps = grouponUserService.getByGroupIds(groupIds);
			// 查询自提点
			Map<Long, List<SelfTakeVO>> selfTakeMaps = selfTakeService.getByGroupIds(groupIds);
			for (GrouponVO g : grouponVOS) {
				g.setIsStart(now.isAfter(g.getGrouponStartTime()));
				List<GrouponGoodsVO> goodsVOS = goodsMap.get(g.getId());
				if (CollUtil.isNotEmpty(goodsVOS)) {
					g.setMaxPrice(goodsVOS.get(goodsVOS.size() - 1).getPrice());
					g.setMinPrice(goodsVOS.get(0).getPrice());
					g.setGoodsImage(goodsVOS.stream().map(GrouponGoodsVO::getGoodsCover).collect(Collectors.toList()));
					g.setGoodsTotal(g.getGoodsImage().size());
				}
				g.setGrouponUsers(userMaps.get(g.getId()));
				g.setSlideshow(imageMaps.get(g.getId()));
				g.setSelfTake(this.getRecentlySelfTake(longitude, latitude, selfTakeMaps.get(g.getId())));
				long seconds = LocalDateTimeUtil.between(now, g.getGrouponEndTime()).getSeconds();
				g.setSeconds(seconds);
				g.setPublishTimeDesc(this.getPublishTimeDesc(g.getGrouponStartTime(), now));
				if (!g.getIsStart()) {
					g.setSecondsStart(LocalDateTimeUtil.between(now, g.getGrouponStartTime()).getSeconds());
				}
			}
		}
		return pages;
	}


	@Override
	public GrouponVO detail(Long grouponId) {
		LocalDateTime now = LocalDateTime.now();
		Groupon groupon = getById(grouponId);
		Assert.notNull(groupon, "数据不存在");
		GrouponVO grouponVO = GrouponWrapper.build().entityVO(groupon);
		List<Long> ids = Collections.singletonList(grouponId);
		// 查询团购详情图片
		List<GrouponImage> grouponImages = grouponImageService.lambdaQuery().eq(GrouponImage::getGrouponId, grouponId).list();
		if (CollUtil.isNotEmpty(grouponImages)) {
			List<String> slideshow = grouponImages.stream().filter(e -> e.getType().equals(1)).map(GrouponImage::getUrl).collect(Collectors.toList());
			List<String> detailImage = grouponImages.stream().filter(e -> e.getType().equals(2)).map(GrouponImage::getUrl).collect(Collectors.toList());
			grouponVO.setSlideshow(slideshow);
			grouponVO.setDetailImage(detailImage);
		}
		// 查询商品
		List<GoodsInfoVO> goodsList = grouponGoodsService.getGoodsByGrouponId(grouponId);
		grouponVO.setGoodsList(goodsList);
		grouponVO.setGoodsTotal(goodsList.size());
		grouponVO.setMinPrice(goodsList.get(0).getDiscountPrice());
		grouponVO.setMaxPrice(goodsList.get(goodsList.size() - 1).getDiscountPrice());
		// 查询参团人员
		Map<Long, List<GrouponUser>> userMaps = grouponUserService.getByGroupIds(ids);
		grouponVO.setGrouponUsers(userMaps.get(grouponId));
		long seconds = LocalDateTimeUtil.between(now, grouponVO.getGrouponEndTime()).getSeconds();
		grouponVO.setSeconds(seconds);
		grouponVO.setPublishTimeDesc(this.getPublishTimeDesc(groupon.getGrouponStartTime(), now));
		grouponVO.setIsStart(now.isAfter(grouponVO.getGrouponStartTime()));
		grouponVO.setIsEnd(now.isAfter(grouponVO.getGrouponEndTime()));
		if (!grouponVO.getIsStart()) {
			grouponVO.setSecondsStart(LocalDateTimeUtil.between(now, grouponVO.getGrouponStartTime()).getSeconds());
		}
		// 更新浏览量
		groupon.setViews(groupon.getViews() + 1);
		updateById(groupon);
		return grouponVO;
	}

	@Transactional(rollbackFor = Exception.class)
	@Override
	public void publishGroupon(GrouponVO groupon) {
		Assert.notEmpty(groupon.getGrouponGoodsList(), "请添加商品");
//		for (GrouponGoods goods : groupon.getGrouponGoodsList()) {
//			if (goods.getGrouponPrice().doubleValue() <= 0.0) {
//				throw new ServiceException("团购价格设置错误");
//			}
//		}
		this.check(groupon);
		groupon.setAuditStatus(AuditStatusEnum.WAIT.getValue());
		groupon.setStatus(StatusEnum.ENABLE.getValue());
		groupon.setIsPerfect(YesOrNoEnum.NO.getValue());
		save(groupon);
		// 添加自提点
		grouponSelfTakeService.addSelfTake(groupon.getId(), groupon.getSelfTakeIds());
		grouponGoodsService.addGoods(groupon.getId(), groupon.getGrouponGoodsList());
	}

	/**
	 * 校验参数
	 * @param groupon
	 */
	@Override
	public void check(GrouponVO groupon) {
		if (groupon.getGrouponStartTime().isAfter(groupon.getGrouponEndTime())) {
			throw new ServiceException("开团开始时间不能早于结束时间");
		}
		if (groupon.getTakeStartTime().isAfter(groupon.getTakeEndTime())) {
			throw new ServiceException("提货开始时间不能早于结束时间");
		}
		if (groupon.getGrouponEndTime().isAfter(groupon.getTakeStartTime())) {
			throw new ServiceException("提货开始时间不能早于开团结束时间");
		}

	}

	@Override
	public void audit(String id, Integer auditStatus, String remark) {
		Groupon groupon = getById(id);
		Assert.notNull(groupon, "数据不存在");
		if (YesOrNoEnum.NO.getValue().equals(groupon.getIsPerfect())) {
			throw new ServiceException("请先完善信息");
		}
		groupon.setAuditStatus(auditStatus);
		groupon.setAuditTime(LocalDateTime.now());
		groupon.setAuditMessage(remark);
		updateById(groupon);
	}

	@Transactional(rollbackFor = Exception.class)
	@Override
	public void perfect(GrouponVO grouponVO) {
		Assert.notNull(grouponVO.getId(), "id不能为空");
		Assert.notNull(grouponVO.getShareImage(), "请上传团购分享图");
		Assert.notEmpty(grouponVO.getDetailImage(), "请上传详情图");
		Assert.notEmpty(grouponVO.getSlideshow(), "请上传轮播图");
		Assert.notEmpty(grouponVO.getGoodsList(), "goodsList不能为空");

		Groupon groupon = getById(grouponVO.getId());
		Assert.notNull(groupon, "团购数据不存在");

		List<GrouponGoods> list = grouponGoodsService.lambdaQuery().eq(GrouponGoods::getGrouponId, groupon.getId()).list();
		Map<Long, GoodsInfoVO> collect = grouponVO.getGoodsList().stream().collect(Collectors.toMap(BaseEntity::getId, Function.identity()));

		for (GrouponGoods grouponGoods : list) {
			GoodsInfoVO goodsInfoVO = collect.get(grouponGoods.getGoodsId());
			if (goodsInfoVO != null) {
				grouponGoods.setSort(goodsInfoVO.getSort());
				grouponGoods.setGrouponPrice(goodsInfoVO.getGrouponPrice());
			}
		}

		grouponGoodsService.updateBatchById(list);

		grouponImageService.deleteByGrouponId(grouponVO.getId());

		List<GrouponImage> imageList = new ArrayList<>();
		for (String s : grouponVO.getDetailImage()) {
			GrouponImage image = new GrouponImage();
			image.setGrouponId(grouponVO.getId());
			image.setUrl(s);
			image.setType(2);
			imageList.add(image);
		}

		for (String s : grouponVO.getSlideshow()) {
			GrouponImage image = new GrouponImage();
			image.setGrouponId(grouponVO.getId());
			image.setUrl(s);
			image.setType(1);
			imageList.add(image);
		}
		grouponImageService.saveBatch(imageList);

		groupon.setIsPerfect(YesOrNoEnum.YES.getValue());

		// 完善信息后将审核状态改为未审核
		groupon.setAuditStatus(AuditStatusEnum.WAIT.getValue());
		groupon.setShareImage(grouponVO.getShareImage());
		updateById(groupon);
	}

	@Override
	public GroupStatisResponse groupStatistics(Long userId) {
		GroupStatisResponse response = new GroupStatisResponse();
		// 查询最新团购数据
		List<Groupon> grouponList = this.lambdaQuery().eq(Groupon::getOrganizerUserId, userId).ge(Groupon::getGrouponEndTime, LocalDateTime.now()).list();
		if (CollUtil.isNotEmpty(grouponList)) {
			int sum = grouponList.stream().mapToInt(Groupon::getViews).sum();
			response.setLastNewViewTotal(sum);
			List<Long> grouponIds = grouponList.stream().map(Groupon::getId).collect(Collectors.toList());
			List<OrderGroupon> list = orderGrouponService.getByGrouponIds(grouponIds);
			if (CollUtil.isNotEmpty(list)) {
				List<Long> orderIds = list.stream().map(OrderGroupon::getOrderId).collect(Collectors.toList());
				List<Order> orders = orderService.lambdaQuery().in(Order::getId, orderIds).list();
				if (CollUtil.isNotEmpty(orders)) {
					BigDecimal total = BigDecimal.valueOf(0.00);
					for (Order order : orders) {
						total = total.add(order.getPaymentAmount());
					}
					response.setLastNewMake(total);
				}
			}
		}
		return response;
	}

	@Override
	public IPage<GrouponVO> grouponMngList(IPage page, Long userId, Integer state) {
		LocalDateTime now = LocalDateTime.now();
		LambdaQueryWrapper<Groupon> wrapper = new LambdaQueryWrapper<>();
		wrapper.eq(Groupon::getOrganizerUserId, userId);
		if (state == 1) {//申请中
			wrapper.eq(Groupon::getAuditStatus, AuditStatusEnum.WAIT.getValue());
		} else if (state == 2) {// 发布中
			wrapper.eq(Groupon::getAuditStatus, AuditStatusEnum.PASS.getValue())
					.ge(Groupon::getGrouponEndTime, now).le(Groupon::getGrouponStartTime, now);
		} else if (state == 3) {// 已拒绝
			wrapper.eq(Groupon::getAuditStatus, AuditStatusEnum.NOT_PASS.getValue());
		} else if (state == 4) {// 已结束
			wrapper.eq(Groupon::getAuditStatus, AuditStatusEnum.PASS.getValue())
					.le(Groupon::getGrouponEndTime, now);
		}
		wrapper.orderByDesc(BaseEntity::getCreateTime);
		IPage<Groupon> iPage = page(page, wrapper);
		List<GrouponVO> grouponVOS = GrouponWrapper.build().listVO(iPage.getRecords());
		for (GrouponVO record : grouponVOS) {
			record.setGrouponStateDesc(this.getGrouponStateDesc(record));
		}
		return page.setRecords(grouponVOS);
	}

	@Override
	public GrouponVO grouponMngDetail(Long grouponId) {
		Groupon groupon = getById(grouponId);
		Assert.notNull(groupon, "数据不存咋");
		GrouponVO grouponVO = GrouponWrapper.build().entityVO(groupon);
		// 查询商品
		List<GoodsInfoVO> goodsList = grouponGoodsService.getGoodsByGrouponId(grouponId);
		grouponVO.setGoodsList(goodsList);
		grouponVO.setGoodsTotal(goodsList.size());
		// 查询自提点列表
		List<SelfTakeVO> selfTakeVOS = selfTakeService.getByGrouponId(null, null, grouponId);
		grouponVO.setSelfTakeList(selfTakeVOS);
		grouponVO.setGrouponStateDesc(this.getGrouponStateDesc(grouponVO));
		return grouponVO;
	}

	@Override
	public String getGrouponPath(Long grouponId) {
		Groupon groupon = getById(grouponId);
		Assert.notNull(groupon, "团购数据不存在");
		List<GrouponSelfTake> list = grouponSelfTakeService.lambdaQuery().eq(GrouponSelfTake::getGrouponId, grouponId).list();
		Assert.notEmpty(list, "未查询团购自提点数据");
		return String.format("/pages/groupbuying_details/index?id=%s&selfTakeId=%s&organizerUserId=%s",
				groupon.getId(), list.get(0).getSelfTakeId(), groupon.getOrganizerUserId());
	}

	@Transactional(rollbackFor = Exception.class)
	@Override
	public void gen(GrouponVO groupon) {
		groupon.setAuditStatus(AuditStatusEnum.PASS.getValue());
		groupon.setStatus(StatusEnum.ENABLE.getValue());
		groupon.setIsPerfect(YesOrNoEnum.YES.getValue());
		groupon.setOrganizerUserId(1674455459210252289L);
		save(groupon);

		List<Long> selfTakeIds = new ArrayList<>();
		selfTakeIds.add(1678390374327545858L);

		List<GrouponGoods> grouponGoodsList = new ArrayList<>();
		GrouponGoods grouponGoods1 = new GrouponGoods();
		grouponGoods1.setGrouponId(groupon.getId());
		grouponGoods1.setGoodsId(1674456327253495810L);
		grouponGoods1.setGrouponPrice(BigDecimal.valueOf(0.01));
		GrouponGoods grouponGoods2 = new GrouponGoods();
		grouponGoods2.setGrouponId(groupon.getId());
		grouponGoods2.setGoodsId(1674459606215147522L);
		grouponGoods2.setGrouponPrice(BigDecimal.valueOf(0.01));
		grouponGoodsList.add(grouponGoods1);
		grouponGoodsList.add(grouponGoods2);

		// 添加自提点
		grouponSelfTakeService.addSelfTake(groupon.getId(), selfTakeIds);
		grouponGoodsService.addGoods(groupon.getId(), grouponGoodsList);

		List<GrouponImage> imageList = new ArrayList<>();
		GrouponImage image1 = new GrouponImage();
		image1.setGrouponId(groupon.getId());
		image1.setUrl("http://www.gzzzyd.com:9000/bladex-test/upload/20230801/192ba6e071a9873d7dc03a37d412f4a1.png");
		image1.setType(2);
		imageList.add(image1);
		GrouponImage image2 = new GrouponImage();
		image2.setGrouponId(groupon.getId());
		image2.setUrl("http://www.gzzzyd.com:9000/bladex-test/upload/20230801/c58eec89fe5e149455f6e12117778bce.png");
		image2.setType(1);
		imageList.add(image2);
		grouponImageService.saveBatch(imageList);
	}

	/**
	 * 获取
	 * @return
	 */
	private String getGrouponStateDesc(GrouponVO grouponVO) {
		LocalDateTime now = LocalDateTime.now();
		if (AuditStatusEnum.WAIT.getValue().equals(grouponVO.getAuditStatus())) {
			return "申请中";
		} else if (AuditStatusEnum.PASS.getValue().equals(grouponVO.getAuditStatus())) {
			if (grouponVO.getGrouponEndTime().isBefore(now)) {
				return "已结束";
			}
			return "发布中";
		} else {
			return "已拒绝";
		}
	}

}
