
package com.tmerclub.cloud.seckill.controller.admin;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import com.tmerclub.cloud.api.platform.dto.OfflineHandleEventDTO;
import com.tmerclub.cloud.api.platform.vo.OfflineHandleEventVO;
import com.tmerclub.cloud.api.product.feign.SpuFeignClient;
import com.tmerclub.cloud.common.constant.Constant;
import com.tmerclub.cloud.common.constant.StatusEnum;
import com.tmerclub.cloud.common.database.dto.PageDTO;
import com.tmerclub.cloud.common.database.vo.PageVO;
import com.tmerclub.cloud.common.exception.LuckException;
import com.tmerclub.cloud.common.product.dto.ProductSearchDTO;
import com.tmerclub.cloud.common.product.vo.SpuVO;
import com.tmerclub.cloud.common.response.ResponseEnum;
import com.tmerclub.cloud.common.response.ServerResponseEntity;
import com.tmerclub.cloud.common.security.AuthUserContext;
import com.tmerclub.cloud.common.util.BeanUtil;
import com.tmerclub.cloud.seckill.dto.SeckillDTO;
import com.tmerclub.cloud.seckill.dto.SeckillSkuDTO;
import com.tmerclub.cloud.seckill.service.SeckillService;
import com.tmerclub.cloud.seckill.service.SeckillSkuService;
import com.tmerclub.cloud.seckill.vo.*;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.validation.Valid;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.bind.annotation.*;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;


/**
 * 秒杀信息
 *
 * @author tmerclub
 * @date 2019-08-28 09:36:59
 */
@RestController("adminSeckillController")
@RequestMapping("/mp/seckill")
@Tag(name = "秒杀管理")
public class SeckillController {

    @Autowired
    private SeckillService seckillService;
    @Autowired
    private SeckillSkuService seckillSkuService;
    @DubboReference
    private SpuFeignClient spuFeignClient;

    @GetMapping("/seckillList")
    @Operation(summary = "显示最近的秒杀信息列表", description = "显示最近的秒杀信息列表，type字段，0:为即将开场，1：已经开场,specTime时间搜索")
    public ServerResponseEntity<PageVO<SeckillAdminVO>> seckillList(@Valid PageDTO pageDTO, @RequestParam("type") Integer type,
                                                                    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") @RequestParam(value = "specTime", required = false) Long specTime) {
        Long shopId = AuthUserContext.get().getTenantId();
        PageVO<SeckillAdminVO> adminVOList = seckillService.listByShopId(pageDTO, shopId, type, specTime);
        return ServerResponseEntity.success(adminVOList);
    }

    @GetMapping("/endSeckillList")
    @Operation(summary = "显示已经结束的秒杀信息列表", description = "显示已经结束的秒杀信息列表,specTime时间搜索")
    public ServerResponseEntity<PageVO<SeckillAdminVO>> endSeckillList(@Valid PageDTO pageDTO, @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") @RequestParam(value = "specTime", required = false) Long specTime) {
        Long shopId = AuthUserContext.get().getTenantId();
        PageVO<SeckillAdminVO> adminVOList = seckillService.listEndSeckillByShopId(pageDTO, shopId, specTime);
        return ServerResponseEntity.success(adminVOList);
    }

    @GetMapping("/seckillSpuByTimeList")
    @Operation(summary = "根据时间、商品名称返回秒杀商品信息列表", description = "显示最近一个月秒杀信息列表")
    public ServerResponseEntity<PageVO<SeckillSpuVO>> seckillSpuByTimeList(@RequestParam("startTimestamp") Long startTimestamp,
                                                                           PageDTO pageDTO, ProductSearchDTO productSearch) {
        if (!Objects.equals(Constant.PLATFORM_SHOP_ID, AuthUserContext.get().getTenantId())) {
            productSearch.setShopId(AuthUserContext.get().getTenantId());
        }
        PageVO<SeckillSpuVO> adminVOList = seckillService.listSeckillSpuByTime(pageDTO, startTimestamp, productSearch);
        return ServerResponseEntity.success(adminVOList);
    }

    /**
     * 通过id查询秒杀信息
     *
     * @param seckillId id
     * @return 单个数据
     */
    @GetMapping
    @Operation(summary = "通过id查询秒杀信息", description = "通过id查询秒杀信息")
    public ServerResponseEntity<SeckillVO> getById(@RequestParam("seckillId") Long seckillId) {
        SeckillVO seckillVO = seckillService.getBySeckillId(seckillId);
        List<SeckillSkuVO> seckillSkuList = seckillSkuService.listSeckillSkuBySeckillId(seckillId);
        long now = System.currentTimeMillis();
        if (Objects.equals(seckillVO.getStatus(), StatusEnum.ENABLE.value()) && seckillVO.getStartTime().getTime() < now && seckillVO.getEndTime().getTime() > now) {
            // 活动正在进行中的库存查询
            Integer totalStock = 0;
            for (SeckillSkuVO seckillSkuVO : seckillSkuList) {
                Integer skuStock = 0;
                List<Long> stockPointIds = seckillSkuVO.getSeckillStockPointList().stream().map(SeckillStockPointSkuVO::getStockPointId).collect(Collectors.toList());
                Map<Long, Integer> stockMap = seckillSkuService.getPointStockBySeckillSkuId(seckillSkuVO.getSeckillId(),seckillSkuVO.getSkuId(), stockPointIds);
                for (SeckillStockPointSkuVO pointSkuVO : seckillSkuVO.getSeckillStockPointList()) {
                    Integer stock = stockMap.get(pointSkuVO.getStockPointId());
                    pointSkuVO.setStock(stock);
                    skuStock += stock;
                }
                seckillSkuVO.setSeckillStocks(skuStock);
                totalStock += skuStock;
            }
            seckillVO.setSeckillTotalStocks(totalStock);
        }
        SpuVO spuVO = spuFeignClient.getSpuAndSkuBySpuId(seckillVO.getSpuId()).getData();
        seckillVO.setSpuVO(spuVO);
        seckillVO.setSkuList(spuVO.getSkus());
        seckillVO.setSeckillSkuList(seckillSkuList);
        return ServerResponseEntity.success(seckillVO);
    }

    /**
     * 新增秒杀信息
     *
     * @return 是否新增成功
     */
    @PostMapping
    @Operation(summary = "新增秒杀信息", description = "新增秒杀信息")
    public ServerResponseEntity<Void> save(@RequestBody @Valid SeckillDTO seckillDTO) {
        SeckillVO seckill = BeanUtil.map(seckillDTO, SeckillVO.class);
        // 处理时间
        Date startTime = new Date(seckillDTO.getStartTimestamps());
        Date endTime = DateUtil.offsetHour(startTime, 2);
        seckill.setStartTime(startTime);
        seckill.setEndTime(endTime);
        Long shopId = AuthUserContext.get().getTenantId();
        List<SpuVO> spuList = spuFeignClient.listCanSeckillProd(seckillDTO.getSpuId(), shopId).getData();
        if (CollectionUtil.isEmpty(spuList)) {
            // 商品无法参与秒杀活动
            throw new LuckException("商品无法参与秒杀活动");
        }
        // 当前小时
        int nowHour = DateUtil.hour(new Date(), true);
        if (DateUtil.isSameDay(new Date(), startTime) && seckillDTO.getSelectedLot() <= nowHour + 1) {
            // 商品无法参与秒杀活动
            throw new LuckException("不能参与离开场不足一个小时的秒杀活动！");
        }
        List<SeckillSkuDTO> seckillSkuList = seckillDTO.getSeckillSkuList();
        Integer seckillTotalStocks = 0;
        long seckillPrice = Long.MAX_VALUE;
        for (SeckillSkuDTO seckillSku : seckillSkuList) {

            seckillTotalStocks += seckillSku.getSeckillStocks();

            seckillPrice = Math.min(seckillPrice, seckillSku.getSeckillPrice());
        }
        // 库存
        seckill.setSeckillOriginStocks(seckillTotalStocks);
        seckill.setSeckillTotalStocks(seckillTotalStocks);
        // 配置店铺id
        seckill.setShopId(AuthUserContext.get().getTenantId());
        seckill.setSpuId(seckillDTO.getSpuId());
        seckill.setSeckillPrice(seckillPrice);
        seckillService.saveSeckillAndItems(seckill, seckillSkuList);
        seckillSkuService.removeSeckillSkuCacheBySeckillId(seckill.getSeckillId());
        seckillService.removeSeckillCacheById(seckill.getSeckillId());
        return ServerResponseEntity.success();
    }

    /**
     * 使秒杀商品失效
     *
     * @param seckillId 秒杀信息
     * @return 是否失效成功
     */
    @PutMapping("/invalid/{seckillId}")
    @Operation(summary = "使秒杀商品失效", description = "使秒杀商品失效")
    public ServerResponseEntity<Void> invalidById(@PathVariable Long seckillId) {
        SeckillVO seckill = seckillService.getBySeckillId(seckillId);
        Long shopId = AuthUserContext.get().getTenantId();
        if (seckill == null) {
            throw new LuckException("未找到此活动，请稍后重试");
        }
        if (!Objects.equals(shopId, seckill.getShopId())) {
            throw new LuckException(ResponseEnum.UNAUTHORIZED);
        }
        if (!Objects.equals(seckill.getStatus(), StatusEnum.ENABLE.value())) {
            throw new LuckException(ResponseEnum.DATA_ERROR);
        }
        seckillService.invalidById(seckill.getSeckillId(), seckill.getSpuId());
        seckillSkuService.handSeckillPointSku(seckill);
        seckillSkuService.removeSeckillSkuCacheBySeckillId(seckill.getSeckillId());
        seckillService.removeSeckillCacheById(seckill.getSeckillId());
        return ServerResponseEntity.success();
    }

    /**
     * 通过id删除秒杀信息
     *
     * @param seckillId id
     * @return 是否删除成功
     */
    @DeleteMapping
    @Operation(summary = "通过id删除秒杀信息", description = "通过id删除秒杀信息")
    public ServerResponseEntity<Void> removeById(@RequestParam("seckillId") Long seckillId) {
        SeckillVO seckill = seckillService.getBySeckillId(seckillId);

        if (!Objects.equals(StatusEnum.DISABLE.value(), seckill.getStatus())) {
            // 秒杀活动未关闭，无法删除
            throw new LuckException("秒杀活动未关闭，无法删除");
        }
        seckill.setIsDelete(1);
        seckillService.updateById(seckill);
        seckillSkuService.removeSeckillSkuCacheBySeckillId(seckill.getSeckillId());
        return ServerResponseEntity.success();
    }

    @GetMapping("/getOfflineHandleEvent/{seckillId}")
    @Operation(summary = "获取最新下线的事件", description = "获取最新下线的事件")
    public ServerResponseEntity<OfflineHandleEventVO> getOfflineHandleEvent(@PathVariable Long seckillId) {
        return ServerResponseEntity.success(seckillService.getOfflineHandleEvent(seckillId));
    }

    @PostMapping("/offline")
    @Operation(summary = "下线秒杀活动", description = "下线秒杀活动")
    public ServerResponseEntity<Void> offline(@RequestBody OfflineHandleEventDTO offlineHandleEventDto) {
        if (!Objects.equals(Constant.PLATFORM_SHOP_ID, AuthUserContext.get().getTenantId())) {
            throw new LuckException(ResponseEnum.UNAUTHORIZED);
        }
        SeckillVO seckillVO = seckillService.getBySeckillId(offlineHandleEventDto.getHandleId());
        if (Objects.isNull(seckillVO)) {
            throw new LuckException(ResponseEnum.DATA_ERROR);
        }
        seckillService.offline(offlineHandleEventDto, seckillVO.getSpuId());
        seckillService.removeSeckillCacheById(offlineHandleEventDto.getHandleId());
        seckillSkuService.removeSeckillSkuCacheBySeckillId(offlineHandleEventDto.getHandleId());
        return ServerResponseEntity.success();
    }

    @PostMapping("/audit")
    @Operation(summary = "审核活动", description = "审核活动")
    public ServerResponseEntity<Void> audit(@RequestBody OfflineHandleEventDTO offlineHandleEventDto) {
        if (!Objects.equals(Constant.PLATFORM_SHOP_ID, AuthUserContext.get().getTenantId())) {
            throw new LuckException(ResponseEnum.UNAUTHORIZED);
        }
        seckillService.audit(offlineHandleEventDto);
        seckillService.removeSeckillCacheById(offlineHandleEventDto.getHandleId());
        seckillSkuService.removeSeckillSkuCacheBySeckillId(offlineHandleEventDto.getHandleId());
        return ServerResponseEntity.success();
    }

    @PostMapping("/auditApply")
    @Operation(summary = "违规活动提交审核", description = "违规活动提交审核")
    public ServerResponseEntity<Void> auditApply(@RequestBody OfflineHandleEventDTO offlineHandleEventDto) {
        seckillService.auditApply(offlineHandleEventDto);
        seckillService.removeSeckillCacheById(offlineHandleEventDto.getHandleId());
        seckillSkuService.removeSeckillSkuCacheBySeckillId(offlineHandleEventDto.getHandleId());
        return ServerResponseEntity.success();
    }

    @GetMapping("/getJoinSeckillMerchantNum")
    @Operation(summary = "获取正在参与秒杀活动的商家数量", description = "获取正在参与秒杀活动的商家数量")
    public ServerResponseEntity<Integer> getJoinSeckillMerchantNum() {
        if (!Objects.equals(AuthUserContext.get().getTenantId(), Constant.PLATFORM_SHOP_ID)) {
            throw new LuckException(ResponseEnum.UNAUTHORIZED);
        }
        Integer num = seckillService.getJoinSeckillMerchantNum();
        return ServerResponseEntity.success(num);
    }
}
