package com.cool.store.service.plan.impl;

import cn.hutool.core.collection.CollStreamUtil;
import com.cool.store.context.CurrentUserHolder;
import com.cool.store.dao.StoreDao;
import com.cool.store.dao.ad.AdDistrictDAO;
import com.cool.store.dao.plan.CityPlanningDAO;
import com.cool.store.entity.plan.CityPlanningDO;
import com.cool.store.enums.ErrorCodeEnum;
import com.cool.store.exception.ServiceException;
import com.cool.store.request.plan.CityPlanningUpdateRequest;
import com.cool.store.request.plan.CityPlanningQueryRequest;
import com.cool.store.service.plan.CityPlanningService;
import com.cool.store.utils.BeanUtil;
import com.cool.store.vo.plan.CityPlanningStatisticsVO;
import com.cool.store.vo.plan.CityPlanningVO;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 城市规划服务实现类
 */
@Service
@RequiredArgsConstructor
public class CityPlanningServiceImpl implements CityPlanningService {
    private final CityPlanningDAO cityPlanningDAO;
    private final AdDistrictDAO adDistrictDAO;
    private final StoreDao storeDao;

    private final static DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyMMddHHmmssSSS");

    @Override
    public Boolean add(CityPlanningUpdateRequest request) {
        // 校验同年份同季度同省市不能存在2个规划
        if (cityPlanningDAO.existsByYearAndQuarterAndRegion(
                request.getYear(), request.getQuarter(), 
                request.getProvinceCode(), request.getCityCode(), null)) {
            throw new ServiceException(ErrorCodeEnum.CITY_PLANNING_EXISTS);
        }

        CityPlanningDO cityPlanningDO = BeanUtil.toBean(request, CityPlanningDO.class);
        cityPlanningDO.setPlanNo(generatePlanNo(request));
        cityPlanningDO.setCreateUserId(CurrentUserHolder.getUserId());
        return cityPlanningDAO.insertSelective(cityPlanningDO);
    }

    @Override
    public Boolean update(CityPlanningUpdateRequest request) {
        // 先查询是否存在
        CityPlanningDO existing = cityPlanningDAO.getById(request.getId());
        if (existing == null) {
            throw new ServiceException("规划不存在");
        }

        // 校验同年份同季度同省市不能存在2个规划（排除自身）
        if (cityPlanningDAO.existsByYearAndQuarterAndRegion(
                request.getYear(), request.getQuarter(), 
                request.getProvinceCode(), request.getCityCode(), request.getId())) {
            throw new ServiceException("同年份同季度同省市已存在其他规划，不能修改");
        }

        CityPlanningDO cityPlanningDO = BeanUtil.toBean(request, CityPlanningDO.class);
        return cityPlanningDAO.updateSelective(cityPlanningDO);
    }

    @Override
    public PageInfo<CityPlanningVO> queryPage(CityPlanningQueryRequest request) {
        PageHelper.startPage(request.getPageNum(), request.getPageSize());
        List<CityPlanningDO> list = cityPlanningDAO.queryByCondition(request);
        PageInfo<CityPlanningDO> page = new PageInfo<>(list);
        PageInfo<CityPlanningVO> result = BeanUtil.toPage(page, CityPlanningVO.class);
        List<String> adCodes = list.stream()
                .flatMap(v -> Stream.of(v.getProvinceCode(), v.getCityCode()))
                .distinct()
                .collect(Collectors.toList());
        Map<String, String> adMap = adDistrictDAO.getNameByCodes(adCodes);
        result.getList().forEach(v -> {
            v.setProvince(adMap.get(v.getProvinceCode()));
            v.setCity(adMap.get(v.getCityCode()));
        });
        return result;
    }

    @Override
    public Boolean deleteByIds(List<Long> ids) {
        return cityPlanningDAO.deleteByIds(ids);
    }

    @Override
    public PageInfo<CityPlanningVO> cityPlanningSchedule(CityPlanningQueryRequest request) {
        PageHelper.startPage(request.getPageNum(), request.getPageSize());
        List<CityPlanningDO> list = cityPlanningDAO.queryByCondition(request);
        PageInfo<CityPlanningDO> page = new PageInfo<>(list);
        PageInfo<CityPlanningVO> result = BeanUtil.toPage(page, CityPlanningVO.class);
        List<String> adCodes = list.stream()
                .flatMap(v -> Stream.of(v.getProvinceCode(), v.getCityCode()))
                .distinct()
                .collect(Collectors.toList());
        Map<String, String> adMap = adDistrictDAO.getNameByCodes(adCodes);
        Set<Integer> years = CollStreamUtil.toSet(list, CityPlanningDO::getYear);
        Map<Integer, Map<Integer, Map<String, Map<String, Integer>>>> storeNumMap = storeDao.storeNumStatisticsByAd(new ArrayList<>(years), new ArrayList<>(adMap.values()));
        result.getList().forEach(v -> {
            v.setProvince(adMap.get(v.getProvinceCode()));
            v.setCity(adMap.get(v.getCityCode()));
            Integer completeNum = storeNumMap.getOrDefault(v.getYear(), Collections.emptyMap())
                    .getOrDefault(v.getQuarter(), Collections.emptyMap())
                    .getOrDefault(v.getProvince(), Collections.emptyMap())
                    .getOrDefault(v.getCity(), 0);
            v.setCompleteNum(completeNum);
            BigDecimal rate = v.getTarget() != 0 ? BigDecimal.valueOf(completeNum)
                    .multiply(BigDecimal.valueOf(100))
                    .divide(BigDecimal.valueOf(v.getTarget()), 1, RoundingMode.HALF_UP) : BigDecimal.ZERO;
            v.setCompleteRate(rate);
        });
        return result;
    }

    @Override
    public CityPlanningStatisticsVO cityPlanningStatistics(CityPlanningQueryRequest request) {
        List<CityPlanningDO> list = cityPlanningDAO.queryByCondition(request);
        List<String> adCodes = list.stream()
                .flatMap(v -> Stream.of(v.getProvinceCode(), v.getCityCode()))
                .distinct()
                .collect(Collectors.toList());
        Map<String, String> adMap = adDistrictDAO.getNameByCodes(adCodes);
        Set<Integer> years = CollStreamUtil.toSet(list, CityPlanningDO::getYear);
        Map<Integer, Map<Integer, Map<String, Map<String, Integer>>>> storeNumMap = storeDao.storeNumStatisticsByAd(new ArrayList<>(years), new ArrayList<>(adMap.values()));
        int completeNum = 0, totalTarget = 0;
        for (CityPlanningDO v : list) {
            String province = adMap.get(v.getProvinceCode());
            String city = adMap.get(v.getCityCode());
            completeNum += storeNumMap.getOrDefault(v.getYear(), Collections.emptyMap())
                    .getOrDefault(v.getQuarter(), Collections.emptyMap())
                    .getOrDefault(province, Collections.emptyMap())
                    .getOrDefault(city, 0);
            totalTarget += v.getTarget();
        }
        BigDecimal rate = totalTarget != 0 ? BigDecimal.valueOf(completeNum)
                .multiply(BigDecimal.valueOf(100))
                .divide(BigDecimal.valueOf(totalTarget), 1, RoundingMode.HALF_UP) : BigDecimal.ZERO;
        return new CityPlanningStatisticsVO(totalTarget, completeNum, rate);
    }

    /**
     * 生成规划编码
     * 格式：CP + 年份 + 季度 + 序号
     */
    private String generatePlanNo(CityPlanningUpdateRequest request) {
        return "GH" + request.getYear() + request.getQuarter() + request.getCityCode() + ((int) (Math.random() * 900) + 100);
    }
}

