package cn.ey.biz.module.system.service.category.dynamic.service;

import cn.ey.biz.common.enums.CommonStatusEnum;
import cn.ey.biz.module.system.api.category.dto.CategoryDynamicReq;
import cn.ey.biz.module.system.dal.dataobject.category.DictDayDO;
import cn.ey.biz.module.system.dal.dataobject.category.DictWeekDO;
import cn.ey.biz.module.system.dal.mapper.category.DictDayMapper;
import cn.ey.biz.module.system.dal.mapper.category.DictWeekMapper;
import cn.ey.biz.module.system.enums.ErrorCodeConstants;
import cn.ey.biz.module.system.enums.category.CategoryCodeEnum;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import org.apache.commons.compress.utils.Lists;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.Month;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;
import java.util.Map;

import static cn.ey.biz.common.exception.util.ServiceExceptionUtil.exception;


@Service(DictDayServiceImpl.CATEGORY_CODE + IBaseService.BASE_SERVICE_NAME)
public class DictDayServiceImpl implements IBaseService {

    public static final String CATEGORY_CODE = "FiscalDay";

    @Resource
    private DictWeekMapper dictWeekMapper;
    @Resource
    private DictDayMapper dictDayMapper;

    @Override
    public List<Map<String, Object>> get(HttpServletRequest request, HttpServletResponse response, CategoryDynamicReq req) {
        return dictWeekMapper.selectMaps(null);
    }

    /**
     * 初始化财天数据
     *
     * @param req 请求参数
     */
    public List<Map<String, Object>> getInitData(HttpServletRequest request, HttpServletResponse response, CategoryDynamicReq req) {
        Map<String, Object> params = this.checkParams(CategoryCodeEnum.FunctionTypeConstants.DICT_DAY_INIT_DATA, req);
        String fiscalYear = (String) params.get(CustomParam.FISCAL_YEAR.getValue());
        validFiscalDayData(fiscalYear);
        List<DictWeekDO> dictWeekEntities = dictWeekMapper.selectList(new LambdaUpdateWrapper<DictWeekDO>()
                .eq(DictWeekDO::getFiscalYear, fiscalYear)
                .orderByAsc(DictWeekDO::getFiscalWeek));
        if (CollectionUtil.isNotEmpty(dictWeekEntities)) {
            List<DictDayDO> dayEntities = Lists.newArrayList();
            for (DictWeekDO dictWeekDO : dictWeekEntities) {
                List<DictDayDO> dayEntitiesTemp = this.calculateFiscalDayData(dictWeekDO);
                dayEntities.addAll(dayEntitiesTemp);
            }
            dictDayMapper.insertBatch(dayEntities);
        }
        return null;
    }

    private void validFiscalDayData(String fiscalYear) {
        Long num = dictDayMapper.selectCount(new LambdaUpdateWrapper<DictDayDO>().eq(DictDayDO::getFiscalYear, fiscalYear));
        if (num > 0) {
            throw exception(ErrorCodeConstants.CATEGORY_DATA_REQUEST_BODY_ERROR, "财天数据已初始化");
        }
    }

    private List<DictDayDO> calculateFiscalDayData(DictWeekDO dictWeekDO) {
        List<DictDayDO> dayEntities = Lists.newArrayList();
        LocalDateTime startTime = dictWeekDO.getStartTime();
        LocalDateTime endTime = dictWeekDO.getEndTime();
        LocalDate tempDate = LocalDate.from(startTime);
        while (tempDate.isBefore(LocalDate.from(endTime)) || tempDate.isEqual(LocalDate.from(endTime))) {
            LocalDate dayDate = LocalDate.of(tempDate.getYear(), tempDate.getMonthValue(), tempDate.getDayOfMonth());
            DictDayDO dictDayDO = new DictDayDO();
            dictDayDO.setDayId(DateUtil.format(dayDate.atStartOfDay(), DatePattern.PURE_DATE_PATTERN));
            dictDayDO.setFiscalYear(dictWeekDO.getFiscalYear());
            dictDayDO.setFiscalWeek(dictWeekDO.getFiscalWeek());
            dictDayDO.setFiscalMonth(dictWeekDO.getFiscalMonth());
            dictDayDO.setYear(dictWeekDO.getYear());
            dictDayDO.setMonth(dayDate.getMonthValue());
            dictDayDO.setMonthValue(Month.of(dayDate.getMonthValue()).name());
            dictDayDO.setDayNum(dayDate.getDayOfMonth());
            dictDayDO.setDayDate(dayDate);
            dictDayDO.setWeekDay(dayDate.getDayOfWeek().name());
            DayOfWeek dayOfWeek = dayDate.getDayOfWeek();
            dictDayDO.setWeekend(dayOfWeek == DayOfWeek.SATURDAY || dayOfWeek == DayOfWeek.SUNDAY ? 1 : 0);
            dictDayDO.setStatus(CommonStatusEnum.ENABLE.getStatus());
            dictDayDO.setCreator("1");
            dictDayDO.setUpdater("1");
            dayEntities.add(dictDayDO);
            tempDate = tempDate.plusDays(1);
        }
        return dayEntities;
    }


    enum CustomParam {
        /**
         * 财年
         */
        FISCAL_YEAR("fiscalYear");

        final String value;

        CustomParam(String value) {
            this.value = value;
        }

        public String getValue() {
            return value;
        }
    }

    @Override
    public Map<String, Object> checkParams(String functionType, CategoryDynamicReq req) {
        boolean nullError = false;
        boolean otherError = false;
        StringBuilder errorMsg = new StringBuilder();
        Map<String, Object> result = req.getRequestBody();
        // InitData
        if (CategoryCodeEnum.FunctionTypeConstants.DICT_DAY_INIT_DATA.equals(functionType)) {
            nullError = (result == null || result.get(CustomParam.FISCAL_YEAR.getValue()) == null);
            if (!nullError) {
                try {
                    String fiscalYear = (String) req.getRequestBody().get(CustomParam.FISCAL_YEAR.getValue());
                    result.put(CustomParam.FISCAL_YEAR.getValue(), fiscalYear);
                } catch (Exception e) {
                    otherError = true;
                }
            }
            if (nullError || otherError) {
                errorMsg.append(CustomParam.FISCAL_YEAR.getValue());
            }
        }
        if (nullError || otherError) {
            throw exception(ErrorCodeConstants.CATEGORY_DATA_REQUEST_BODY_PARAMETER_ERROR, errorMsg.toString());
        }
        return result;
    }
}
