package com.haha.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.haha.common.constant.CommonConstants;
import com.haha.common.enums.ApplyScopeEnum;
import com.haha.common.enums.CommonStatus;
import com.haha.common.enums.CouponTypeEnum;
import com.haha.common.enums.ValidTypeEnum;
import com.haha.common.exception.BusinessException;
import com.haha.common.vo.StatusLabel;
import com.haha.entity.CouponProduct;
import com.haha.entity.CouponShop;
import com.haha.entity.CouponTemplate;
import com.haha.entity.dto.CouponCreateDTO;
import com.haha.entity.dto.CouponQueryDTO;
import com.haha.mapper.CouponProductMapper;
import com.haha.mapper.CouponShopMapper;
import com.haha.mapper.CouponTemplateMapper;
import com.haha.mapper.UserCouponMapper;
import com.haha.service.CouponTemplateService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
@RequiredArgsConstructor
public class CouponTemplateServiceImpl extends ServiceImpl<CouponTemplateMapper, CouponTemplate> implements CouponTemplateService {

    private final CouponTemplateMapper templateMapper;
    private final CouponShopMapper couponShopMapper;
    private final CouponProductMapper couponProductMapper;
    private final UserCouponMapper userCouponMapper;

    @Override
    public IPage<CouponTemplate> getPage(CouponQueryDTO queryDTO) {
        queryDTO.validate();
        Page<CouponTemplate> page = new Page<>(queryDTO.getPage(), queryDTO.getPageSize());

        LambdaQueryWrapper<CouponTemplate> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(StringUtils.hasText(queryDTO.getCouponName()), CouponTemplate::getCouponName, queryDTO.getCouponName());
        wrapper.eq(queryDTO.getCouponType() != null, CouponTemplate::getCouponType, queryDTO.getCouponType());
        wrapper.eq(queryDTO.getStatus() != null, CouponTemplate::getStatus, queryDTO.getStatus());
        wrapper.eq(StringUtils.hasText(queryDTO.getReceiveType()), CouponTemplate::getReceiveType, queryDTO.getReceiveType());
        wrapper.eq(queryDTO.getActivityId() != null, CouponTemplate::getActivityId, queryDTO.getActivityId());
        wrapper.eq(queryDTO.getCreatorId() != null, CouponTemplate::getCreatorId, queryDTO.getCreatorId());
        wrapper.ge(queryDTO.getValidStartTimeBegin() != null, CouponTemplate::getValidStartTime, queryDTO.getValidStartTimeBegin());
        wrapper.le(queryDTO.getValidStartTimeEnd() != null, CouponTemplate::getValidStartTime, queryDTO.getValidStartTimeEnd());
        wrapper.eq(CouponTemplate::getDeleted, CommonConstants.NOT_DELETED);
        wrapper.orderByDesc(CouponTemplate::getCreateTime);

        IPage<CouponTemplate> result = this.page(page, wrapper);
        result.getRecords().forEach(this::fillLabels);

        return result;
    }

    @Override
    public CouponTemplate getDetail(Long id) {
        CouponTemplate template = this.getById(id);
        if (template == null || template.getDeleted() == CommonConstants.DELETED) {
            throw new BusinessException(404, "优惠券模板不存在");
        }
        fillLabels(template);
        return template;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public CouponTemplate create(CouponCreateDTO dto, Long creatorId, String creatorName) {
        validateCouponData(dto);

        CouponTemplate template = new CouponTemplate();
        template.setCouponName(dto.getCouponName());
        template.setCouponType(dto.getCouponType());
        template.setCouponDesc(dto.getCouponDesc());
        template.setDiscountValue(dto.getDiscountValue());
        template.setMinAmount(dto.getMinAmount() != null ? dto.getMinAmount() : BigDecimal.ZERO);
        template.setMaxDiscount(dto.getMaxDiscount());
        template.setTotalCount(dto.getTotalCount());
        template.setRemainCount(dto.getTotalCount());
        template.setReceiveLimit(dto.getReceiveLimit() != null ? dto.getReceiveLimit() : 1);
        template.setValidType(dto.getValidType());
        template.setValidStartTime(dto.getValidStartTime());
        template.setValidEndTime(dto.getValidEndTime());
        template.setValidDays(dto.getValidDays());
        template.setApplyScope(dto.getApplyScope());
        template.setProductScope(dto.getProductScope());
        template.setActivityId(dto.getActivityId());
        template.setReceiveType(dto.getReceiveType() != null ? dto.getReceiveType() : "Release");
        template.setStatus(CommonStatus.ENABLED.getCode());
        template.setCreatorId(creatorId);
        template.setCreatorName(creatorName);
        template.setDeleted(CommonConstants.NOT_DELETED);

        this.save(template);

        saveCouponShops(template.getId(), dto.getShopIds(), dto.getApplyScope());
        saveCouponProducts(template.getId(), dto.getProductIds(), dto.getProductScope());

        log.info("创建优惠券模板成功: id={}, name={}", template.getId(), template.getCouponName());
        return template;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public CouponTemplate update(CouponCreateDTO dto) {
        return null;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateStatus(Long id, Integer status) {
        CouponTemplate template = this.getById(id);
        if (template == null || template.getDeleted() == CommonConstants.DELETED) {
            throw new BusinessException(404, "优惠券模板不存在");
        }

        boolean result = templateMapper.updateStatus(id, status) > 0;

        if (result) {
            log.info("更新优惠券状态成功: id={}, status={}", id, status);
        }
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteTemplate(Long id) {
        CouponTemplate template = this.getById(id);
        if (template == null) {
            throw new BusinessException(404, "优惠券模板不存在");
        }

        template.setDeleted(CommonConstants.DELETED);
        boolean result = this.updateById(template);

        if (result) {
            couponShopMapper.deleteByTemplateId(id);
            couponProductMapper.deleteByTemplateId(id);
            log.info("删除优惠券模板成功: id={}", id);
        }
        return result;
    }

    @Override
    public List<CouponTemplate> getAvailableTemplates() {
        return templateMapper.selectAvailableTemplates();
    }

    @Override
    public List<CouponTemplate> getAvailableTemplatesWithStatus(Long userId) {
        List<CouponTemplate> templates = templateMapper.selectAvailableTemplates();
        templates.forEach(template -> {
            int receivedCount = userCouponMapper.countByTemplateAndUser(template.getId(), userId);
            template.setAlreadyReceived(receivedCount > 0);
        });
        log.info("[优惠券] 可领取优惠券数量: {}", templates.size());
        return templates;
    }

    @Override
    public boolean decreaseRemainCount(Long id) {
        return templateMapper.decreaseRemainCount(id) > 0;
    }

    @Override
    public boolean increaseRemainCount(Long id) {
        return templateMapper.increaseRemainCount(id) > 0;
    }

    @Override
    public List<Long> getCouponShopIds(Long templateId) {
        return couponShopMapper.selectShopIdsByTemplateId(templateId);
    }

    @Override
    public List<Long> getCouponProductIds(Long templateId) {
        return couponProductMapper.selectProductIdsByTemplateId(templateId);
    }

    @Override
    public Map<String, Object> getStatistics(Long templateId) {
        Map<String, Object> stats = new HashMap<>();
        stats.put("totalTemplates", templateMapper.countTotal());
        stats.put("totalRemainCount", templateMapper.sumRemainCount());
        return stats;
    }

    private void validateCouponData(CouponCreateDTO dto) {
        if (dto.getCouponType() == null) {
            throw new BusinessException(400, "优惠券类型不能为空");
        }
        if (dto.getDiscountValue() == null || dto.getDiscountValue().compareTo(BigDecimal.ZERO) <= 0) {
            throw new BusinessException(400, "优惠值必须大于0");
        }
        if (dto.getTotalCount() == null || dto.getTotalCount() <= 0) {
            throw new BusinessException(400, "发放总量必须大于0");
        }
        if (dto.getValidType() == null) {
            throw new BusinessException(400, "有效期类型不能为空");
        }
        if (dto.getValidType() == ValidTypeEnum.FIXED_TIME.getCode()) {
            if (dto.getValidStartTime() == null || dto.getValidEndTime() == null) {
                throw new BusinessException(400, "固定时间有效期必须指定开始和结束时间");
            }
            if (dto.getValidStartTime().isAfter(dto.getValidEndTime())) {
                throw new BusinessException(400, "有效期开始时间不能晚于结束时间");
            }
        } else if (dto.getValidType() == ValidTypeEnum.RELATIVE_TIME.getCode()) {
            if (dto.getValidDays() == null || dto.getValidDays() <= 0) {
                throw new BusinessException(400, "相对时间有效期必须指定有效天数");
            }
        }
        if (dto.getCouponType() == CouponTypeEnum.DISCOUNT.getCode()) {
            if (dto.getDiscountValue().compareTo(BigDecimal.ONE) < 0 || dto.getDiscountValue().compareTo(BigDecimal.TEN) > 0) {
                throw new BusinessException(400, "折扣比例必须在1-10之间");
            }
        }
    }

    private void saveCouponShops(Long templateId, List<Long> shopIds, Integer applyScope) {
        if (applyScope != null && applyScope == ApplyScopeEnum.SPECIFIED_SHOP.getCode()
                && shopIds != null && !shopIds.isEmpty()) {
            for (Long shopId : shopIds) {
                CouponShop couponShop = new CouponShop();
                couponShop.setTemplateId(templateId);
                couponShop.setShopId(shopId);
                couponShopMapper.insert(couponShop);
            }
        }
    }

    private void saveCouponProducts(Long templateId, List<Long> productIds, Integer productScope) {
        if (productScope != null && productScope == ApplyScopeEnum.SPECIFIED_SHOP.getCode()
                && productIds != null && !productIds.isEmpty()) {
            for (Long productId : productIds) {
                CouponProduct couponProduct = new CouponProduct();
                couponProduct.setTemplateId(templateId);
                couponProduct.setProductId(productId);
                couponProductMapper.insert(couponProduct);
            }
        }
    }

    private void fillLabels(CouponTemplate template) {
        StatusLabel typeLabel = CouponTypeEnum.getLabelByCode(template.getCouponType());
        template.setTypeLabel(typeLabel.getLabel());

        StatusLabel validTypeLabel = ValidTypeEnum.getLabelByCode(template.getValidType());
        template.setValidTypeLabel(validTypeLabel.getLabel());

        StatusLabel statusLabel = CommonStatus.getLabelByCode(template.getStatus());
        template.setStatusLabel(statusLabel.getLabel());
        template.setStatusColor(statusLabel.getColor());
    }
}
