package com.yiqi.order.service.impl;

import java.util.*;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.github.pagehelper.PageInfo;
import com.qcloud.cos.common_utils.CommonFileUtils;
import com.yiqi.common.enums.SourceType;
import com.yiqi.common.exception.ServiceException;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yiqi.app.domain.AppUser;
import com.yiqi.app.service.IAppUserService;
import com.yiqi.common.core.domain.AuthHolder;
import com.yiqi.common.enums.ClothOrderFlowStatus;
import com.yiqi.common.utils.DateUtils;
import com.yiqi.common.utils.SecurityUtils;
import com.yiqi.common.utils.StringUtils;
import com.yiqi.core.domain.ClothHanger;
import com.yiqi.core.domain.ClothHangerOrderRelation;
import com.yiqi.core.domain.SettlementManageBill;
import com.yiqi.core.domain.dto.SettlementBillAddDTO;
import com.yiqi.core.service.IClothHangerOrderRelationService;
import com.yiqi.core.service.IClothHangerService;
import com.yiqi.order.domain.*;
import com.yiqi.order.domain.dto.*;
import com.yiqi.order.domain.vo.*;
import com.yiqi.order.service.*;
import com.yiqi.system.domain.SysOrg;
import com.yiqi.system.service.ISysOrgService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.yiqi.order.mapper.OrderClothItemMapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.transaction.annotation.Transactional;

/**
 * 洗衣订单衣服明细Service业务层处理
 *
 * @author ruoyi
 * @date 2023-10-06
 */
@Service
public class OrderClothItemServiceImpl extends ServiceImpl<OrderClothItemMapper, OrderClothItem> implements IOrderClothItemService {
    @Autowired
    private IOrderClothItemService orderClothItemService;
    @Autowired
    private IOrderClothColorService orderClothColorService;
    @Autowired
    private IOrderClothCraftService orderClothCraftService;
    @Autowired
    private IOrderClothFlawService orderClothFlawService;
    @Autowired
    private IOrderClothAdjunctService orderClothAdjunctService;
    @Autowired
    private IOrderClothTypeService orderClothTypeService;
    @Autowired
    private IClothHangerService clothHangerService;
    @Autowired
    private ISysOrgService sysOrgService;
    @Autowired
    private IAppUserService appUserService;
    @Autowired
    private IOrderClothItemFlowRecordService orderClothItemFlowRecordService;
    @Autowired
    private IClothHangerOrderRelationService clothHangerOrderRelationService;

    @Override
    public OrderClothItemCountStatisticVO getUnFinishedOrderClothCountGroupByStatus(Long factoryId, Long storeId) {
        return baseMapper.getUnFinishedOrderClothCountGroupByStatus(factoryId, storeId);
    }

    @Override
    public OrderClothItemTimeoutCountStatisticVO getTimeoutOrderClothCountGroupByStatus(Long factoryId, Long storeId) {
        return baseMapper.getTimeoutOrderClothCountGroupByStatus(factoryId, storeId, DateUtils.addDays(DateUtils.getNowDate(), -3)
                , DateUtils.addDays(DateUtils.getNowDate(), -5));
    }

    @Override
    public List<OrderClothItemVO> buildWeAppOrderClothItemDetail(List<OrderClothItem> orderClothItems) {
        if (orderClothItems.size() == 0) {
            return new ArrayList<>();
        }
        Set<Long> orderClothItemIds = orderClothItems.stream().map(OrderClothItem::getId).collect(Collectors.toSet());
        Map<Long, List<OrderClothAdjunct>> orderClothAdjunctMap = orderClothAdjunctService.list(
                        new QueryWrapper<OrderClothAdjunct>().lambda().in(OrderClothAdjunct::getOrderClothId, orderClothItemIds))
                .stream().collect(Collectors.groupingBy(OrderClothAdjunct::getOrderClothId));
        Map<Long, List<OrderClothColor>> orderClothColorMap = orderClothColorService.list(
                        new QueryWrapper<OrderClothColor>().lambda().in(OrderClothColor::getOrderClothId, orderClothItemIds))
                .stream().collect(Collectors.groupingBy(OrderClothColor::getOrderClothId));
        Map<Long, List<OrderClothCraft>> orderClothCraftMap = orderClothCraftService.list(
                        new QueryWrapper<OrderClothCraft>().lambda().in(OrderClothCraft::getOrderClothId, orderClothItemIds))
                .stream().collect(Collectors.groupingBy(OrderClothCraft::getOrderClothId));
        Map<Long, List<OrderClothFlaw>> orderClothFlawMap = orderClothFlawService.list(
                        new QueryWrapper<OrderClothFlaw>().lambda().in(OrderClothFlaw::getOrderClothId, orderClothItemIds))
                .stream().collect(Collectors.groupingBy(OrderClothFlaw::getOrderClothId));
        Map<Long, List<OrderClothType>> orderClothTypeMap = orderClothTypeService.list(
                        new QueryWrapper<OrderClothType>().lambda().in(OrderClothType::getOrderClothId, orderClothItemIds))
                .stream().collect(Collectors.groupingBy(OrderClothType::getOrderClothId));

        List<OrderClothItemVO> orderClothItemVOS = new ArrayList<>();
        for (OrderClothItem record : orderClothItems) {
            OrderClothItemVO orderClothItemVO = new OrderClothItemVO();
            BeanUtils.copyProperties(record, orderClothItemVO);
            orderClothItemVO.setOrderClothAdjuncts(orderClothAdjunctMap.get(record.getId()));
            orderClothItemVO.setOrderClothColors(orderClothColorMap.get(record.getId()));
            orderClothItemVO.setOrderClothCrafts(orderClothCraftMap.get(record.getId()));
            orderClothItemVO.setOrderClothFlaws(orderClothFlawMap.get(record.getId()));
            orderClothItemVO.setOrderClothTypes(orderClothTypeMap.get(record.getId()));
            orderClothItemVOS.add(orderClothItemVO);
        }
        return orderClothItemVOS;
    }

    @Override
    public List<OrderClothItemVO> buildOrderClothItemDetail(List<OrderClothItem> orderClothItems) {
        List<OrderClothItemVO> orderClothItemVOS = buildWeAppOrderClothItemDetail(orderClothItems);

        if (orderClothItems.size() == 0) {
            return new ArrayList<>();
        }
        Map<Long, AppUser> appUserMap = appUserService.list(new QueryWrapper<AppUser>().lambda().in(AppUser::getId, orderClothItems.stream()
                .map(OrderClothItem::getAppUserId).collect(Collectors.toSet()))).stream().collect(Collectors.toMap(AppUser::getId, AppUser -> AppUser));
        Map<Long, ClothHanger> clothHangerMap = new HashMap<>();
        if (orderClothItems.stream()
                .filter(orderClothItem -> orderClothItem.getClothHangerId() != null)
                .map(OrderClothItem::getClothHangerId)
                .collect(Collectors.toSet()).size() > 0) {
            clothHangerMap = clothHangerService.list(new QueryWrapper<ClothHanger>().lambda()
                            .in(ClothHanger::getId, orderClothItems.stream()
                                    .filter(orderClothItem -> orderClothItem.getClothHangerId() != null)
                                    .map(OrderClothItem::getClothHangerId)
                                    .collect(Collectors.toSet()))).stream()
                    .collect(Collectors.toMap(ClothHanger::getId, ClothHanger -> ClothHanger));
        }
        for (OrderClothItemVO orderClothItemVO : orderClothItemVOS) {
            orderClothItemVO.setAppUserName(appUserMap.get(orderClothItemVO.getAppUserId()).getRealName());
            orderClothItemVO.setAppUserPhoneNumber(appUserMap.get(orderClothItemVO.getAppUserId()).getPhoneNumber());
            if (clothHangerMap.containsKey(orderClothItemVO.getClothHangerId())) {
                orderClothItemVO.setClothHanger(clothHangerMap.get(orderClothItemVO.getClothHangerId()));
            }
        }
        return orderClothItemVOS;
    }

    @Override
    public List<OrderClothItem> outFactory(OrderClothItemOutFactoryDTO orderClothItemOutFactoryDTO) throws Exception {
        /**
         * 先进行验证，如果这批ID里，有状态不符合的，查出来
         */
        List<OrderClothItem> orderClothItems = list(new QueryWrapper<OrderClothItem>().lambda()
                .in(OrderClothItem::getId, orderClothItemOutFactoryDTO.getIds()));
        List<OrderClothItem> errorOrderClothItems = orderClothItems.stream().filter(orderClothItem -> !orderClothItem.getFlowStatus().equals(ClothOrderFlowStatus.checkCloth.getCode())).collect(Collectors.toList());
        if (errorOrderClothItems.size() > 0) {
            String errorMsg = "";
            for (OrderClothItem orderClothItem : errorOrderClothItems) {
                errorMsg += (StringUtils.isEmpty(errorMsg)
                        ? ("衣服编号" + orderClothItem.getWashCode()) : ("，" + orderClothItem.getWashCode()));
            }
            errorMsg += "洗衣状态不正确，请重新选择";
            throw new ServiceException(errorMsg);
        }
        update(new UpdateWrapper<OrderClothItem>().lambda().set(OrderClothItem::getFlowStatus
                        , ClothOrderFlowStatus.outFactory.getCode())
                .set(OrderClothItem::getOutFactoryTime, DateUtils.getNowDate())
                .set(OrderClothItem::getOutFactoryById, AuthHolder.userId())
                .set(OrderClothItem::getOutFactoryBy, AuthHolder.nickName())
                .in(OrderClothItem::getId, orderClothItemOutFactoryDTO.getIds())
                .eq(OrderClothItem::getFlowStatus, ClothOrderFlowStatus.checkCloth.getCode()));
        orderClothItemFlowRecordService.addRecordBatch(orderClothItemService.list(new QueryWrapper<OrderClothItem>().lambda()
                .in(OrderClothItem::getId, orderClothItemOutFactoryDTO.getIds())), ClothOrderFlowStatus.outFactory.getCode());
        return orderClothItems;
    }

    /**
     * 查询洗衣订单衣服明细
     *
     * @param id 洗衣订单衣服明细主键
     * @return 洗衣订单衣服明细
     */
    @Override
    public OrderClothItem selectOrderClothItemById(Long id) {
        return baseMapper.selectById(id);
    }

    /**
     * 查询洗衣订单衣服明细列表
     *
     * @param orderClothItem 洗衣订单衣服明细
     * @return 洗衣订单衣服明细
     */
    @Override
    public List<OrderClothItem> selectOrderClothItemList(OrderClothItem orderClothItem) {
        return baseMapper.selectOrderClothItemList(orderClothItem);
    }

    /**
     * 新增洗衣订单衣服明细
     *
     * @param orderClothItem 洗衣订单衣服明细
     * @return 结果
     */
    @Override
    public int insertOrderClothItem(OrderClothItem orderClothItem) {
        orderClothItem.setCreateTime(DateUtils.getNowDate());
        return baseMapper.insertOrderClothItem(orderClothItem);
    }

    /**
     * 修改洗衣订单衣服明细
     *
     * @param orderClothItem 洗衣订单衣服明细
     * @return 结果
     */
    @Override
    public int updateOrderClothItem(OrderClothItem orderClothItem) {
        orderClothItem.setUpdateTime(DateUtils.getNowDate());
        return baseMapper.updateOrderClothItem(orderClothItem);
    }

    /**
     * 批量删除洗衣订单衣服明细
     *
     * @param ids 需要删除的洗衣订单衣服明细主键
     * @return 结果
     */
    @Override
    public int deleteOrderClothItemByIds(Long[] ids) {
        return baseMapper.deleteOrderClothItemByIds(ids);
    }

    /**
     * 删除洗衣订单衣服明细信息
     *
     * @param id 洗衣订单衣服明细主键
     * @return 结果
     */
    @Override
    public int deleteOrderClothItemById(Long id) {
        return baseMapper.deleteOrderClothItemById(id);
    }

    /**
     * 查询洗衣订单-待上挂衣服列表
     */
    @Override
    public Page<OrderClothItemVO> getOrderClothItemListByUpHanger(OrderClothHangerDTO orderClothHangerDTO) {
        LambdaQueryWrapper<OrderClothItem> queryWrapper = new QueryWrapper<OrderClothItem>().lambda()
                .eq(OrderClothItem::getOrgId, SecurityUtils.getLoginUser().getOrgId())
                .eq(OrderClothItem::getSourceType, SecurityUtils.getLoginUser().getSourceType());
        if (orderClothHangerDTO.getFlowStatus() != null) {
            queryWrapper.eq(OrderClothItem::getFlowStatus, orderClothHangerDTO.getFlowStatus());
        } else {
            queryWrapper.in(OrderClothItem::getFlowStatus, ClothOrderFlowStatus.hangering.getCode(), ClothOrderFlowStatus.outFactory.getCode());
        }
        if (orderClothHangerDTO.getWashCode() != null) {
            queryWrapper.eq(OrderClothItem::getWashCode, orderClothHangerDTO.getWashCode());
        }
        if (orderClothHangerDTO.getOrderNo() != null) {
            queryWrapper.eq(OrderClothItem::getOrderNo, orderClothHangerDTO.getOrderNo());
        }

        Page<OrderClothItem> page = orderClothItemService.page(
                new Page<>(orderClothHangerDTO.getPageNum()
                        , orderClothHangerDTO.getPageSize())
                , queryWrapper);
        if (page.getRecords().size() == 0) {
            Page<OrderClothItemVO> orderClothItemVOPage = new Page<>();
            orderClothItemVOPage.setRecords(new ArrayList<>());
            orderClothItemVOPage.setTotal(page.getTotal());
            return orderClothItemVOPage;
        }

        Set<Long> orderClothItemIds = page.getRecords().stream().map(OrderClothItem::getId).collect(Collectors.toSet());
        Map<Long, List<OrderClothAdjunct>> orderClothAdjunctMap = orderClothAdjunctService.list(
                        new QueryWrapper<OrderClothAdjunct>().lambda().in(OrderClothAdjunct::getOrderClothId, orderClothItemIds))
                .stream().collect(Collectors.groupingBy(OrderClothAdjunct::getOrderClothId));
        Map<Long, List<OrderClothColor>> orderClothColorMap = orderClothColorService.list(
                        new QueryWrapper<OrderClothColor>().lambda().in(OrderClothColor::getOrderClothId, orderClothItemIds))
                .stream().collect(Collectors.groupingBy(OrderClothColor::getOrderClothId));
        Map<Long, List<OrderClothCraft>> orderClothCraftMap = orderClothCraftService.list(
                        new QueryWrapper<OrderClothCraft>().lambda().in(OrderClothCraft::getOrderClothId, orderClothItemIds))
                .stream().collect(Collectors.groupingBy(OrderClothCraft::getOrderClothId));
        Map<Long, List<OrderClothFlaw>> orderClothFlawMap = orderClothFlawService.list(
                        new QueryWrapper<OrderClothFlaw>().lambda().in(OrderClothFlaw::getOrderClothId, orderClothItemIds))
                .stream().collect(Collectors.groupingBy(OrderClothFlaw::getOrderClothId));
        Map<Long, List<OrderClothType>> orderClothTypeMap = orderClothTypeService.list(
                        new QueryWrapper<OrderClothType>().lambda().in(OrderClothType::getOrderClothId, orderClothItemIds))
                .stream().collect(Collectors.groupingBy(OrderClothType::getOrderClothId));

        List<OrderClothItemVO> orderClothItemVOS = new ArrayList<>();
        for (OrderClothItem record : page.getRecords()) {
            OrderClothItemVO orderClothItemVO = new OrderClothItemVO();
            BeanUtils.copyProperties(record, orderClothItemVO);
            orderClothItemVO.setIsAdjunct("N");
            orderClothItemVO.setOrderClothAdjuncts(orderClothAdjunctMap.get(record.getId()));
            orderClothItemVO.setOrderClothColors(orderClothColorMap.get(record.getId()));
            orderClothItemVO.setOrderClothCrafts(orderClothCraftMap.get(record.getId()));
            orderClothItemVO.setOrderClothFlaws(orderClothFlawMap.get(record.getId()));
            orderClothItemVO.setOrderClothTypes(orderClothTypeMap.get(record.getId()));
            orderClothItemVOS.add(orderClothItemVO);
        }

        Page<OrderClothItemVO> orderClothItemVOPage = new Page<>();
        orderClothItemVOPage.setRecords(orderClothItemVOS);
        orderClothItemVOPage.setTotal(page.getTotal());
        return orderClothItemVOPage;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void reFlowCloth(Long orderClothItemId) {
        baseMapper.reFlowCloth(orderClothItemId);
        clothHangerOrderRelationService.remove(new QueryWrapper<ClothHangerOrderRelation>().lambda()
                .eq(ClothHangerOrderRelation::getOrderClothItemId, orderClothItemId));
    }

    @Override
    public List<FactoryFinancialClothDayVO> listFinancialStatisticsByFactoryWithToday(FactoryOrderFinancialDayQueryDTO factoryOrderFinancialDayQueryDTO) {
        return baseMapper.listFinancialStatisticsByFactoryWithToday(factoryOrderFinancialDayQueryDTO, SecurityUtils.getLoginUser().getOrgId());
    }

    @Override
    public List<FactoryStatisticsListQueryVO> listFinancialStatisticsByFactoryOperate(FactoryStatisticsQueryDTO factoryStatisticsQueryDTO) {
        return baseMapper.listFinancialStatisticsByFactoryOperate(factoryStatisticsQueryDTO, SecurityUtils.getLoginUser().getOrgId());
    }

    @Override
    public List<FactoryStatisticsDetailQueryVO> listFinancialStatisticsByFactoryOperateDetail(FactoryStatisticsDetailQueryDTO factoryStatisticsDetailQueryDTO) {
        return baseMapper.listFinancialStatisticsByFactoryOperateDetail(factoryStatisticsDetailQueryDTO, SecurityUtils.getLoginUser().getOrgId());
    }

    @Override
    public int countFinancialStatisticsByFactoryOperateDetail(FactoryStatisticsDetailQueryDTO factoryStatisticsDetailQueryDTO) {
        return baseMapper.countFinancialStatisticsByFactoryOperateDetail(factoryStatisticsDetailQueryDTO, SecurityUtils.getLoginUser().getOrgId());
    }

    @Override
    public List<OrderClothItemVO> queryClothItem(OrderClothItemQueryDTO orderClothItemQueryDTO) {
        return baseMapper.queryClothItem(orderClothItemQueryDTO);
    }

    @Override
    public List<OrderClothItemVO> queryClothItemByOrderId(String orderSn) {
        OrderClothItemQueryDTO orderClothItemQueryDTO = new OrderClothItemQueryDTO();
        orderClothItemQueryDTO.setOrderNo(orderSn);
        List<OrderClothItemVO> orderClothItemVOList = orderClothItemService.queryClothItem(orderClothItemQueryDTO);
        Set<Long> orderClothItemIds = orderClothItemVOList.stream().map(OrderClothItemVO::getId).collect(Collectors.toSet());
        Map<Long, List<OrderClothAdjunct>> orderClothAdjunctMap = orderClothAdjunctService.list(
                        new QueryWrapper<OrderClothAdjunct>().lambda().in(OrderClothAdjunct::getOrderClothId, orderClothItemIds))
                .stream().collect(Collectors.groupingBy(OrderClothAdjunct::getOrderClothId));
        Map<Long, List<OrderClothColor>> orderClothColorMap = orderClothColorService.list(
                        new QueryWrapper<OrderClothColor>().lambda().in(OrderClothColor::getOrderClothId, orderClothItemIds))
                .stream().collect(Collectors.groupingBy(OrderClothColor::getOrderClothId));
        Map<Long, List<OrderClothCraft>> orderClothCraftMap = orderClothCraftService.list(
                        new QueryWrapper<OrderClothCraft>().lambda().in(OrderClothCraft::getOrderClothId, orderClothItemIds))
                .stream().collect(Collectors.groupingBy(OrderClothCraft::getOrderClothId));
        Map<Long, List<OrderClothFlaw>> orderClothFlawMap = orderClothFlawService.list(
                        new QueryWrapper<OrderClothFlaw>().lambda().in(OrderClothFlaw::getOrderClothId, orderClothItemIds))
                .stream().collect(Collectors.groupingBy(OrderClothFlaw::getOrderClothId));
        Map<Long, List<OrderClothType>> orderClothTypeMap = orderClothTypeService.list(
                        new QueryWrapper<OrderClothType>().lambda().in(OrderClothType::getOrderClothId, orderClothItemIds))
                .stream().collect(Collectors.groupingBy(OrderClothType::getOrderClothId));

        List<OrderClothItemVO> orderClothItemVOS = new ArrayList<>();
        for (OrderClothItemVO orderClothItemVO : orderClothItemVOList) {
            orderClothItemVO.setOrderClothAdjuncts(orderClothAdjunctMap.get(orderClothItemVO.getId()));
            orderClothItemVO.setOrderClothColors(orderClothColorMap.get(orderClothItemVO.getId()));
            orderClothItemVO.setOrderClothCrafts(orderClothCraftMap.get(orderClothItemVO.getId()));
            orderClothItemVO.setOrderClothFlaws(orderClothFlawMap.get(orderClothItemVO.getId()));
            orderClothItemVO.setOrderClothTypes(orderClothTypeMap.get(orderClothItemVO.getId()));
            if (orderClothItemVO.getPlanSendClothTime() != null) {
                if (orderClothItemVO.getPlanSendClothTime().getTime() < DateUtils.getNowDate().getTime()) {
                    orderClothItemVO.setTimeoutDayNum((DateUtils.getNowDate().getTime()
                            - orderClothItemVO.getPlanSendClothTime().getTime()) / (24 * 3600 * 1000) + 1);
                }
            }
            orderClothItemVOS.add(orderClothItemVO);
        }
        return orderClothItemVOS;
    }

    @Override
    public void updateAllClothItemStatusByOrderId(Long clothOrderId, String flawStatus) {
        baseMapper.updateAllClothItemStatusByOrderId(clothOrderId, flawStatus);
    }

    @Override
    public Boolean checkClothItemStatus(Long clothOrderId, String flawStatus) {
        Boolean result = true;
        List<OrderClothItem> orderClothItems = baseMapper.checkClothItemStatus(clothOrderId, flawStatus);
        for (OrderClothItem orderClothItem : orderClothItems) {
            if (Integer.valueOf(orderClothItem.getFlowStatus()) < Integer.valueOf(flawStatus) || Integer.valueOf(orderClothItem.getFlowStatus()) > 5) {
                result = false;
            }
        }
        return result;
    }

    @Override
    public List<OrderClothItemVO> findAllFactoryClothPage(OrderClothItemFactoryQueryDTO orderClothItemFactoryQueryDTO) {
        return baseMapper.findAllFactoryClothPage(orderClothItemFactoryQueryDTO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void reFlowClothByStore(Long orderClothItemId) {
        baseMapper.reFlowCloth(orderClothItemId);
        clothHangerOrderRelationService.remove(new QueryWrapper<ClothHangerOrderRelation>().lambda()
                .eq(ClothHangerOrderRelation::getOrderClothItemId, orderClothItemId));
        //添加记录
        orderClothItemFlowRecordService.addRecordBatch(orderClothItemService.list(new QueryWrapper<OrderClothItem>().lambda()
                .in(OrderClothItem::getId, orderClothItemId)), ClothOrderFlowStatus.rewashStore.getCode());
    }


}
