package com.cool.store.service.impl;

import com.cool.store.dao.*;
import com.cool.store.dto.pre.fry.*;
import com.cool.store.entity.*;
import com.cool.store.enums.ErrorCodeEnum;
import com.cool.store.enums.PreFryApplyTypeEnum;
import com.cool.store.enums.PreFryStageEnum;
import com.cool.store.enums.ViolationEnum;
import com.cool.store.exception.ServiceException;
import com.cool.store.service.PreFryRecordsService;
import com.cool.store.utils.CoolDateUtils;
import com.cool.store.utils.poi.DateUtils;
import com.cool.store.vo.PartnerUserInfoVO;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;

import static com.cool.store.enums.PreFryStageEnum.*;

/**
 * @Author suzhuhong
 * @Date 2025/6/23 14:39
 * @Version 1.0
 */
@Service
public class PreFryRecordsServiceImpl implements PreFryRecordsService {


    @Resource
    PreFryRecordsDAO preFryRecordsDAO;

    @Resource
    PreFryStageChangesDAO preFryStageChangesDAO;
    @Resource
    PreFryQualificationApplyDAO preFryQualificationApplyDAO;
    @Resource
    PreFriedProductsDAO preFriedProductsDAO;
    @Resource
    StoreDao storeDao;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean batchInsert(AddPreFryRecordsDTO addPreFryRecordsDTO, PartnerUserInfoVO user) {
        if (CollectionUtils.isEmpty(addPreFryRecordsDTO.getRecords())|| CollectionUtils.isEmpty(addPreFryRecordsDTO.getRecords())){
            throw  new ServiceException(ErrorCodeEnum.PARAMS_REQUIRED);
        }
        //查询门店当前最高优先级申请类型
        PreFryQualificationApplyDO minApplyTypeByStoreCode = preFryQualificationApplyDAO.getMinApplyTypeByStoreCode(addPreFryRecordsDTO.getStoreCode());
        if (minApplyTypeByStoreCode==null){
            throw  new ServiceException(ErrorCodeEnum.PRE_FRY_APPLY_NOT_EXIST);
        }
        if (addPreFryRecordsDTO!=null&&CollectionUtils.isNotEmpty(addPreFryRecordsDTO.getRecords())){
            List<Long> productList = addPreFryRecordsDTO.getRecords().stream().map(AddPreFryRecordsDetailDTO::getProductId).collect(Collectors.toList());
            List<PreFriedProductsDO> preFriedProductsDOS = preFriedProductsDAO.selectByProductIds(productList);
            //校验是否包含下架的产品 recordId是空的时候是新增 是有新增的时候限制
            if (preFriedProductsDOS.stream().anyMatch(e->e.getStatus()==0)&&addPreFryRecordsDTO.getRecords().get(0).getRecordId()==null){
                throw new ServiceException(ErrorCodeEnum.PRODUCTS_STATUS);
            }
        }


        //如果出现优先级升高的情况 优先级低的只有报废可选择 1的优先级最高 3最低
        if (minApplyTypeByStoreCode.getApplyType()<addPreFryRecordsDTO.getApplyType()
                &&addPreFryRecordsDTO.getCurrentStage()!= DISCARDED.getCode()){
            //当前有更优选择，请确认
            throw new ServiceException(ErrorCodeEnum.CURRENT_STAGE_NOT_OPERATION);
        }
        //只有当最高类型是1/3且是预炸完成 或者 2 且放入展示柜 新增一条预炸记录  其他情况只新增阶段记录表
        List<PreFryStageChangesDO> list = new ArrayList<>();
        if (addPreFryRecordsFlag(minApplyTypeByStoreCode.getApplyType(), addPreFryRecordsDTO.getCurrentStage())){
            addPreFryRecordsDTO.getRecords().forEach(x->{
                if (x.getProductId()==null){
                    throw new ServiceException(ErrorCodeEnum.PARAMS_REQUIRED);
                }
                PreFryRecordsDO preFryRecordsDO = new PreFryRecordsDO();
                preFryRecordsDO.setStoreCode(addPreFryRecordsDTO.getStoreCode());
                preFryRecordsDO.setProductId(x.getProductId());
                preFryRecordsDO.setFryDate(new Date());
                preFryRecordsDO.setRecordCode(getRecordCode());
                preFryRecordsDO.setFryCompleteTime(new Date());
                preFryRecordsDO.setLatestSaleTime(getLatestSaleTime(minApplyTypeByStoreCode.getApplyType()));
                preFryRecordsDO.setCurrentStage(addPreFryRecordsDTO.getCurrentStage());
                preFryRecordsDO.setCurrentApplyType(minApplyTypeByStoreCode.getApplyType());
                preFryRecordsDAO.insert(preFryRecordsDO);
                PreFryStageChangesDO preFryStageChangesDO = new PreFryStageChangesDO();
                preFryStageChangesDO.setStage(preFryRecordsDO.getCurrentStage());
                preFryStageChangesDO.setRecordId(preFryRecordsDO.getId());
                preFryStageChangesDO.setImage1(x.getImage1());
                preFryStageChangesDO.setImage2(x.getImage2());
                preFryStageChangesDO.setOperatorName(user.getUsername());
                list.add(preFryStageChangesDO);
            });
        }else {
            List<Long>  recordList= new ArrayList<>();
            addPreFryRecordsDTO.getRecords().forEach(x->{
                if (x.getRecordId()==null){
                    throw new ServiceException(ErrorCodeEnum.PARAMS_REQUIRED);
                }
                PreFryStageChangesDO preFryStageChangesDO = new PreFryStageChangesDO();
                preFryStageChangesDO.setStage(addPreFryRecordsDTO.getCurrentStage());
                preFryStageChangesDO.setRecordId(x.getRecordId());
                preFryStageChangesDO.setImage1(x.getImage1());
                preFryStageChangesDO.setImage2(x.getImage2());
                preFryStageChangesDO.setOperatorName(user.getUsername());
                preFryStageChangesDO.setCreatedTime(new Date());
                recordList.add(x.getRecordId());
                list.add(preFryStageChangesDO);
            });
            preFryRecordsDAO.batchUpdateStageByIds(recordList,addPreFryRecordsDTO.getCurrentStage());
            List<PreFryRecordsDO> preFryRecordsDOS = preFryRecordsDAO.queryByIds(recordList);
            handleViolationFlag(preFryRecordsDOS,addPreFryRecordsDTO.getApplyType(),addPreFryRecordsDTO.getCurrentStage(),list);
            if (DISCARDED.getCode()==addPreFryRecordsDTO.getCurrentStage()){
                //只要有一条记录是销售完成的 不能报销
                if (preFryRecordsDOS.stream().anyMatch(x->x.getCurrentStage()==SALES_COMPLETED.getCode())){
                    throw new ServiceException(ErrorCodeEnum.PRODUCTS_SALES_COMPLETED);
                }
            }
        }
        preFryStageChangesDAO.batchInsert(list);
        return Boolean.TRUE;
    }


    private void handleViolationFlag(List<PreFryRecordsDO>  records ,Integer applyType,Integer currentStage,List<PreFryStageChangesDO> list) {
        //如果最高级优先级是冷藏展示柜 计算是否违规  冷却时间小于15分钟或者大于25分钟 违规  冰箱取出时间距离预炸完成时间超过24小时
        if (PreFryApplyTypeEnum.HAS_REFRIGERATED_DISPLAY.getCode()==applyType&&
                (STORED_IN_DISPLAY_CABINET.getCode()==currentStage||STORED_IN_FRIDGE.getCode()==currentStage)){
            Map<Long,PreFryRecordsDO> recordMap = records.stream().collect(Collectors.toMap(PreFryRecordsDO::getId, data->data));
            //list 转为 map 记录id与创建时间
            Map<Long,Date> listMap = list.stream().collect(Collectors.toMap(PreFryStageChangesDO::getRecordId, PreFryStageChangesDO::getCreatedTime));
            List<ViolationDTO> violationList = new ArrayList<>();
            if (STORED_IN_DISPLAY_CABINET.getCode()==currentStage){
                records.forEach(x->{
                    PreFryRecordsDO preFryRecordsDO = recordMap.get(x.getId());
                    Long time = getTime(preFryRecordsDO.getFryCompleteTime(), listMap.get(x.getId()));
                    if (time!=null&&(time<15||time>25)){
                        ViolationDTO violationDTO = new ViolationDTO();
                        violationDTO.setId(x.getId());
                        violationDTO.setViolationFlag(ViolationEnum.COOLING_TIME_EXCEEDED.getCode());
                        violationDTO.setViolationReason(String.format(",%d,", ViolationEnum.COOLING_TIME_EXCEEDED.getCode()));
                        violationList.add(violationDTO);
                    }
                });
            }else if (STORED_IN_FRIDGE.getCode()==currentStage){
                records.forEach(x->{
                    PreFryRecordsDO preFryRecordsDO = recordMap.get(x.getId());
                    Long time = getTime(preFryRecordsDO.getFryCompleteTime(), listMap.get(x.getId()));
                    if (time!=null&&time>24*60){
                        ViolationDTO violationDTO = new ViolationDTO();
                        violationDTO.setId(x.getId());
                        violationDTO.setViolationFlag(ViolationEnum.STORAGE_TIME_EXCEEDED.getCode());
                        if (StringUtils.isEmpty(preFryRecordsDO.getViolationReason())){
                            violationDTO.setViolationReason(String.format(",%d,", ViolationEnum.STORAGE_TIME_EXCEEDED.getCode()));
                        }else {
                            violationDTO.setViolationReason(preFryRecordsDO.getViolationReason()+String.format("%d,", ViolationEnum.STORAGE_TIME_EXCEEDED.getCode()));
                        }
                        violationList.add(violationDTO);
                    }

                });
            }
            if (!violationList.isEmpty()) {
                preFryRecordsDAO.batchUpdateViolation(violationList);
            }
        }

    }

    private Long getTime(Date startTime,Date endTime){
        if (startTime==null||endTime==null){
            return null;
        }
        return CoolDateUtils.getMinutesBetween(startTime,endTime);
    }


    @Override
    public PageInfo<PreFryRecordsDetailDTO> ListByStoreCodeAndDate(FryRecordsQueryDTO dto) {
        PageHelper.startPage(dto.getPageNum(),dto.getPageSize());
        if (dto.getCurrentDate()==null|| StringUtils.isBlank(dto.getStoreCode())){
            throw new ServiceException(ErrorCodeEnum.PARAMS_REQUIRED);
        }
        List<PreFryRecordsDO> preFryRecordsDOS = preFryRecordsDAO.selectByStoreAndDateStage(dto.getStoreCode(),dto.getApplyType(), DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD,dto.getCurrentDate()));
        PageInfo result = new PageInfo<>(preFryRecordsDOS);
        if (CollectionUtils.isEmpty(preFryRecordsDOS)){
            return result;
        }
        List<Long> recordIdList = preFryRecordsDOS.stream().map(PreFryRecordsDO::getId).collect(Collectors.toList());
        List<PreFryStageImagesDTO> stageImagesDTOS = preFryStageChangesDAO.selectByRecordIdList(recordIdList);
        List<Long> productIdList = preFryRecordsDOS.stream().map(PreFryRecordsDO::getProductId).collect(Collectors.toList());
        List<PreFriedProductsDO> preFriedProductsDOS = preFriedProductsDAO.selectByProductIds(productIdList);
        Map<Long, PreFriedProductsDO> preFriedProductsDOSMap = preFriedProductsDOS.stream().collect(Collectors.toMap(PreFriedProductsDO::getId, x -> x));
        //将数据根据recordId分组 并根据id排序
        Map<Long, List<PreFryStageImagesDTO>> stageImagesDTOMap =
                stageImagesDTOS.stream().collect(Collectors.groupingBy(PreFryStageImagesDTO::getRecordId));
        List<PreFryRecordsDetailDTO> list = new ArrayList<>();
        preFryRecordsDOS.forEach(x->{
            PreFryRecordsDetailDTO preFryRecordsDetailDTO = new PreFryRecordsDetailDTO();
            preFryRecordsDetailDTO.setId(x.getId());
            preFryRecordsDetailDTO.setStoreCode(x.getStoreCode());
            preFryRecordsDetailDTO.setProductId(x.getProductId());
            preFryRecordsDetailDTO.setProductCode(preFriedProductsDOSMap.getOrDefault(x.getProductId(),new PreFriedProductsDO()).getProductCode());
            preFryRecordsDetailDTO.setProductName(preFriedProductsDOSMap.getOrDefault(x.getProductId(),new PreFriedProductsDO()).getProductName());
            preFryRecordsDetailDTO.setProductImageUrl(preFriedProductsDOSMap.getOrDefault(x.getProductId(),new PreFriedProductsDO()).getProductImage());
            preFryRecordsDetailDTO.setFryCompleteTime(x.getFryCompleteTime());
            preFryRecordsDetailDTO.setLatestSaleTime(x.getLatestSaleTime());
            preFryRecordsDetailDTO.setCurrentStage(x.getCurrentStage());
            preFryRecordsDetailDTO.setCurrentApplyType(x.getCurrentApplyType());
            preFryRecordsDetailDTO.setStageHistory(stageImagesDTOMap.getOrDefault(x.getId(),new ArrayList<>()));
            list.add(preFryRecordsDetailDTO);
        });
        result.setList( list);
        return result;
    }



    @Override
    public PreFryRecordsDetailDTO getById(Long id) {
        PreFryRecordsDO preFryRecordsDO = preFryRecordsDAO.queryById(id);
        if (preFryRecordsDO == null) {
            throw new ServiceException(ErrorCodeEnum.PARAMS_REQUIRED);
        }
        List<PreFryStageImagesDTO> preFryStageImagesDTOS = preFryStageChangesDAO.selectByRecordId(id);
        PreFriedProductsDO preFriedProductsDO = preFriedProductsDAO.queryById(preFryRecordsDO.getProductId());
        StoreDO store = storeDao.getByStoreNum(preFryRecordsDO.getStoreCode());
        PreFryRecordsDetailDTO preFryRecordsDetailDTO = new PreFryRecordsDetailDTO();
        if (store != null) {
            preFryRecordsDetailDTO.setStoreName(store.getStoreName());
        }
        preFryRecordsDetailDTO.setId(preFryRecordsDO.getId());
        preFryRecordsDetailDTO.setStoreCode(preFryRecordsDO.getStoreCode());
        preFryRecordsDetailDTO.setProductId(preFryRecordsDO.getProductId());
        preFryRecordsDetailDTO.setRecordCode(preFryRecordsDO.getRecordCode());
        if (preFriedProductsDO!=null){
            preFryRecordsDetailDTO.setProductName(preFriedProductsDO.getProductName());
            preFryRecordsDetailDTO.setProductImageUrl(preFriedProductsDO.getProductImage());
            preFryRecordsDetailDTO.setProductCode(preFriedProductsDO.getProductCode());
        }
        preFryRecordsDetailDTO.setFryCompleteTime(preFryRecordsDO.getFryCompleteTime());
        preFryRecordsDetailDTO.setLatestSaleTime(preFryRecordsDO.getLatestSaleTime());
        preFryRecordsDetailDTO.setCurrentStage(preFryRecordsDO.getCurrentStage());
        preFryRecordsDetailDTO.setCurrentApplyType(preFryRecordsDO.getCurrentApplyType());
        preFryRecordsDetailDTO.setViolationFlag(preFryRecordsDO.getViolationFlag());
        preFryRecordsDetailDTO.setViolationReason(getViolationReasonChinese(preFryRecordsDO.getViolationReason()));
        preFryRecordsDetailDTO.setStageHistory(preFryStageImagesDTOS);
        return preFryRecordsDetailDTO;
    }

    @Override
    public Boolean salesCompleted(Long id, PartnerUserInfoVO user) {
        PreFryRecordsDO preFryRecordsDO = preFryRecordsDAO.queryById(id);
        if (preFryRecordsDO == null) {
            throw new ServiceException(ErrorCodeEnum.PRODUCTS_RECORD_NOT_EXIST);
        }
        if (preFryRecordsDO.getCurrentStage() == PreFryStageEnum.DISCARDED.getCode()){
            throw new ServiceException(ErrorCodeEnum.PRODUCTS_DISCARDED);
        }
        preFryRecordsDO.setCurrentStage(SALES_COMPLETED.getCode());
        preFryRecordsDO.setUpdatedTime(new Date());
        preFryRecordsDAO.updateByPrimaryKeySelective(preFryRecordsDO);
        //新增销售记录
        PreFryStageChangesDO preFryStageChangesDO = new PreFryStageChangesDO();
        preFryStageChangesDO.setStage(SALES_COMPLETED.getCode());
        preFryStageChangesDO.setRecordId(id);
        preFryStageChangesDO.setOperatorName(user.getUsername());
        preFryStageChangesDO.setCreatedTime(new Date());
        preFryStageChangesDAO.batchInsert(Arrays.asList(preFryStageChangesDO));
        return Boolean.TRUE;
    }


    @Override
    public List<DailyFryCountDTO> queryByStoreCode(String storeCode,Long time) {
        return preFryRecordsDAO.selectDailyFryCountInCurrentMonth(storeCode, time);
    }

    @Override
    public PageInfo<PreFryRecordsDTO> queryByQueryDTO(PreFryRecordQueryDTO dto) {
        PageHelper.startPage(dto.getPageNum(), dto.getPageSize());
        List<PreFryRecordsDTO> preFryRecordQueryDTOS = preFryRecordsDAO.selectByQueryDTO(dto);
        preFryRecordQueryDTOS.forEach(x->{
            x.setViolationReason(getViolationReasonChinese(x.getViolationReason()));
        });
        PageInfo<PreFryRecordsDTO> preFryRecordQueryDTOPageInfo = new PageInfo<>(preFryRecordQueryDTOS);
        return preFryRecordQueryDTOPageInfo;
    }


    private Boolean addPreFryRecordsFlag(Integer applyType,Integer stage){
        if (applyType== PreFryApplyTypeEnum.HAS_REFRIGERATED_DISPLAY.getCode() && stage== PRE_FRY_COMPLETED.getCode()){
            return Boolean.TRUE;
        }else if (applyType == PreFryApplyTypeEnum.NO_DISPLAY.getCode() && stage== PRE_FRY_COMPLETED.getCode()){
            return Boolean.TRUE;
        }
        if (applyType==PreFryApplyTypeEnum.HAS_NORMAL_DISPLAY.getCode() && stage== STORED_IN_DISPLAY_CABINET.getCode()){
            return Boolean.TRUE;
        }
        return Boolean.FALSE;
    }

    private Date getLatestSaleTime(Integer applyType) {
        Calendar calendar = Calendar.getInstance();
        if (applyType == PreFryApplyTypeEnum.HAS_REFRIGERATED_DISPLAY.getCode()) {
            // 冷藏展示柜加24小时
            calendar.add(Calendar.HOUR_OF_DAY, 24);
        } else {
            // 常温展示柜或无展示柜加4小时
            calendar.add(Calendar.HOUR_OF_DAY, 4);
        }
        return calendar.getTime();
    }

    public String getRecordCode() {
        //当前日期
        String today = CoolDateUtils.getToday();
        return "14" + today + String.format("%04d", ThreadLocalRandom.current().nextInt(100000));
    }

    /**
     * 根据违规原因字符串获取中文描述
     * @param violationReason 违规原因字符串，格式如 ",1,2,"、",1," 或 ",2,"
     * @return 格式化后的中文违规原因，如 "冷却时间超标，存储时间超标"
     */
    public String getViolationReasonChinese(String violationReason) {
        if (StringUtils.isBlank(violationReason)) {
            return "";
        }

        // 分割字符串并过滤有效数字
        List<Integer> reasonCodes = Arrays.stream(violationReason.split(","))
                .filter(StringUtils::isNotBlank)
                .map(String::trim)
                .map(Integer::valueOf)
                .collect(Collectors.toList());

        // 转换为中文描述
        return reasonCodes.stream()
                .map(code -> ViolationEnum.getByCode(code))
                .filter(Objects::nonNull)
                .map(ViolationEnum::getDescription)
                .collect(Collectors.joining("，"));
    }


}
