package com.yc.ship.module.resource.service.route;

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.resource.controller.admin.route.vo.ResourceRoutePageReqVO;
import com.yc.ship.module.resource.controller.admin.route.vo.ResourceRouteSaveReqVO;
import com.yc.ship.module.resource.controller.app.route.vo.AppResourceRoutePageReqVO;
import com.yc.ship.module.resource.controller.app.route.vo.AppResourceRoutePriceVO;
import com.yc.ship.module.resource.controller.app.route.vo.AppResourceRouteRespVO;
import com.yc.ship.module.resource.dal.dataobject.route.ResourceRouteDO;
import com.yc.ship.module.resource.dal.dataobject.routecost.ResourceRouteCostDO;
import com.yc.ship.module.resource.dal.dataobject.routelight.ResourceRouteLightDO;
import com.yc.ship.module.resource.dal.dataobject.routetrip.ResourceRouteTripDO;
import com.yc.ship.module.resource.dal.dataobject.routetripdetail.ResourceRouteTripDetailDO;
import com.yc.ship.module.resource.dal.mysql.route.ResourceRouteMapper;
import com.yc.ship.module.resource.dal.mysql.routecost.ResourceRouteCostMapper;
import com.yc.ship.module.resource.dal.mysql.routelight.ResourceRouteLightMapper;
import com.yc.ship.module.resource.dal.mysql.routetrip.ResourceRouteTripMapper;
import com.yc.ship.module.resource.dal.mysql.routetripdetail.ResourceRouteTripDetailMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.yc.ship.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.yc.ship.module.resource.enums.ErrorCodeConstants.ROUTE_NOT_EXISTS;

/**
 * 航线管理 Service 实现类
 *
 * @author lfy
 */
@Service
@Validated
public class ResourceRouteServiceImpl implements ResourceRouteService {

    @Resource
    private ResourceRouteMapper routeMapper;

    @Resource
    private ResourceRouteLightMapper routeLightMapper;

    @Resource
    private ResourceRouteCostMapper routeCostMapper;

    @Resource
    private ResourceRouteTripMapper routeTripMapper;

    @Resource
    private ResourceRouteTripDetailMapper routeTripDetailMapper;

    @Override
    @Transactional
    public Long createRoute(ResourceRouteSaveReqVO createReqVO) {
        // 插入
        ResourceRouteDO route = BeanUtils.toBean(createReqVO, ResourceRouteDO.class);
        routeMapper.insert(route);
        // 处理航线亮点
        handleRouteLights(route.getId(), createReqVO.getRouteLights());
        // 处理费用包含
        handleRouteCosts(route.getId(), createReqVO.getRouteCosts());
        // 处理每日详情
        handleRouteTrips(route.getId(), createReqVO.getRouteTrips());
        // 返回
        return route.getId();
    }

    private void handleRouteTrips(Long id, List<ResourceRouteTripDO> routeTrips) {
        routeTripMapper.deleteByRouteId(id);
        routeTrips.stream().forEach(routeTrip -> {
            Long tripId = IdWorker.getId();
            routeTrip.setRouteId(id);
            routeTrip.setId(tripId);
            List<ResourceRouteTripDetailDO> routeTripDetails = routeTrip.getRouteTripDetails();
            if(routeTripDetails != null) {
                routeTripDetails.stream().forEach(routeTripDetail -> {
                    routeTripDetail.setTripId(tripId);
                    routeTripDetail.setRouteId(id);
                });
            }
        });
        routeTripMapper.insertBatch(routeTrips);
        List<ResourceRouteTripDetailDO> list = CollectionUtils.convertList(routeTrips, ResourceRouteTripDO::getRouteTripDetails).stream().flatMap(List::stream).collect(Collectors.toList());
        routeTripDetailMapper.deleteByRouteId(id);
        routeTripDetailMapper.insertBatch(list);
    }

    private void handleRouteCosts(Long id, List<ResourceRouteCostDO> routeCosts) {
        routeCostMapper.deleteByRouteId(id);
        routeCosts.stream().forEach(routeCost -> {
            routeCost.setRouteId(id);
        });
        routeCostMapper.insertBatch(routeCosts);
    }

    private void handleRouteLights(Long routeId, List<ResourceRouteLightDO> routeLights) {
        // 删除
        routeLightMapper.deleteByRouteId(routeId);
        routeLights.stream().forEach(routeLight -> {
            routeLight.setRouteId(routeId);
        });
        // 添加
        routeLightMapper.insertBatch(routeLights);
    }

    @Override
    @Transactional
    public void updateRoute(ResourceRouteSaveReqVO updateReqVO) {
        // 校验存在
        validateRouteExists(updateReqVO.getId());
        // 更新
        ResourceRouteDO updateObj = BeanUtils.toBean(updateReqVO, ResourceRouteDO.class);
        routeMapper.updateById(updateObj);
        // 处理航线亮点
        handleRouteLights(updateReqVO.getId(), updateReqVO.getRouteLights());
        // 处理费用包含
        handleRouteCosts(updateReqVO.getId(), updateReqVO.getRouteCosts());
        // 处理每日详情
        handleRouteTrips(updateReqVO.getId(), updateReqVO.getRouteTrips());
    }

    @Override
    @Transactional
    public void deleteRoute(Long id) {
        // 校验存在
        validateRouteExists(id);
        // 删除
        routeMapper.deleteById(id);
        routeTripMapper.deleteByRouteId(id);
        routeTripDetailMapper.deleteByRouteId(id);
        routeCostMapper.deleteByRouteId(id);
        routeLightMapper.deleteByRouteId(id);
    }

    private void validateRouteExists(Long id) {
        if (routeMapper.selectById(id) == null) {
            throw exception(ROUTE_NOT_EXISTS);
        }
    }

    @Override
    public ResourceRouteDO getRoute(Long id) {
        ResourceRouteDO routeDO = routeMapper.selectById(id);
        List<ResourceRouteLightDO> lightDOList = routeLightMapper.selectByRouteId(id);
        routeDO.setRouteLights(lightDOList);
        List<ResourceRouteCostDO> costDOList = routeCostMapper.selectByRouteId(id);
        routeDO.setRouteCosts(costDOList);
        List<ResourceRouteTripDO> tripDOList = routeTripMapper.selectByRouteId(id);
        List<ResourceRouteTripDetailDO> tripDetailDOList = routeTripDetailMapper.selectByRouteId(id);
        Map<Long, List<ResourceRouteTripDetailDO>> detailMap = CollectionUtils.convertMultiMap(tripDetailDOList, ResourceRouteTripDetailDO::getTripId);
        tripDOList.stream().forEach(tripDO -> {
            MapUtils.findAndThen(detailMap, tripDO.getId(), detailList -> tripDO.setRouteTripDetails(detailList));
        });
        routeDO.setRouteTrips(tripDOList);
        return routeDO;
    }

    @Override
    public PageResult<ResourceRouteDO> getRoutePage(ResourceRoutePageReqVO pageReqVO) {
        return routeMapper.selectPage(pageReqVO);
    }

    @Override
    public List<ResourceRouteDO> getRouteList() {
        return routeMapper.selectList();
    }

    @Override
    public List<ResourceRouteDO> getEnableRouteList() {
        return routeMapper.selectEnableList();
    }

    @Override
    public List<ResourceRouteDO> getList(List<Long> routeIds) {
        if(routeIds.isEmpty()) {
            return Collections.emptyList();
        }
        return routeMapper.selectByIds(routeIds);
    }

    @Override
    public ResourceRouteDO getById(Long routeId) {
        return routeMapper.selectById(routeId);
    }

    @Override
    public PageResult<AppResourceRouteRespVO> getAppRoutePage(AppResourceRoutePageReqVO pageReqVO) {
        PageResult<ResourceRouteDO> page = routeMapper.selectAppPageNew(pageReqVO);
        return BeanUtils.toBean(page, AppResourceRouteRespVO.class);
    }

    @Override
    public AppResourceRoutePriceVO getMinAndMaxPrice(Long routeId, Long shipId) {
        return routeMapper.selectMinAndMaxPrice(routeId, shipId);
    }

}