package com.czg.service.market.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.czg.PageQueryParam;
import com.czg.account.service.ShopInfoService;
import com.czg.exception.CzgException;
import com.czg.market.dto.MkLimitTimeDiscountDTO;
import com.czg.market.entity.MkLimitTimeDiscount;
import com.czg.market.service.MkLimitTimeDiscountService;
import com.czg.product.entity.Product;
import com.czg.product.service.ProductService;
import com.czg.service.market.mapper.MkLimitTimeDiscountMapper;
import com.czg.utils.AssertUtil;
import com.czg.utils.CzgStrUtils;
import com.czg.utils.PageUtil;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Arrays;
import java.util.List;

/**
 * 限时折扣 服务层实现。
 *
 * @author ww
 * @since 2025-10-21
 */
@Service
public class MkLimitTimeDiscountServiceImpl extends ServiceImpl<MkLimitTimeDiscountMapper, MkLimitTimeDiscount> implements MkLimitTimeDiscountService {

    @DubboReference
    private ShopInfoService shopInfoService;
    @DubboReference
    private ProductService productService;

    @Override
    public Page<MkLimitTimeDiscountDTO> getLimitTimeDiscountPage(PageQueryParam param, Long shopId) {
        Long mainShopId = shopInfoService.getMainIdByShopId(shopId);
        QueryWrapper queryWrapper = new QueryWrapper();
        queryWrapper.eq(MkLimitTimeDiscount::getIsDel, 0)
                .lt(MkLimitTimeDiscount::getValidStartTime, CzgStrUtils.getStrOrNull(param.getStartTime()))
                .le(MkLimitTimeDiscount::getValidEndTime, CzgStrUtils.getStrOrNull(param.getEndTime()))
                .orderBy(MkLimitTimeDiscount::getSort).desc()
                .orderBy(MkLimitTimeDiscount::getUpdateTime).desc();

        queryWrapper.and(q -> {
            q.eq(MkLimitTimeDiscount::getShopId, shopId).or(q1 -> {
                q1.eq(MkLimitTimeDiscount::getUseShopType, "all").eq(MkLimitTimeDiscount::getShopId, mainShopId);
            }).or(q2 -> {
                q2.eq(MkLimitTimeDiscount::getUseShopType, "custom").and("FIND_IN_SET( " + shopId + ", use_shops ) > 0");
            });
        });
        Page<MkLimitTimeDiscountDTO> page = pageAs(PageUtil.buildPage(), queryWrapper, MkLimitTimeDiscountDTO.class);
        if (mainShopId.equals(shopId)) {
            return page;
        }
        for (MkLimitTimeDiscountDTO record : page.getRecords()) {
            if (record.getFoodType() == 2 && StrUtil.isNotBlank(record.getFoods())) {
                List<String> foodIds = Arrays.stream(record.getFoods().split(","))
                        .map(String::trim)
                        .filter(StrUtil::isNotBlank)
                        .distinct()
                        .toList();
                List<String> ids = productService.listAs(QueryWrapper.create().select(Product::getId)
                        .eq(Product::getShopId, shopId).in(Product::getSyncId, foodIds), String.class);
                if (CollUtil.isEmpty(ids)) {
                    record.setFoods("");
                } else {
                    record.setFoods(String.join(",", ids));
                }
            }
        }
        return page;
    }


    @Override
    public MkLimitTimeDiscount getLimitTimeDiscountByShopId(Long shopId) {
        Long mainShopId = shopInfoService.getMainIdByShopId(shopId);
        MkLimitTimeDiscount limitTimeDiscount = mapper.selectOneByShopId(mainShopId, shopId, CzgStrUtils.getStrWeek());
        if (limitTimeDiscount != null && limitTimeDiscount.getFoodType() == 2 && StrUtil.isNotBlank(limitTimeDiscount.getFoods()) && !shopId.equals(mainShopId)) {
            List<String> foodIds = Arrays.stream(limitTimeDiscount.getFoods().split(","))
                    .map(String::trim)
                    .filter(StrUtil::isNotBlank)
                    .distinct()
                    .toList();
            List<String> ids = productService.listAs(QueryWrapper.create().select(Product::getId)
                    .eq(Product::getShopId, shopId).in(Product::getSyncId, foodIds), String.class);
            if (CollUtil.isEmpty(ids)) {
                limitTimeDiscount.setFoods("");
            } else {
                limitTimeDiscount.setFoods(String.join(",", ids));
            }
        }
        return limitTimeDiscount;
    }

    @Override
    public void addLimitTimeDiscount(MkLimitTimeDiscountDTO param) {
        AssertUtil.isBlank(param.getDiscountPriority(), "请配置折扣优先级");
        AssertUtil.isBlank(param.getUseDays(), "请配置可用周期");
        if ("only".equals(param.getUseShopType())) {
            param.setUseShops(param.getShopId().toString());
        } else if ("custom".equals(param.getUseShopType())) {
            AssertUtil.isBlank(param.getUseShops(), "请配置可用门店");
        }
        if (param.getFoodType() == 2) {
            AssertUtil.isBlank(param.getFoods(), "请配置参与商品");
        }
        validateAndInitStatus(param);
        param.setIsDel(false);
        MkLimitTimeDiscount activity = BeanUtil.toBean(param, MkLimitTimeDiscount.class);
        save(activity);
    }

    @Override
    public void updateLimitTimeDiscountById(MkLimitTimeDiscountDTO param) {
        AssertUtil.isBlank(param.getDiscountPriority(), "请配置折扣优先级");
        AssertUtil.isBlank(param.getUseDays(), "请配置可用周期");
        if ("only".equals(param.getUseShopType())) {
            param.setUseShops(param.getShopId().toString());
        } else if ("custom".equals(param.getUseShopType())) {
            AssertUtil.isBlank(param.getUseShops(), "请配置可用门店");
        }
        if (param.getFoodType() == 2) {
            AssertUtil.isBlank(param.getFoods(), "请配置参与商品");
        }
        validateAndInitStatus(param);
        param.setIsDel(false);
        MkLimitTimeDiscount limitTimeDiscount = BeanUtil.toBean(param, MkLimitTimeDiscount.class);
        updateById(limitTimeDiscount, true);
    }

    @Override
    public void deleteLimitTimeDiscount(Long id) {
        MkLimitTimeDiscount limitTimeDiscount = new MkLimitTimeDiscount();
        limitTimeDiscount.setId(id);
        limitTimeDiscount.setIsDel(true);
        updateById(limitTimeDiscount, true);
    }


    /**
     * 校验时间有效性并初始化状态
     */
    private void validateAndInitStatus(MkLimitTimeDiscountDTO param) {
        LocalDate startDate;
        LocalDate endDate;
        LocalDate currentDate = LocalDate.now();

        try {
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
            startDate = LocalDate.parse(param.getValidStartTime(), formatter);
            endDate = LocalDate.parse(param.getValidEndTime(), formatter);
        } catch (DateTimeParseException e) {
            throw new IllegalArgumentException("时间格式不正确，请使用yyyy-MM-dd格式");
        }
        // 校验开始时间不能晚于结束时间
        if (currentDate.isAfter(endDate)) {
            throw new CzgException("有效期结束时间不能早于当前时间");
        }
        // 校验开始时间不能晚于结束时间
        if (startDate.isAfter(endDate)) {
            throw new CzgException("有效期开始时间不能晚于结束时间");
        }

        // 根据时间初始化状态
        if (currentDate.isBefore(startDate)) {
            // 当前日期在开始日期之前-未开始
            param.setStatus(1);
        } else {
            // 这里先默认设置为进行中，具体由定时任务根据时段更新
            param.setStatus(2);
        }
    }
}
