package com.yc.ship.module.product.service.pricetemplate;

import cn.hutool.core.util.IdUtil;
import com.yc.ship.framework.common.pojo.PageResult;
import com.yc.ship.framework.common.util.collection.CollectionUtils;
import com.yc.ship.framework.common.util.collection.MapUtils;
import com.yc.ship.framework.common.util.object.BeanUtils;
import com.yc.ship.module.product.controller.admin.pricetemplate.vo.*;
import com.yc.ship.module.product.dal.dataobject.basicpricearea.BasicPriceAreaDO;
import com.yc.ship.module.product.dal.dataobject.pricearea.PriceAreaDO;
import com.yc.ship.module.product.dal.dataobject.pricefloor.PriceFloorDO;
import com.yc.ship.module.product.dal.dataobject.priceroommodel.PriceRoomModelDO;
import com.yc.ship.module.product.dal.dataobject.priceroommodeltype.PriceRoomModelTypeDO;
import com.yc.ship.module.product.dal.dataobject.pricesinglesetting.PriceSingleSettingDO;
import com.yc.ship.module.product.dal.dataobject.pricespu.PriceSpuDO;
import com.yc.ship.module.product.dal.dataobject.pricetemplate.PriceTemplateDO;
import com.yc.ship.module.product.dal.mysql.basicpricearea.BasicPriceAreaMapper;
import com.yc.ship.module.product.dal.mysql.pricearea.PriceAreaMapper;
import com.yc.ship.module.product.dal.mysql.pricefloor.PriceFloorMapper;
import com.yc.ship.module.product.dal.mysql.priceroommodel.PriceRoomModelMapper;
import com.yc.ship.module.product.dal.mysql.priceroommodeltype.PriceRoomModelTypeMapper;
import com.yc.ship.module.product.dal.mysql.pricesinglesetting.PriceSingleSettingMapper;
import com.yc.ship.module.product.dal.mysql.pricespu.PriceSpuMapper;
import com.yc.ship.module.product.dal.mysql.pricetemplate.PriceTemplateMapper;
import com.yc.ship.module.product.service.pricearea.PriceAreaService;
import com.yc.ship.module.product.service.pricefloor.PriceFloorService;
import com.yc.ship.module.product.service.priceroommodel.PriceRoomModelService;
import com.yc.ship.module.product.service.pricesinglesetting.PriceSingleSettingService;
import com.yc.ship.module.product.service.pricespu.PriceSpuService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import static com.yc.ship.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.yc.ship.module.product.enums.ErrorCodeConstants.PRICE_TEMPLATE_NOT_EXISTS;

/**
 * 价格模板 Service 实现类
 *
 * @author 管理员
 */
@Service
@Validated
public class PriceTemplateServiceImpl implements PriceTemplateService {

    @Resource
    private PriceTemplateMapper priceTemplateMapper;

    @Resource
    private PriceRoomModelMapper priceRoomModelMapper;

    @Resource
    private PriceFloorMapper priceFloorMapper;

    @Resource
    private PriceSingleSettingMapper priceSingleSettingMapper;

    @Resource
    private PriceAreaMapper priceAreaMapper;

    @Resource
    private PriceSpuMapper priceSpuMapper;

    @Resource
    private PriceRoomModelService priceRoomModelService;

    @Resource
    private PriceFloorService priceFloorService;

    @Resource
    private PriceSingleSettingService priceSingleSettingService;

    @Resource
    private PriceAreaService priceAreaService;

    @Resource
    private PriceSpuService priceSpuService;

    @Resource
    private BasicPriceAreaMapper basicPriceAreaMapper;

    @Resource
    private PriceRoomModelTypeMapper priceRoomModelTypeMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createPriceTemplate(PriceTemplateSaveReqVO createReqVO) {
        // 插入
        PriceTemplateDO priceTemplate = BeanUtils.toBean(createReqVO, PriceTemplateDO.class);
        priceTemplateMapper.insert(priceTemplate);
        Long id = priceTemplate.getId();
        saveRelation(id, createReqVO);
        // 返回
        return id;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updatePriceTemplate(PriceTemplateSaveReqVO updateReqVO) {
        Long id = updateReqVO.getId();
        // 校验存在
        validatePriceTemplateExists(id);
        // 更新
        PriceTemplateDO updateObj = BeanUtils.toBean(updateReqVO, PriceTemplateDO.class);
        priceTemplateMapper.updateById(updateObj);
        deleteRelation(id);
        saveRelation(id, updateReqVO);

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deletePriceTemplate(Long id) {
        // 校验存在
        validatePriceTemplateExists(id);
        // 删除
        priceTemplateMapper.deleteById(id);
        deleteRelation(id);
    }

    private void validatePriceTemplateExists(Long id) {
        if (priceTemplateMapper.selectById(id) == null) {
            throw exception(PRICE_TEMPLATE_NOT_EXISTS);
        }
    }

    @Override
    public PriceTemplateRespVO getPriceTemplate(Long id) {
        PriceTemplateDO priceTemplate = priceTemplateMapper.selectById(id);
        PriceTemplateRespVO respVO = BeanUtils.toBean(priceTemplate, PriceTemplateRespVO.class);
        List<PriceRoomModelDO> roomModelDOList = priceRoomModelService.getListByObjectId(id);
        List<PriceRoomModelRespVO> priceRoomModelRespVOS = BeanUtils.toBean(roomModelDOList, PriceRoomModelRespVO.class);
        List<PriceSingleSettingDO> singleSettingList = priceSingleSettingService.getByObjectId(id);
        List<PriceSingleSettingRespVO> priceSingleSettingRespVOS = BeanUtils.toBean(singleSettingList, PriceSingleSettingRespVO.class);
        Map<Long, PriceSingleSettingRespVO> singleSettingRespVOMap = CollectionUtils.convertMap(priceSingleSettingRespVOS, PriceSingleSettingRespVO::getRoomModelTypeId);
        List<PriceRoomModelTypeDO> roomModelTypeList = priceRoomModelTypeMapper.selectByObjectId(id);
        List<PriceRoomModelTypeRespVO> priceRoomModelTypeRespVOS = BeanUtils.toBean(roomModelTypeList, PriceRoomModelTypeRespVO.class);
        priceRoomModelTypeRespVOS.stream().forEach(item -> {
            MapUtils.findAndThen(singleSettingRespVOMap, item.getId(), item::setSingleSetting);
        });
        Map<Long, List<PriceRoomModelTypeRespVO>> roomModelTypeMap = CollectionUtils.convertMultiMap(priceRoomModelTypeRespVOS, PriceRoomModelTypeRespVO::getRoomModelId);
        priceRoomModelRespVOS.stream().forEach(item -> {
            MapUtils.findAndThen(roomModelTypeMap, item.getRoomModelId(), itemTypeList -> item.setRoomModelTypeList(BeanUtils.toBean(itemTypeList, PriceRoomModelTypeRespVO.class)));
        });
        respVO.setRoomModelList(priceRoomModelRespVOS);
        List<PriceFloorDO> floorDOList = priceFloorService.getListByObjectId(id);
        respVO.setFloorList(BeanUtils.toBean(floorDOList, PriceFloorRespVO.class));
        List<PriceAreaDO> areaList = priceAreaService.getListByObjectId(id);
        respVO.setAreaList(BeanUtils.toBean(areaList, PriceAreaRespVO.class));
        //区域基准价
        List<BasicPriceAreaDO> basicPriceAreaList = basicPriceAreaMapper.selectListByObjectId(id);
        respVO.setBasicAreaList(BeanUtils.toBean(basicPriceAreaList, BasicPriceAreaRespVO.class));
        //附加产品
        List<PriceSpuRespVO> spuList = priceSpuService.getListByObjectId(id);
        respVO.setSpuList(spuList);
        return respVO;
    }

    @Override
    public PageResult<PriceTemplateDO> getPriceTemplatePage(PriceTemplatePageReqVO pageReqVO) {
        return priceTemplateMapper.selectPage(pageReqVO);
    }

    @Override
    public List<PriceTemplateDO> getListSimple(PriceTemplateReqVO reqVO) {
        return priceTemplateMapper.selectList(reqVO);
    }

    @Override
    public void copyPriceTemplate(PriceTemplateSaveReqVO updateReqVO) {
        Long id = IdUtil.getSnowflakeNextId();
        // 更新
        PriceTemplateDO updateObj = BeanUtils.toBean(updateReqVO, PriceTemplateDO.class);
        updateObj.setId(id);
        priceTemplateMapper.insert(updateObj);
        saveRelation(id, updateReqVO);
    }

    private void saveRelation(Long objectId, PriceTemplateSaveReqVO vo) {
        //插入房型价格系数
        List<PriceRoomModelDO> roomModelList = vo.getRoomModelList();
        roomModelList.stream().forEach(roomModel -> {
            roomModel.setObjectId(objectId);
        });
        priceRoomModelMapper.insertBatch(roomModelList);

        //插入单人票设置
        List<PriceSingleSettingDO> singleSettingList = new ArrayList<>();
        //插入房型入住价格模式
        List<PriceRoomModelTypeDO> roomModelTypeDOList = new ArrayList<>();
        roomModelList.stream().forEach(roomModel -> {
            List<PriceRoomModelTypeDO> roomModelTypeList = roomModel.getRoomModelTypeList();
            if(!CollectionUtils.isAnyEmpty(roomModelTypeList)) {
                roomModelTypeList.stream().forEach(roomModelType -> {
                    Long roomModelTypeId = IdUtil.getSnowflakeNextId();
                    roomModelType.setRoomModelId(roomModel.getRoomModelId());
                    roomModelType.setRoomModelName(roomModel.getRoomModelName());
                    roomModelType.setObjectId(objectId);
                    roomModelType.setId(roomModelTypeId);
                    roomModelTypeDOList.add(roomModelType);
                    PriceSingleSettingDO singleSetting = roomModelType.getSingleSetting();
                    if(singleSetting != null) {
                        singleSetting.setRoomModelId(roomModel.getRoomModelId());
                        singleSetting.setObjectId(objectId);
                        singleSetting.setRoomModelTypeId(roomModelTypeId);
                        singleSettingList.add(singleSetting);
                    }
                });
            }
        });
        if(singleSettingList.size() > 0) {
            priceSingleSettingMapper.insertBatch(singleSettingList);
        }
        if(roomModelTypeDOList.size() > 0) {
            priceRoomModelTypeMapper.insertBatch(roomModelTypeDOList);
        }
        //插入楼层价格系数
        List<PriceFloorDO> floorList = vo.getFloorList();
        floorList.stream().forEach(floor -> {
            floor.setObjectId(objectId);
        });
        if(floorList.size() > 0) {
            priceFloorMapper.insertBatch(floorList);
        }
        //插入区域加价
        List<PriceAreaDO> areaList = vo.getAreaList();
        List<PriceAreaDO> insertAreaList = new ArrayList<>();
        areaList.stream().forEach(area -> {
            area.setObjectId(objectId);
            insertAreaList.add(area);
            List<PriceAreaDO> children = area.getChildren();
            if (children != null) {
                children.stream().forEach(child -> {
                    child.setObjectId(objectId);
                    child.setParentAreaId(area.getAreaId());
                    child.setParentAreaName(area.getAreaName());
                    insertAreaList.add(child);
                });
            }
        });
        if(insertAreaList.size() > 0) {
            priceAreaMapper.insertBatch(insertAreaList);
        }

        // 插入区域基准价
        List<BasicPriceAreaDO> basicAreaList = vo.getBasicAreaList();
        List<BasicPriceAreaDO> insertBasicAreaList = new ArrayList<>();
        basicAreaList.stream().forEach(area -> {
            area.setObjectId(objectId);
            insertBasicAreaList.add(area);
            List<BasicPriceAreaDO> children = area.getChildren();
            if (children != null) {
                children.stream().forEach(child -> {
                    child.setObjectId(objectId);
                    child.setParentAreaId(area.getAreaId());
                    child.setParentAreaName(area.getAreaName());
                    insertBasicAreaList.add(child);
                });
            }
        });
        if(insertBasicAreaList.size() > 0) {
            basicPriceAreaMapper.insertBatch(insertBasicAreaList);
        }
        // 插入附加产品
        List<PriceSpuDO> spuList = vo.getSpuList();
        if(!CollectionUtils.isAnyEmpty(spuList)) {
            spuList.stream().forEach(spu -> {
                spu.setObjectId(objectId);
            });
            priceSpuMapper.insertBatch(spuList);
        }
    }

    private void deleteRelation(Long objectId) {
        priceRoomModelMapper.deleteByObjectId(objectId);
        priceFloorMapper.deleteByObjectId(objectId);
        priceSingleSettingMapper.deleteByObjectId(objectId);
        priceAreaMapper.deleteByObjectId(objectId);
        priceSpuMapper.deleteByObjectId(objectId);
        basicPriceAreaMapper.deleteByObjectId(objectId);
        priceRoomModelTypeMapper.deleteByObjectId(objectId);
    }

}