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

import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
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.controller.admin.pricevoyage.vo.PriceVoyagePageReqVO;
import com.yc.ship.module.product.controller.admin.pricevoyage.vo.PriceVoyageRespVO;
import com.yc.ship.module.product.controller.admin.pricevoyage.vo.PriceVoyageSaveReqVO;
import com.yc.ship.module.product.controller.app.voyage.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.pricevoyage.PriceVoyageDO;
import com.yc.ship.module.product.dal.dataobject.voyage.VoyageDO;
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.pricevoyage.PriceVoyageMapper;
import com.yc.ship.module.product.dal.mysql.voyage.VoyageMapper;
import com.yc.ship.module.product.enums.ErrorCodeConstants;
import com.yc.ship.module.product.service.pricearea.PriceAreaService;
import com.yc.ship.module.product.service.priceroommodel.PriceRoomModelService;
import com.yc.ship.module.product.service.pricespu.PriceSpuService;
import com.yc.ship.module.product.service.voyage.VoyageService;
import com.yc.ship.module.resource.controller.admin.roommodel.vo.ResourceRoomModelRespVO;
import com.yc.ship.module.resource.dal.dataobject.roommodel.ResourceRoomModelDO;
import com.yc.ship.module.resource.service.roommodel.ResourceRoomModelService;
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.*;

/**
 * 航次价格 Service 实现类
 *
 * @author 管理员
 */
@Service
@Validated
public class PriceVoyageServiceImpl implements PriceVoyageService {

    @Resource
    private PriceVoyageMapper priceVoyageMapper;

    @Resource
    private PriceRoomModelMapper priceRoomModelMapper;

    @Resource
    private PriceFloorMapper priceFloorMapper;

    @Resource
    private PriceSingleSettingMapper priceSingleSettingMapper;

    @Resource
    private PriceAreaMapper priceAreaMapper;

    @Resource
    private PriceSpuMapper priceSpuMapper;

    @Resource
    private BasicPriceAreaMapper basicPriceAreaMapper;

    @Resource
    private PriceRoomModelTypeMapper priceRoomModelTypeMapper;

    @Resource
    private PriceRoomModelService priceRoomModelService;

    @Resource
    private PriceSpuService priceSpuService;

    @Resource
    private ResourceRoomModelService roomModelService;

    @Resource
    private PriceAreaService priceAreaService;

    @Resource
    private VoyageMapper voyageMapper;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createPriceVoyage(PriceVoyageSaveReqVO createReqVO) {
        PriceVoyageDO priceVoyageDO = priceVoyageMapper.selectByVoyageId(createReqVO.getVoyageId());
        if(priceVoyageDO != null) {
            throw exception(PRICE_VOYAGE_EXISTS);
        }
        // 插入
        PriceVoyageDO priceVoyage = BeanUtils.toBean(createReqVO, PriceVoyageDO.class);
        priceVoyageMapper.insert(priceVoyage);
        Long id = priceVoyage.getId();
        saveRelation(id, createReqVO);
        // 返回
        return id;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updatePriceVoyage(PriceVoyageSaveReqVO updateReqVO) {
        Long id = updateReqVO.getId();
        // 校验存在
        validatePriceVoyageExists(id);
        // 更新
        PriceVoyageDO updateObj = BeanUtils.toBean(updateReqVO, PriceVoyageDO.class);
        priceVoyageMapper.updateById(updateObj);
        deleteRelation(id);
        saveRelation(id, updateReqVO);
    }

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

    private void validatePriceVoyageExists(Long id) {
        if (priceVoyageMapper.selectById(id) == null) {
            throw exception(PRICE_VOYAGE_NOT_EXISTS);
        }
    }

    @Override
    public PriceVoyageRespVO getPriceVoyage(Long id) {
        PriceVoyageDO priceVoyageDO = priceVoyageMapper.selectById(id);
        PriceVoyageRespVO respVO = BeanUtils.toBean(priceVoyageDO, PriceVoyageRespVO.class);
        List<PriceRoomModelDO> roomModelDOList = priceRoomModelService.getListByObjectId(id);
        List<PriceRoomModelRespVO> priceRoomModelRespVOS = BeanUtils.toBean(roomModelDOList, PriceRoomModelRespVO.class);
        List<PriceSingleSettingDO> singleSettingList = priceSingleSettingMapper.selectByObjectId(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.forEach(item -> {
            MapUtils.findAndThen(singleSettingRespVOMap, item.getId(), item::setSingleSetting);
        });
        Map<Long, List<PriceRoomModelTypeRespVO>> roomModelTypeMap = CollectionUtils.convertMultiMap(priceRoomModelTypeRespVOS, PriceRoomModelTypeRespVO::getRoomModelId);
        priceRoomModelRespVOS.forEach(item -> {
            MapUtils.findAndThen(roomModelTypeMap, item.getRoomModelId(), item::setRoomModelTypeList);
        });
        respVO.setRoomModelList(priceRoomModelRespVOS);
        List<PriceFloorDO> floorDOList = priceFloorMapper.selectListByObjectId(id);
        respVO.setFloorList(BeanUtils.toBean(floorDOList, PriceFloorRespVO.class));
        List<PriceAreaDO> areaList = priceAreaMapper.selectListByObjectId(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<PriceVoyageDO> getPriceVoyagePage(PriceVoyagePageReqVO pageReqVO) {
        return priceVoyageMapper.selectPage(pageReqVO);
    }

    @Override
    public PriceVoyageRespVO getByVoyageId(Long voyageId) {
        PriceVoyageDO priceVoyage = priceVoyageMapper.selectByVoyageId(voyageId);
        if(priceVoyage == null) {
            throw exception(ErrorCodeConstants.PRICE_VOYAGE_NOT_EXISTS);
        }
        Long id = priceVoyage.getId();
        PriceVoyageRespVO respVO = BeanUtils.toBean(priceVoyage, PriceVoyageRespVO.class);
        List<PriceRoomModelDO> roomModelDOList = priceRoomModelService.getListByObjectId(id);
        List<PriceRoomModelRespVO> priceRoomModelRespVOS = BeanUtils.toBean(roomModelDOList, PriceRoomModelRespVO.class);
        List<PriceSingleSettingDO> singleSettingDO = priceSingleSettingMapper.selectByObjectId(id);
        List<PriceSingleSettingRespVO> priceSingleSettingRespVOS = BeanUtils.toBean(singleSettingDO, PriceSingleSettingRespVO.class);
        Map<Long, PriceSingleSettingRespVO> settingRespVOMap = CollectionUtils.convertMap(priceSingleSettingRespVOS, PriceSingleSettingRespVO::getRoomModelTypeId);

        List<Long> roomModelIds = CollectionUtils.convertList(priceRoomModelRespVOS, item -> item.getRoomModelId());
        List<ResourceRoomModelDO> roomModelList = roomModelService.getList(roomModelIds);
        Map<Long, ResourceRoomModelDO> resourceRoomModelDOMap = CollectionUtils.convertMap(roomModelList, item -> item.getId());
        List<PriceRoomModelTypeDO> roomModelTypeList = priceRoomModelTypeMapper.selectByObjectId(id);
        List<PriceRoomModelTypeRespVO> priceRoomModelTypeRespVOS = BeanUtils.toBean(roomModelTypeList, PriceRoomModelTypeRespVO.class);
        priceRoomModelTypeRespVOS.forEach(item -> {
            MapUtils.findAndThen(settingRespVOMap, item.getId(), item::setSingleSetting);
        });
        Map<Long, List<PriceRoomModelTypeRespVO>> roomModelTypeMap = CollectionUtils.convertMultiMap(priceRoomModelTypeRespVOS, PriceRoomModelTypeRespVO::getRoomModelId);
        priceRoomModelRespVOS.forEach(item -> {
            MapUtils.findAndThen(roomModelTypeMap, item.getRoomModelId(), item::setRoomModelTypeList);
            if(resourceRoomModelDOMap.get(item.getRoomModelId()) != null) {
                item.setRoomModel(BeanUtils.toBean(resourceRoomModelDOMap.get(item.getRoomModelId()), ResourceRoomModelRespVO.class));
            }
        });
        respVO.setRoomModelList(priceRoomModelRespVOS);
        List<PriceFloorDO> floorDOList = priceFloorMapper.selectListByObjectId(id);
        respVO.setFloorList(BeanUtils.toBean(floorDOList, PriceFloorRespVO.class));
        List<PriceAreaDO> areaList = priceAreaMapper.selectListByObjectId(id);
        respVO.setAreaList(BeanUtils.toBean(areaList, PriceAreaRespVO.class));
        List<PriceCountryRespVO> countryList = priceAreaService.getCountryPriceByObjectId(id);
        respVO.setCountryList(countryList);
        //区域基准价
        List<BasicPriceAreaDO> basicPriceAreaList = basicPriceAreaMapper.selectListByObjectId(id);
        respVO.setBasicAreaList(BeanUtils.toBean(basicPriceAreaList, BasicPriceAreaRespVO.class));
        List<BasicPriceCountryRespVO> basicPriceCountryRespVOS = basicPriceAreaMapper.selectCountryPriceByObjectId(id);
        respVO.setBasicCountryList(basicPriceCountryRespVOS);
        //附加产品
        List<PriceSpuRespVO> spuList = priceSpuService.getListByObjectId(id);
        respVO.setSpuList(spuList);
        return respVO;
    }

    @Override
    public List<AppVoyageCalendarPriceRespVO> getListCalendarPrice(AppVoyageCalendarPriceReqVO reqVO) {
        return priceVoyageMapper.selectListCalendarPrice(reqVO);
    }

    @Override
    public List<AppRoomModelPriceRespVO> getRoomModelListByVoyageId(Long voyageId) {
        return priceVoyageMapper.selectRoomModelListByVoyageId(voyageId);
    }

    @Override
    public AppPriceVoyageRespVO getAppPrice(Long voyageId, Long roomModelId) {
        PriceVoyageDO priceVoyage = priceVoyageMapper.selectByVoyageId(voyageId);
        if(priceVoyage == null) {
            throw exception(ErrorCodeConstants.PRICE_VOYAGE_NOT_EXISTS);
        }
        Long id = priceVoyage.getId();
        AppPriceVoyageRespVO respVO = BeanUtils.toBean(priceVoyage, AppPriceVoyageRespVO.class);
        // 设置航次信息
        VoyageDO voyage = voyageMapper.selectById(voyageId);
        if(voyage != null) {
            respVO.setVoyage(BeanUtils.toBean(voyage, AppVoyageRespVO.class));
            respVO.setVoyageName(voyage.getName());
        }
        PriceRoomModelDO priceRoomModelDO = priceRoomModelService.getListByObjectIdAndRoomModelId(id, roomModelId);
        PriceRoomModelRespVO priceRoomModelRespVO = BeanUtils.toBean(priceRoomModelDO, PriceRoomModelRespVO.class);
        List<PriceSingleSettingDO> singleSettingDO = priceSingleSettingMapper.selectByObjectIdAndRoomModelId(id, roomModelId);
        List<PriceSingleSettingRespVO> priceSingleSettingRespVOS = BeanUtils.toBean(singleSettingDO, PriceSingleSettingRespVO.class);
        Map<Long, PriceSingleSettingRespVO> settingRespVOMap = CollectionUtils.convertMap(priceSingleSettingRespVOS, PriceSingleSettingRespVO::getRoomModelTypeId);
        ResourceRoomModelDO roomModelDO = roomModelService.getRoomModel(roomModelId);
        List<PriceRoomModelTypeDO> roomModelTypeList = priceRoomModelTypeMapper.selectByObjectIdAndRoomModelId(id,roomModelId);
        List<PriceRoomModelTypeRespVO> priceRoomModelTypeRespVOS = BeanUtils.toBean(roomModelTypeList, PriceRoomModelTypeRespVO.class);
        priceRoomModelTypeRespVOS.forEach(item -> {
            MapUtils.findAndThen(settingRespVOMap, item.getId(), item::setSingleSetting);
        });
        priceRoomModelRespVO.setRoomModelTypeList(priceRoomModelTypeRespVOS);
        priceRoomModelRespVO.setRoomModel(BeanUtils.toBean(roomModelDO, ResourceRoomModelRespVO.class));
        respVO.setPriceRoomModel(priceRoomModelRespVO);
        List<PriceFloorDO> floorDOList = priceFloorMapper.selectListByObjectId(id);
        respVO.setFloorList(BeanUtils.toBean(floorDOList, PriceFloorRespVO.class));
        List<PriceAreaDO> areaList = priceAreaMapper.selectListByObjectId(id);
        respVO.setAreaList(BeanUtils.toBean(areaList, PriceAreaRespVO.class));
        List<PriceCountryRespVO> countryList = priceAreaService.getCountryPriceByObjectId(id);
        respVO.setCountryList(countryList);
        //区域基准价
        List<BasicPriceAreaDO> basicPriceAreaList = basicPriceAreaMapper.selectListByObjectId(id);
        respVO.setBasicAreaList(BeanUtils.toBean(basicPriceAreaList, BasicPriceAreaRespVO.class));
        List<BasicPriceCountryRespVO> basicPriceCountryRespVOS = basicPriceAreaMapper.selectCountryPriceByObjectId(id);
        respVO.setBasicCountryList(basicPriceCountryRespVOS);
        //附加产品
        List<PriceSpuRespVO> spuList = priceSpuService.getListByObjectId(id);
        respVO.setSpuList(spuList);
        return respVO;
    }

    private void saveRelation(Long objectId, PriceVoyageSaveReqVO vo) {
        //插入房型价格系数
        List<PriceRoomModelDO> roomModelList = vo.getRoomModelList();
        roomModelList.forEach(roomModel -> {
            roomModel.setObjectId(objectId);
        });
        priceRoomModelMapper.insertBatch(roomModelList);
        //插入楼层价格系数
        List<PriceFloorDO> floorList = vo.getFloorList();
        floorList.forEach(floor -> {
            floor.setObjectId(objectId);
        });
        priceFloorMapper.insertBatch(floorList);

        //插入单人票设置
        List<PriceSingleSettingDO> singleSettingList = new ArrayList<>();
        //插入房型入住价格模式
        List<PriceRoomModelTypeDO> roomModelTypeDOList = new ArrayList<>();
        roomModelList.forEach(roomModel -> {
            List<PriceRoomModelTypeDO> roomModelTypeList = roomModel.getRoomModelTypeList();
            if(!CollectionUtils.isAnyEmpty(roomModelTypeList)) {
                roomModelTypeList.forEach(roomModelType -> {
                    Long roomModelTypeId = IdUtil.getSnowflakeNextId();
                    IdWorker.getId();
                    roomModelType.setId(roomModelTypeId);
                    roomModelType.setRoomModelId(roomModel.getRoomModelId());
                    roomModelType.setRoomModelName(roomModel.getRoomModelName());
                    roomModelType.setObjectId(objectId);
                    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.isEmpty()) {
            priceSingleSettingMapper.insertBatch(singleSettingList);
        }
        if(!roomModelTypeDOList.isEmpty()) {
            priceRoomModelTypeMapper.insertBatch(roomModelTypeDOList);
        }
        //插入区域加价
        List<PriceAreaDO> areaList = vo.getAreaList();
        List<PriceAreaDO> insertAreaList = new ArrayList<>();
        areaList.forEach(area -> {
            area.setObjectId(objectId);
            insertAreaList.add(area);
            List<PriceAreaDO> children = area.getChildren();
            if (children != null) {
                children.forEach(child -> {
                    child.setObjectId(objectId);
                    child.setParentAreaId(area.getAreaId());
                    child.setParentAreaName(area.getAreaName());
                    insertAreaList.add(child);
                });
            }
        });
        priceAreaMapper.insertBatch(insertAreaList);

        // 插入区域基准价
        List<BasicPriceAreaDO> basicAreaList = vo.getBasicAreaList();
        List<BasicPriceAreaDO> insertBasicAreaList = new ArrayList<>();
        basicAreaList.forEach(area -> {
            area.setObjectId(objectId);
            insertBasicAreaList.add(area);
            List<BasicPriceAreaDO> children = area.getChildren();
            if (children != null) {
                children.forEach(child -> {
                    child.setObjectId(objectId);
                    child.setParentAreaId(area.getAreaId());
                    child.setParentAreaName(area.getAreaName());
                    insertBasicAreaList.add(child);
                });
            }
        });
        if(!insertBasicAreaList.isEmpty()) {
            basicPriceAreaMapper.insertBatch(insertBasicAreaList);
        }

        // 插入附加产品
        List<PriceSpuDO> spuList = vo.getSpuList();
        if(!CollectionUtils.isAnyEmpty(spuList)) {
            spuList.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);
    }

}