package com.sw.mes.store.controller;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sw.mes.core.api.system.YbFeignClients;
import com.sw.mes.core.dto.MaterialModelDto;
import com.sw.mes.core.dto.store.WarehouseInventoryBo;
import com.sw.mes.core.exception.BusinessException;
import com.sw.mes.core.response.ResponsePage;
import com.sw.mes.core.response.Result;
import com.sw.mes.core.response.ResultGenerator;
import com.sw.mes.core.utils.DynmaicQueryWrapper;
import com.sw.mes.core.utils.ExcelUtil;
import com.sw.mes.core.utils.RequestPage;
import com.sw.mes.core.utils.StringUtils;
import com.sw.mes.store.dto.AvailableInventoryDto;
import com.sw.mes.store.dto.WarehouseInventoryDto;
import com.sw.mes.store.entity.WarehouseInventory;
import com.sw.mes.store.entity.WarehouseModel;
import com.sw.mes.store.service.WarehouseInventoryService;
import com.sw.mes.store.service.WarehouseModelService;
import io.swagger.annotations.*;
import lombok.extern.slf4j.Slf4j;
import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.ObjectUtils;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore;

import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Author wupeng
 * @Description 库存表接口
 * @Date 11:58 2023/7/31
 * @Param
 * @return
 **/
@RestController
@RequestMapping("/warehouse/inventory")
@Slf4j
@Api(tags = "线边仓-库存表")
public class WarehouseInventoryController {
    @Autowired
    private ModelMapper modelMapper;

    @Autowired
    private WarehouseInventoryService warehouseInventoryService;
    @Autowired
    private YbFeignClients ybFeignClients;
    @Autowired
    private WarehouseModelService warehouseModelService;

    @ApiOperation(value = "分页查询库存信息-根据物料分组查询")
    @ApiImplicitParams({@ApiImplicitParam(name = "rows", value = "行数", dataType = "integer", paramType = "query"),
            @ApiImplicitParam(name = "page", value = "页码", dataType = "integer", paramType = "query"),
            @ApiImplicitParam(name = "search_LIKE_materialName", value = "物料名称", dataType = "string", paramType = "query"),
            @ApiImplicitParam(name = "search_LIKE_materialCode", value = "物料编码", dataType = "string", paramType = "query"),
            @ApiImplicitParam(name = "search_LIKE_materialTypeName", value = "物料类型", dataType = "string", paramType = "query"),
            @ApiImplicitParam(name = "search_IN_warehouseModelId", value = "仓库位置id", dataType = "integer", paramType = "query"),
            @ApiImplicitParam(name = "search_EQ_batchNo", value = "批次号", dataType = "string", paramType = "query"),
            @ApiImplicitParam(name = "search_EQ_uniqueCode", value = "唯一码", dataType = "string", paramType = "query"),
            @ApiImplicitParam(name = "search_IN_warehouseId", value = "仓库位置id", dataType = "integer", paramType = "query"),})
    @GetMapping("/groupByMaterial")
    public Result<ResponsePage<WarehouseInventory>> groupByMaterial(ServletRequest request, @ApiIgnore RequestPage requestPage) {
        Page<WarehouseInventory> pages = warehouseInventoryService.groupByMaterial(request, requestPage);
        ResponsePage<WarehouseInventory> responsePage = new ResponsePage<>(pages.getRecords(), pages.getTotal());
        return ResultGenerator.success(responsePage);
    }

    @ApiOperation(value = "分页查询库存详情信息")
    @ApiImplicitParams({@ApiImplicitParam(name = "rows", value = "行数", dataType = "integer", paramType = "query"),
            @ApiImplicitParam(name = "page", value = "页码", dataType = "integer", paramType = "query"),
            @ApiImplicitParam(name = "search_LIKE_materialModelCode", value = "物料编码", dataType = "string", paramType = "query"),
            @ApiImplicitParam(name = "search_LIKE_materialModelName", value = "物料名称", dataType = "string", paramType = "query"),
            @ApiImplicitParam(name = "search_LIKE_materialTypeName", value = "物料类型", dataType = "string", paramType = "query"),
            @ApiImplicitParam(name = "search_IN_warehouseId", value = "仓库ID", dataType = "string", paramType = "query")})
    @GetMapping("/listByPage")
    public Result<ResponsePage<WarehouseInventory>> listByPage(ServletRequest request, @ApiIgnore RequestPage requestPage) {
        Page<WarehouseInventory> page = warehouseInventoryService.listByPage(request, requestPage);
        ResponsePage<WarehouseInventory> responsePage = new ResponsePage<>(page.getRecords(), page.getTotal());
        return ResultGenerator.success(responsePage);
    }

    @ApiOperation(value = "导出库存明细记录接口")
    @GetMapping("/exportExcel")
    public void export(ServletRequest request, HttpServletResponse response) {
        try {
            List<WarehouseInventory> entities = warehouseInventoryService.findAllWarehouseInventory(request);
            List<WarehouseInventoryDto> dtos = entities.stream()
                    .map(storeOutputBill -> toLazyDto(storeOutputBill))
                    .collect(Collectors.toList());
            ExcelUtil.exportExcel(dtos, "库存明细记录", WarehouseInventoryDto.class, response);
        } catch (Exception e) {
            throw new RuntimeException("库存明细记录历导出失败，错误信息：" + e.getMessage());
        }
    }

    @ApiOperation(value = "库存详细信息")
    @GetMapping("/{id}")
    public Result<WarehouseInventoryDto> get(@PathVariable @ApiParam(value = "库存id") Integer id) {
        WarehouseInventory warehouseInventory = warehouseInventoryService.getById(id);
        if (StringUtils.isNotEmpty(warehouseInventory.getMaterialModelCode())) {
            Result<MaterialModelDto> materialByCode = ybFeignClients.getMaterialByCode(warehouseInventory.getMaterialModelCode());
            if (materialByCode.getCode().equals(200) && !ObjectUtils.isEmpty(materialByCode.getData())) {
                warehouseInventory.setMaterialCategoryName(materialByCode.getData().getMaterialTypeDto().getName());
            }
        }
        if (null == warehouseInventory) {
            return ResultGenerator.fail("该库存物料不存在");
        }
        return ResultGenerator.success(toEagerDto(warehouseInventory));
    }

    /**
     * 刷新物料库存数量
     **/
    @ApiOperation(value = "刷新库存")
    @PostMapping("/refresh")
    public Result refresh(@RequestBody @Valid @ApiParam(value = "库存对象") List<WarehouseInventoryDto> inventoryDtos, BindingResult bindingResult) {
        if (bindingResult.hasErrors()) {
            return ResultGenerator.fail(bindingResult.getFieldError().getDefaultMessage());
        }
        try {
            //查询物料明细的库存量
            Map<String, BigDecimal> result = warehouseInventoryService.getQuantity(inventoryDtos);
            return ResultGenerator.success(result);
        } catch (Exception e) {
            return ResultGenerator.fail(e.getMessage());
        }
    }

    /**
     * @return 库存信息
     * @Author wupeng
     * @Description 根据扫描的结果查询物料库存数据，扫描结果可能是 唯一码、批次号、料号
     * @Date 13:18 2023/8/7
     * @Param scanCode 扫描结果
     * @Param materialIds 要出库的物料编码集合
     **/
    @ApiOperation(value = "根据扫描的结果查询物料库存数据")
    @GetMapping("/scan")
    public Result scan(@RequestParam @ApiParam(value = "扫码结果") String scanCode) {
        try {
            //查询物料明细的库存量
            List<WarehouseInventory> inventories = warehouseInventoryService.getByScanCode(scanCode);
            List<WarehouseInventoryDto> result = inventories.stream().map(this::toLazyDto).collect(Collectors.toList());
            return ResultGenerator.success(result);
        } catch (Exception e) {
            return ResultGenerator.fail(e.getMessage());
        }
    }

    @ApiOperation(value = "根据批次号,库位编码库存数据")
    @GetMapping("/getByBatchNoAndWarehouseCode")
    public Result<WarehouseInventoryBo> getByBatchNoAndWarehouseCode(@RequestParam String batchNo, @RequestParam String warehouseCode) {
        try {
            //查询物料明细的库存量
            WarehouseModel warehouseModel = warehouseModelService.getCode(warehouseCode);
            if (null != warehouseModel) {
                WarehouseInventory inventories = warehouseInventoryService.getByBatchWarehouseCode(batchNo, warehouseCode);
                List<String> uniqueCodeList = warehouseInventoryService.getUniqueCodesByBatchNo(batchNo);
                if (null == inventories) {
                    return ResultGenerator.fail("根据批次号、库位编码查询，无库存");
                }
                WarehouseInventoryBo eagerBo = toEagerBo(inventories);
                if (CollectionUtil.isNotEmpty(uniqueCodeList) && uniqueCodeList.get(0) != null) {
                    eagerBo.setUniqueCodeList(uniqueCodeList);
                }

                return ResultGenerator.success(eagerBo);
            }
        } catch (Exception e) {
            return ResultGenerator.fail("根据批次号、库位编码库存数据失败:" + e.getMessage());
        }
        return ResultGenerator.success();
    }

    @ApiOperation(value = "根据批次号,物料编码,库位编码库存数据")
    @GetMapping("/getByMaterialAndBatchNoAndWarehouseCode")
    public Result<WarehouseInventoryBo> getByMaterialAndBatchNoAndWarehouseCode(@RequestParam String batchNo, @RequestParam String materialModelCode, @RequestParam String warehouseCode) {
        try {
            //查询物料明细的库存量
            WarehouseModel warehouseModel = warehouseModelService.getCode(warehouseCode);
            if (null != warehouseModel) {
                List<WarehouseInventory> warehouseInventories = warehouseInventoryService.getByMaterialAndBatchNoAndWarehouseCode(batchNo, materialModelCode, warehouseCode);
                if (null != warehouseInventories && warehouseInventories.size() > 0) {
                    WarehouseInventoryBo eagerBo = toEagerBo(warehouseInventories.get(0));
                    return ResultGenerator.success(eagerBo);
                }
            }
        } catch (Exception e) {
            return ResultGenerator.fail("根据批次号,物料编码,库位编码库存数据:" + e.getMessage());
        }
        return ResultGenerator.success();
    }

    /**
     * 查询可用库存
     *
     * @param materialCodes 物料编号列表
     * @return 可用库存列表
     */
    @PostMapping("/getAvailableInventorys")
    public Result<List<AvailableInventoryDto>> getAvailableInventorys(@RequestBody List<String> materialCodes) {
        return ResultGenerator.success(warehouseInventoryService.getAvailableInventorys(materialCodes));
    }

    /**
     * @return com.sw.common.warehouse.server.dto.WarehouseInventoryDto
     * @Author wupeng
     * @Description 根据唯一码、料号查询库存信息
     * @Date 19:08 2023/8/14
     * @Param
     **/
    @ApiOperation(value = "根据唯一码查询库存信息")
    @GetMapping("/getByUniqueCode")
    public Result getByUniqueCode(@RequestParam @ApiParam(value = "唯一码") String uniqueCode, @RequestParam @ApiParam(value = "料号") String materialCode) {
        try {
            //查询物料明细的库存量
            LambdaQueryWrapper<WarehouseInventory> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(WarehouseInventory::getUniqueCode, uniqueCode);
//            queryWrapper.eq(WarehouseInventory::getMaterialModelCode, materialCode);
            queryWrapper.eq(WarehouseInventory::getDel, false);
            WarehouseInventory inventory = warehouseInventoryService.getOne(queryWrapper);
            if (inventory == null) {
                throw new BusinessException("唯一码【" + uniqueCode + "】对应的库存数据不存在，请重新扫描或输入唯一码！");
            }
            return ResultGenerator.success(inventory);
        } catch (Exception e) {
            return ResultGenerator.fail(e.getMessage());
        }
    }

    @ApiOperation(value = "根据批次号and库位获取库存信息")
    @GetMapping("/getByBatchWarehouseId")
    public Result getByBatchWarehouseId(@RequestParam @ApiParam(value = "批次号") String batchNo, @RequestParam @ApiParam(value = "库位id") Long warehouseId) {
        WarehouseInventory batchWarehouse = warehouseInventoryService.getByBatchWarehouseId(batchNo, warehouseId);
        return ResultGenerator.success(batchWarehouse);
    }

    @ApiOperation(value = "根据晶段批次获取库存信息")
    @GetMapping("/getByCrystalNo")
    public Result<WarehouseInventoryDto> getByCrystalNo(@RequestParam @ApiParam(value = "晶编编号") String crystalNo) {
        WarehouseInventory batchWarehouse = warehouseInventoryService.getByCrystalNo(crystalNo);
        WarehouseInventoryDto eagerDto = toEagerDto(batchWarehouse);
        return ResultGenerator.success(eagerDto);
    }

    @ApiOperation(value = "根据物料号获取库存信息")
    @GetMapping("/getByMaterialCode")
    public Result<List<WarehouseInventoryDto>> getByMaterialCode(@RequestParam @ApiParam(value = "物料号") String materialCode) {
        List<WarehouseInventory> inventories = warehouseInventoryService.getByMaterialCode(materialCode);
        List<WarehouseInventoryDto> inventoryDtos = inventories.stream().map(entity -> toEagerDto(entity)).collect(Collectors.toList());
        return ResultGenerator.success(inventoryDtos);
    }

    public WarehouseInventoryDto toLazyDto(WarehouseInventory entity) {
        return modelMapper.map(entity, WarehouseInventoryDto.class);
    }

    public WarehouseInventoryDto toEagerDto(WarehouseInventory entity) {
        WarehouseInventoryDto dto = modelMapper.map(entity, WarehouseInventoryDto.class);
        return dto;
    }

    public WarehouseInventoryBo toEagerBo(WarehouseInventory entity) {
        WarehouseInventoryBo bo = modelMapper.map(entity, WarehouseInventoryBo.class);
        return bo;
    }

    public WarehouseInventory fromDto(WarehouseInventoryDto dto) {
        return modelMapper.map(dto, WarehouseInventory.class);
    }


}