package com.usky.vpp.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.usky.common.core.bean.CommonPage;
import com.usky.common.core.exception.BusinessException;
import com.usky.common.security.utils.SecurityUtils;
import com.usky.vpp.domain.VppBiddingConfig;
import com.usky.vpp.mapper.VppBiddingConfigMapper;
import com.usky.vpp.service.VppBiddingConfigService;
import com.usky.vpp.service.vo.BiddingConfigRequest;
import com.usky.vpp.service.vo.BiddingConfigVO;
import com.usky.vpp.util.VppAuditHelper;
import com.usky.vpp.util.VppBiddingConfigHelper;
import com.usky.vpp.util.VppPageHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class VppBiddingConfigServiceImpl implements VppBiddingConfigService {

    @Autowired
    private VppBiddingConfigMapper biddingConfigMapper;

    @Override
    public CommonPage<BiddingConfigVO> page(String configName,
                                              LocalDateTime effectiveStart,
                                              LocalDateTime effectiveEnd,
                                              Integer current,
                                              Integer size) {
        Map<String, Object> pageParams = new HashMap<>(2);
        pageParams.put("current", current);
        pageParams.put("size", size);
        Page<VppBiddingConfig> page = VppPageHelper.of(pageParams);
        LambdaQueryWrapper<VppBiddingConfig> wrapper = new LambdaQueryWrapper<VppBiddingConfig>()
                .eq(VppBiddingConfig::getDeleteFlag, VppAuditHelper.NOT_DELETED)
                .orderByDesc(VppBiddingConfig::getUpdateTime);
        applyTenantFilter(wrapper);

        if (StringUtils.hasText(configName)) {
            wrapper.like(VppBiddingConfig::getConfigName, configName.trim());
        }
        if (effectiveStart != null) {
            wrapper.ge(VppBiddingConfig::getEffectiveEnd, effectiveStart);
        }
        if (effectiveEnd != null) {
            wrapper.le(VppBiddingConfig::getEffectiveStart, effectiveEnd);
        }

        Page<VppBiddingConfig> result = biddingConfigMapper.selectPage(page, wrapper);
        List<BiddingConfigVO> records = result.getRecords().stream()
                .map(this::toVo)
                .collect(Collectors.toList());
        return new CommonPage<>(records, result.getTotal(), result.getCurrent(), result.getSize());
    }

    @Override
    public BiddingConfigVO get(Long id) {
        return toVo(requireConfig(id));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long create(BiddingConfigRequest request) {
        validateRequest(request);

        VppBiddingConfig config = new VppBiddingConfig();
        fillConfigFromRequest(config, request);
        VppAuditHelper.fillCreate(config);
        biddingConfigMapper.insert(config);
        return config.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(Long id, BiddingConfigRequest request) {
        VppBiddingConfig config = requireConfig(id);
        validateRequest(request);

        fillConfigFromRequest(config, request);
        VppAuditHelper.fillUpdate(config);
        biddingConfigMapper.updateById(config);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(Long id) {
        VppBiddingConfig config = requireConfig(id);
        VppAuditHelper.fillSoftDelete(config);
        biddingConfigMapper.updateById(config);
    }

    private VppBiddingConfig requireConfig(Long id) {
        VppBiddingConfig config = biddingConfigMapper.selectById(id);
        if (config == null || VppAuditHelper.isDeleted(config.getDeleteFlag())) {
            throw new BusinessException("竞价配置不存在");
        }
        return config;
    }

    private void fillConfigFromRequest(VppBiddingConfig config,
                                       BiddingConfigRequest request) {
        config.setConfigName(request.getConfigName().trim());
        config.setEffectiveStart(request.getEffectiveStart());
        config.setEffectiveEnd(request.getEffectiveEnd());
        config.setAttachmentUrl(request.getAttachmentUrl());
        config.setAttachmentName(request.getAttachmentName());
        config.setBiddingMode(request.getBiddingMode());
        config.setTypicalCoefficient(request.getTypicalCoefficient());
        config.setNoticeMinHours(request.getNoticeMinHours());
        config.setNoticeMaxHours(request.getNoticeMaxHours());
        config.setMaxPrice(request.getMaxPrice());
        config.setMinPrice(request.getMinPrice());
    }

    private BiddingConfigVO toVo(VppBiddingConfig config) {
        BiddingConfigVO vo = new BiddingConfigVO();
        vo.setId(config.getId());
        vo.setConfigName(config.getConfigName());
        vo.setEffectiveStart(config.getEffectiveStart());
        vo.setEffectiveEnd(config.getEffectiveEnd());
        vo.setEffectivePeriod(VppBiddingConfigHelper.formatEffectivePeriod(
                config.getEffectiveStart(), config.getEffectiveEnd()));
        vo.setAttachmentUrl(config.getAttachmentUrl());
        vo.setAttachmentName(config.getAttachmentName());
        vo.setBiddingMode(config.getBiddingMode());
        // vo.setBiddingModeName(VppBiddingConfigHelper.resolveBiddingModeName(config.getBiddingMode()));
        vo.setTypicalCoefficient(config.getTypicalCoefficient());
        vo.setNoticeMinHours(config.getNoticeMinHours());
        vo.setNoticeMaxHours(config.getNoticeMaxHours());
        vo.setMaxPrice(config.getMaxPrice());
        vo.setMinPrice(config.getMinPrice());
        vo.setUpdateTime(config.getUpdateTime());
        return vo;
    }

    private void validateRequest(BiddingConfigRequest request) {
        if (request == null) {
            throw new BusinessException("请求体不能为空");
        }
        if (!StringUtils.hasText(request.getConfigName())) {
            throw new BusinessException("配置名称不能为空");
        }
        if (request.getEffectiveStart() == null || request.getEffectiveEnd() == null) {
            throw new BusinessException("适用时间段不能为空");
        }
        if (request.getEffectiveStart().isAfter(request.getEffectiveEnd())) {
            throw new BusinessException("适用开始时间不能晚于结束时间");
        }
        if (request.getBiddingMode() == null
                || (request.getBiddingMode() != VppBiddingConfigHelper.BIDDING_MODE_TIME_SLOT
                && request.getBiddingMode() != VppBiddingConfigHelper.BIDDING_MODE_WHOLE)) {
            throw new BusinessException("竞价模式无效，取值 1 或 2");
        }
        if (request.getTypicalCoefficient() == null) {
            throw new BusinessException("典型系数不能为空");
        }
        if (request.getNoticeMinHours() != null
                && request.getNoticeMinHours().compareTo(new java.math.BigDecimal("0.5")) < 0) {
            throw new BusinessException("提前截标最小通知时间不能小于0.5小时！");
        }
        if (request.getNoticeMaxHours() != null
                && request.getNoticeMaxHours().compareTo(new java.math.BigDecimal("0.5")) < 0) {
            throw new BusinessException("提前截标最大通知时间不能小于0.5小时！");
        }
        if (request.getMaxPrice() == null) {
            throw new BusinessException("最高价格不能为空");
        }
        if (request.getMinPrice() == null) {
            throw new BusinessException("最低价格不能为空");
        }
        VppBiddingConfigHelper.validatePriceRange(request.getMinPrice(), request.getMaxPrice());
    }

    private Integer resolveCurrentTenantId() {
        try {
            return SecurityUtils.getTenantId();
        } catch (Exception ex) {
            return null;
        }
    }

    private void applyTenantFilter(LambdaQueryWrapper<VppBiddingConfig> wrapper) {
        Integer tenantId = resolveCurrentTenantId();
        if (tenantId != null) {
            wrapper.eq(VppBiddingConfig::getTenantId, tenantId);
        }
    }
}
