package net.lab1024.sa.admin.module.business.wms.base.location.service.impl;

import cn.idev.excel.FastExcel;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import net.lab1024.sa.admin.constant.UsageStatusEnum;
import net.lab1024.sa.admin.module.business.wms.base.area.domain.entity.AreaEntity;
import net.lab1024.sa.admin.module.business.wms.base.area.service.AreaQueryService;
import net.lab1024.sa.admin.module.business.wms.base.location.domain.entity.LocationEntity;
import net.lab1024.sa.admin.module.business.wms.base.location.domain.form.*;
import net.lab1024.sa.admin.module.business.wms.base.location.manager.LocationManager;
import net.lab1024.sa.admin.module.business.wms.base.location.service.LocationQueryService;
import net.lab1024.sa.admin.module.business.wms.base.location.service.LocationService;
import net.lab1024.sa.admin.util.JoinerResult;
import net.lab1024.sa.admin.util.ResponseDTOUtil;
import net.lab1024.sa.admin.util.ValidateDictKeyUtil;
import net.lab1024.sa.base.common.code.UserErrorCode;
import net.lab1024.sa.base.common.domain.ResponseDTO;
import net.lab1024.sa.base.common.exception.BusinessException;
import net.lab1024.sa.base.common.util.SmartBeanUtil;
import net.lab1024.sa.base.common.util.SmartRequestUtil;
import net.lab1024.sa.base.common.util.SmartStringUtil;
import net.lab1024.sa.base.module.support.dict.constant.DictConst;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Slf4j
public class LocationServiceImpl implements LocationService {

    @Resource
    private LocationManager locationManager;

    @Resource
    private AreaQueryService areaQueryService;

    @Resource
    private LocationQueryService locationQueryService;

    @Resource
    private ValidateDictKeyUtil ValidateDictKeyUtil;

    /**
     * 添加
     *
     * @param addForm 添加参数
     * @return ResponseDTO<String>
     */
    @Transactional(rollbackFor = Exception.class)
    public ResponseDTO<String> add(LocationAddForm addForm) {
        LocationEntity existingLocation = locationQueryService.queryByLocationCode(addForm.getLocationCode());
        if (existingLocation != null) {
            return ResponseDTO.error(UserErrorCode.ALREADY_EXIST, UserErrorCode.ALREADY_EXIST.getMsg());
        }
        LocationEntity locationEntity = SmartBeanUtil.copy(addForm, LocationEntity.class);
        locationManager.save(locationEntity);
        return ResponseDTO.ok();
    }

    /**
     * 更新
     *
     * @param updateForm 更新参数
     * @return ResponseDTO<String>
     */
    @Transactional(rollbackFor = Exception.class)
    public ResponseDTO<String> update(LocationUpdateForm updateForm) {
        LocationEntity existingLocation = locationQueryService.queryByLocationCode(updateForm.getLocationCode());
        if (existingLocation != null && !existingLocation.getLocationId().equals(updateForm.getLocationId())) {
            return ResponseDTO.error(UserErrorCode.ALREADY_EXIST, UserErrorCode.ALREADY_EXIST.getMsg());
        }
        LocationEntity locationEntity = SmartBeanUtil.copy(updateForm, LocationEntity.class);
        //更新并更新缓存
        locationManager.update(locationEntity);
        return ResponseDTO.ok();
    }

    /**
     * 批量删除
     *
     * @param idList 删除参数
     * @return ResponseDTO<String>
     */
    @Transactional(rollbackFor = Exception.class)
    public ResponseDTO<String> batchDelete(List<Long> idList) {
        if (CollectionUtils.isEmpty(idList)) {
            return ResponseDTO.userErrorParam(UserErrorCode.PARAM_ERROR.getMsg());
        }
        //删除并删除缓存
        locationManager.batchDelete(idList);
        return ResponseDTO.ok();
    }

    /**
     * 单个删除
     *
     * @param locationId 入参
     * @return ResponseDTO<String>
     */
    @Transactional(rollbackFor = Exception.class)
    public ResponseDTO<String> delete(Long locationId) {
        if (null == locationId) {
            return ResponseDTO.userErrorParam(UserErrorCode.PARAM_ERROR.getMsg());
        }

        //删除并删除缓存
        locationManager.deleteById(locationId);
        return ResponseDTO.ok();
    }

    /**
     * 批量调整
     *
     * @param multipleAdjust 参数
     * @return ResponseDTO<String>
     */
    @Transactional(rollbackFor = Exception.class)
    public ResponseDTO<String> multipleAdjust(MultipleAdjust multipleAdjust) {

        if (CollectionUtils.isEmpty(multipleAdjust.getLocationIds())) {
            return ResponseDTO.userErrorParam(UserErrorCode.PARAM_ERROR.getMsg());
        }

        //查询库位
        Map<Long, LocationEntity> locationEntityMap = locationQueryService.queryByLocationIdsToMap(multipleAdjust.getLocationIds());

        //调整状态，true:空闲;false:占用
        String status = multipleAdjust.getStatus() ? UsageStatusEnum.FREE.getValue() : UsageStatusEnum.USED.getValue();

        //是否启用，true:启用;false:禁用
        Boolean disabledFlag = multipleAdjust.getDisabledFlag();

        //批量更新
        List<LocationEntity> updateToLocation = new ArrayList<>();

        //更新状态
        locationEntityMap.forEach((locationId, location) -> {
            location.setStatus(status);
            location.setDisabledFlag(disabledFlag);
            updateToLocation.add(location);
        });

        if (CollectionUtils.isNotEmpty(updateToLocation)) {
            //更新并更新缓存
            locationManager.batchUpdate(updateToLocation);
        }


        return ResponseDTO.ok();


    }

    /**
     * 创建库位
     *
     * @param locationCode 库位编码
     * @param areaId       区域ID
     * @param locationRow  行
     * @param locationLine 列
     * @param locationCow  层
     * @param locationType 类型
     * @return LocationEntity
     */
    public LocationEntity createLocation(String locationCode, Long areaId, String locationRow, String locationLine, String locationCow, String locationType) {
        return LocationEntity.builder()
                .locationCode(locationCode)
                .locationName(locationCode)
                .status(UsageStatusEnum.FREE.getValue())
                .areaId(areaId)
                .disabledFlag(true)
                .locationRow(locationRow)
                .locationLine(locationLine)
                .locationCow(locationCow)
                .locationType(locationType)
                .createUserId(SmartRequestUtil.getRequestUser().getUserId())
                .createUserName(SmartRequestUtil.getRequestUser().getUserName())
                .build();
    }


    public LocationEntity createLocation(String locationCode, Long areaId, String locationType) {
        int firstDashIndex = locationCode.indexOf('-');
        if (firstDashIndex == -1) {
            return createLocation(locationCode, areaId, null, null, null, locationType);
        }
        String[] parts = locationCode.substring(firstDashIndex + 1).split("-");
        if (parts.length < 3) {
            return createLocation(locationCode, areaId, null, null, null, locationType);
        }
        String row = parts[0];
        String col = parts[1];
        String layer = parts[2];
        return createLocation(locationCode, areaId, row, col, layer, locationType);
    }

    /**
     * 批量新增
     *
     * @param locationCodes 库位集合
     * @param areaId        库区
     * @param locationType  库位类型
     */
    public void multipleInsert(List<String> locationCodes, Long areaId, String locationType) {
        List<LocationEntity> insertToLocation = new ArrayList<>();
        for (String locationCode : locationCodes) {
            LocationEntity location = createLocation(locationCode, areaId, locationType);
            insertToLocation.add(location);
        }
        if (CollectionUtils.isNotEmpty(insertToLocation)) {
            // 批量新增并更新缓存
            locationManager.saveBatch(insertToLocation);
        }
    }

    /**
     * 批量新增
     *
     * @param multipleInsert 参数
     * @return ResponseDTO<String>
     */
    @Transactional(rollbackFor = Exception.class)
    public ResponseDTO<String> multipleInsert(MultipleInsert multipleInsert) {
        //入参的所以库位集合
        List<String> locationCodes = multipleInsert.getLocationCodes();

        //查询数据库已存在的库位集合
        List<LocationEntity> list = locationQueryService.queryByLocationCodes(locationCodes);
        JoinerResult resultMsg = JoinerResult.createJoiner();
        if (CollectionUtils.isNotEmpty(list)) {
            List<String> existingLocationCodes = list.stream()
                    .map(LocationEntity::getLocationCode)
                    .toList();
            // 获取两个集合的交集说明库位已存在；提示错误
            List<String> getIntersection = SmartStringUtil.getIntersection(locationCodes, existingLocationCodes);
            resultMsg.getErrorMsg().add(getIntersection + "库位已存在,新增失败");
            // 获取两个集合的非交集说明库位不存在；批量新增
            List<String> difference = SmartStringUtil.getDifference(locationCodes, existingLocationCodes);
            if (CollectionUtils.isNotEmpty(difference)) {
                //批量新增
                multipleInsert(difference, multipleInsert.getAreaId(), multipleInsert.getLocationType());
                resultMsg.getSussMsg().add(difference + "库位新增成功");
            }

            return ResponseDTOUtil.buildResponseDTO(resultMsg);
        }

        // 没有查询到库位，直接新增
        multipleInsert(locationCodes, multipleInsert.getAreaId(), multipleInsert.getLocationType());
        resultMsg.getSussMsg().add(locationCodes + "库位新增成功");

        return ResponseDTOUtil.buildResponseDTO(resultMsg);
    }

    /**
     * 库位导入
     *
     * @param file 上传文件
     * @return ResponseDTO<String>
     */
    @Transactional(rollbackFor = Exception.class)
    public ResponseDTO<String> importLocations(MultipartFile file) {
        List<LocationsImportForm> dataList;
        try {
            dataList = FastExcel.read(file.getInputStream()).head(LocationsImportForm.class)
                    .sheet()
                    .doReadSync();
        } catch (IOException e) {
            throw new BusinessException("数据格式存在问题，无法读取");
        }
        if (CollectionUtils.isEmpty(dataList)) {
            return ResponseDTO.userErrorParam("数据为空");
        }

        //获取所有的库区
        List<String> areaNames = dataList.stream().map(LocationsImportForm::getAreaName).toList();

        //验证库区
        Map<String, AreaEntity> areaMap = validateArea(areaNames);

        //获取所有的库位类型
        List<String> locationTypes = dataList.stream().map(LocationsImportForm::getLocationType).toList();

        //验证库位类型
        Map<String, String> locationTypeMap = ValidateDictKeyUtil.validateDictCodes(locationTypes, DictConst.LOC_TYPE.getValue());

        //获取所有的库位编码
        List<String> locationCodes = dataList.stream().map(LocationsImportForm::getLocationCode).toList();

        //查询数据库存在的库位编码
        Map<String, LocationEntity> exitLocationMap = locationQueryService.queryByLocationCodesToMap(locationCodes);

        List<LocationEntity> insertToLocation = new ArrayList<>();
        List<LocationEntity> updateToLocation = new ArrayList<>();
        for (LocationsImportForm locationsImportForm : dataList) {
            //库区
            AreaEntity area = areaMap.get(locationsImportForm.getAreaName());

            //库位类型
            String locationType = locationTypeMap.get(locationsImportForm.getLocationType());

            //库位
            LocationEntity location = exitLocationMap.get(locationsImportForm.getLocationCode());

            //库位为空则新增，否则更新
            if (location == null) {
                insertToLocation.add(createLocation(locationsImportForm.getLocationCode(), area.getAreaId(), locationType));
            } else {
                updateToLocation.add(createLocation(locationsImportForm.getLocationCode(), area.getAreaId(), locationType));
            }
        }

        JoinerResult resultMsg = JoinerResult.createJoiner();
        return ResponseDTOUtil.buildResponseDTO(insertToLocation, updateToLocation, locationManager::saveBatch, locationManager::batchUpdate, resultMsg);
    }

    /**
     * 验证库区
     *
     * @param areaNames 库区集合
     * @return Map<String, AreaEntity>
     */
    public Map<String, AreaEntity> validateArea(List<String> areaNames) {
        //查询数据库存在的库区
        Map<String, AreaEntity> areaMap = areaQueryService.queryByAreaNamesToMap(areaNames);
        if (areaMap.isEmpty()) {
            throw new BusinessException(areaNames + "库区不存在,在库区管理中维护库区");
        }

        //获取map的key集合
        List<String> exitAreaNameList = areaMap.keySet().stream().toList();
        //获取两个集合的非交集说明库区不存在；提示错误
        List<String> diffAreaName = SmartStringUtil.getDifference(areaNames, exitAreaNameList);
        if (CollectionUtils.isNotEmpty(diffAreaName)) {
            throw new BusinessException(diffAreaName + "库区不存在,在库区管理中维护库区");
        }
        return areaMap;
    }

    /**
     * 更新库位状态
     *
     * @param locationId 库位id
     * @param status     状态
     */
    @Transactional(rollbackFor = Exception.class)
    public void updateLocationStatus(Long locationId, String status) {
        if (locationId != null) {
            LocationEntity location = locationManager.queryLocation(locationId);
            if (location != null) {
                location.setStatus(status);
                locationManager.update(location);
            }
        }
    }
}
