package com.sw.mes.store.api.controller;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.sw.mes.core.dto.store.*;
import com.sw.mes.core.dto.store.StoreDataBo;
import com.sw.mes.store.dto.*;
import com.sw.mes.core.enums.MessageEnum;
import com.sw.mes.core.response.Result;
import com.sw.mes.core.response.ResultGenerator;
import com.sw.mes.store.api.interfaces.supplier.WarehouseSupplierService;
import com.sw.mes.store.dto.LockInventoryDto;
import com.sw.mes.store.dto.StoreDto;
import com.sw.mes.store.dto.WarehouseAllotBillDto;
import com.sw.mes.store.dto.WarehouseInputReturnDto;
import com.sw.mes.store.dto.WarehouseInventoryDto;
import com.sw.mes.store.entity.*;
import com.sw.mes.store.service.WarehouseOutputBillService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @Description 提供给外部系统调用的接口
 * @Author wupeng
 * @Date 2023/12/28 17:25
 **/
@RestController
@RequestMapping("/warehouse/supplier")
@Slf4j
@Api(tags = "线边仓提供给外部系统调用的接口")
public class WarehouseSupplierController {

    @Autowired
    private WarehouseSupplierService warehouseSupplierService;
    @Autowired
    private WarehouseOutputBillService warehouseOutputBillService;

    /**
     * 入库申请接口
     **/
    @ApiOperation(value = "入库申请")
    @PostMapping("/inputApply")
    public Result<String> inputApply(@RequestBody @Valid @ApiParam(value = "入库单对象") WarehouseInputBillBo inputBillBo) {
        try {
            String billNo = warehouseSupplierService.input(inputBillBo);
            return ResultGenerator.success(billNo);
        } catch (Exception e) {
            return ResultGenerator.fail(e.getMessage());
        }
    }

    /**
     * 入库申请接口
     **/
    @ApiOperation(value = "入库申请")
    @PostMapping("/inputApplyData")
    public Result<WarehouseInputReturnDto> inputApplyData(@RequestBody @Valid @ApiParam(value = "入库单对象") WarehouseInputBillBo inputBillBo) {
        try {
            WarehouseInputReturnDto warehouseInputReturnDto = warehouseSupplierService.inputData(inputBillBo);
            return ResultGenerator.success(warehouseInputReturnDto);
        } catch (Exception e) {
            return ResultGenerator.fail(e.getMessage());
        }
    }

    /**
     * 取消入库申请接口
     **/
    @ApiOperation(value = "取消入库申请")
    @PostMapping("/cancelInputApply")
    public Result cancelInputApply(@RequestParam("billNo") @ApiParam(value = "入库单号") String billNo) {
        try {
            warehouseSupplierService.cancelInput(billNo);
        } catch (Exception e) {
            return ResultGenerator.fail(e.getMessage());
        }
        return ResultGenerator.success();
    }

    /**
     * 出库申请接口
     **/
    @ApiOperation(value = "出库申请")
    @PostMapping("/outputApply")
    public Result<String> outputApply(@RequestBody @Valid @ApiParam(value = "出库单对象") WarehouseOutputBillBo outputBillBo) {
        try {
            String billNo = warehouseSupplierService.output(outputBillBo);
            return ResultGenerator.success(billNo);
        } catch (Exception e) {
            return ResultGenerator.fail(e.getMessage());
        }
    }

    @ApiOperation(value = "出库申请返回对象")
    @PostMapping("/outputApplyData")
    public Result<WarehouseInputReturnDto> outputApplyData(@RequestBody @Valid @ApiParam(value = "出库单对象") WarehouseOutputBillBo outputBillBo) {
        try {
            WarehouseInputReturnDto warehouseInputReturnDto = warehouseSupplierService.outputData(outputBillBo);
            return ResultGenerator.success(warehouseInputReturnDto);
        } catch (Exception e) {
            return ResultGenerator.fail(e.getMessage());
        }
    }

    /**
     * 取消入库申请接口
     **/
    @ApiOperation(value = "取消出库申请")
    @PostMapping("/cancelOutputApply")
    public Result cancelOutputApply(@RequestParam("billNo") @ApiParam(value = "出库单号") String billNo) {
        try {
            warehouseSupplierService.cancelOutput(billNo);
        } catch (Exception e) {
            return ResultGenerator.fail(e.getMessage());
        }
        return ResultGenerator.success();
    }

    @ApiOperation(value = "创建入库单AND调拨单AND出库单接口")
    @PostMapping("/createInputAndAllotAndOut")
    public Result createInputAndAllotAndOut(@RequestBody @Valid StoreDto storeDto) {
        warehouseSupplierService.createInputAndAllotAndOut(storeDto);
        return ResultGenerator.success();
    }

    /**
     * 通过批次号获取库存信息
     */
    @ApiOperation(value = "通过批次号获取库存信息")
    @GetMapping("/findByBatchNo")
    public Result<WarehouseInventory> findByBatchNo(@RequestParam("batchNo") @ApiParam(value = "批次号") String batchNo) {
        try {
            List<WarehouseInventory> inventories = warehouseSupplierService.findByBatchNo(batchNo);
            if (ObjectUtils.isEmpty(inventories)) {
                return ResultGenerator.fail("未查询到数据!");
            }
            //所有批次号对应的主数据料号都应该是一样的话返回一条数据即可，否则返回错误信息
            Map<String, List<WarehouseInventory>> inventoriesGroups = inventories.stream()
                    .collect(Collectors.groupingBy(WarehouseInventory::getMaterialModelCode));
            if (inventoriesGroups.size() == 1) {
                return ResultGenerator.success(MessageEnum.SUCCESS.getMessage(), inventories.get(0));
            } else {
                return ResultGenerator.fail("查询数据存在错误数据!");
            }
        } catch (Exception e) {
            return ResultGenerator.fail(e.getMessage());
        }
    }

    @ApiOperation(value = "对外创建调拨单接口")
    @PostMapping("/createAllotBill")
    public Result createAllotBill(@RequestBody @Valid @ApiParam(value = "调拨单对象") WarehouseAllotBillDto warehouseAllotBillDto) {
        Boolean allotBill = warehouseSupplierService.createAllotBill(warehouseAllotBillDto);
        if (allotBill) {
            return ResultGenerator.success("调拨单创建成功!", null);
        } else {
            return ResultGenerator.fail("调拨单创建失败!");
        }
    }

    /**
     * 获取当前节点的所有子节点id
     *
     * @param id
     * @return
     */
    @GetMapping("/getChildrenId")
    @ApiOperation("获取当前节点的所有子节点id")
    public Result<List<Long>> getByWarehouseModelId(@RequestParam("id") Long id) {
        List<WarehouseModelDto> storeLocations = warehouseSupplierService.getChildLocationIds(id);
        List<Long> result = storeLocations.stream().map(storeLocationId -> {
            return storeLocationId.getId();
        }).collect(Collectors.toList());
        return ResultGenerator.success(result);
    }

    @ApiOperation(value = "对外申请入库且是否自动出库接口")
    @PostMapping("/automaticInputOut")
    public Result AutomaticInputOut(@RequestBody @Valid @ApiParam(value = "申请入库单对象") WarehouseInputBillBo inputBillBo) {
        Result result = warehouseSupplierService.automaticInputOut(inputBillBo);
        if (result.getCode().equals(200)) {
            return ResultGenerator.success("生成入库单成功!", result.getData());
        } else {
            return ResultGenerator.fail("生成入库单成功!");
        }
    }

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

    @ApiOperation(value = "线边仓模型详细信息")
    @GetMapping("/getById")
    public Result<WarehouseModelDto> getById(@RequestParam @ApiParam(value = "线边仓模型id") Long id) {
        WarehouseModel warehouseModel = warehouseSupplierService.getById(id);
        if (null == warehouseModel) {
            return ResultGenerator.fail("线边仓模型不存在");
        }
        WarehouseModelDto warehouseModelDto = new WarehouseModelDto();
        BeanUtils.copyProperties(warehouseModel, warehouseModelDto);
        return ResultGenerator.success(warehouseModelDto);
    }

    @ApiOperation(value = "同步物料主数据")
    @PostMapping("/syncMaterial")
    public Result syncMaterial(@RequestBody List<WarehouseMaterialBo> warehouseMaterialBos) {
        Result result = warehouseSupplierService.syncMaterial(warehouseMaterialBos);
        if (result.getCode().equals(200)) {
            return ResultGenerator.success("同步物料主数据成功!", null);
        } else {
            return ResultGenerator.fail("同步物料主数据失败!");
        }
    }

    @ApiOperation(value = "通过箱号或者托号获取批次号")
    @PostMapping("/findBatchNoBySerialNoOrTraceId")
    public Result<List<String>> findBatchNoBySerialNoOrTraceId(@ApiParam(value = "箱号", type = "query") @RequestParam String serialNo,
                                                               @ApiParam(value = "托号", type = "query") @RequestParam String traceId) {
        List<String> batchNos = warehouseSupplierService.findBatchNoBySerialNoOrTraceId(serialNo, traceId);
        if (ObjectUtils.isNotEmpty(batchNos) && batchNos.size() > 0) {
            return ResultGenerator.success(batchNos);
        }
        return ResultGenerator.fail("未查询到相关批次号!");
    }

    @ApiOperation(value = "锁定库存")
    @PostMapping("/lockInventory")
    public Result lockInventory(@RequestBody @Valid @ApiParam(value = "锁定库存对象") List<LockInventoryDto> lockInventoryDto) {
        try {
            warehouseSupplierService.lockInventory(lockInventoryDto);
        } catch (Exception e) {
            return ResultGenerator.fail("【锁定库存失败:】" + e.getMessage());
        }
        return ResultGenerator.success();
    }

    @ApiOperation(value = "解锁库存")
    @PostMapping("/unLockInventory")
    public Result unLockInventory(@RequestBody @Valid @ApiParam(value = "解锁库存对象") List<LockInventoryDto> lockInventoryDto) {
        try {
            warehouseSupplierService.unLockInventory(lockInventoryDto);
        } catch (Exception e) {
            return ResultGenerator.fail("【解锁库存失败:】" + e.getMessage());
        }
        return ResultGenerator.success();
    }

    @ApiOperation(value = "通过物料料号获取入库明细")
    @PostMapping("/findWarehouseInputBillDetailsByMaterialCode")
    public Result<List<WarehouseInputBillDetailBo>> findWarehouseInputBillDetailsByMaterialCode(@ApiParam(value = "物料料号", type = "query") @RequestParam String materialCode) {
        try {
            List<WarehouseInputBillDetailBo> billDetailsByMaterialCode = warehouseSupplierService.findWarehouseInputBillDetailsByMaterialCode(materialCode);
            return ResultGenerator.success(billDetailsByMaterialCode);
        } catch (Exception e) {
            return ResultGenerator.fail("【通过物料料号获取入库明细失败:】" + e.getMessage());
        }
    }

    @ApiOperation(value = "通过物料料号获取库存明细")
    @PostMapping("/findWarehouseInventoryByMaterialCode")
    public Result<List<WarehouseInventoryDto>> findWarehouseInventoryByMaterialCode(@ApiParam(value = "物料料号", type = "query") @RequestParam String materialCode) {
        try {
            List<WarehouseInventoryDto> inventoryByMaterialCode = warehouseSupplierService.findWarehouseInventoryByMaterialCode(materialCode);
            return ResultGenerator.success(inventoryByMaterialCode);
        } catch (Exception e) {
            return ResultGenerator.fail("【通过物料料号获取库存明细:】" + e.getMessage());
        }
    }

    @ApiOperation(value = "通过物料料号获取出库明细")
    @PostMapping("/findWarehouseOutputBillDetailByMaterialCode")
    public Result<List<WarehouseOutputBillDetailBo>> findWarehouseOutputBillDetailByMaterialCode(@ApiParam(value = "物料料号", type = "query") @RequestParam String materialCode) {
        try {
            List<WarehouseOutputBillDetailBo> warehouseOutputBillDetailBos = warehouseSupplierService.findWarehouseOutputBillDetailByMaterialCode(materialCode);
            return ResultGenerator.success(warehouseOutputBillDetailBos);
        } catch (Exception e) {
            return ResultGenerator.fail("【通过物料料号获取出库明细:】" + e.getMessage());
        }
    }

    @ApiOperation(value = "通过出库单号获取出库信息")
    @PostMapping("/findWarehouseOutputBillByCode")
    public Result<WarehouseOutputBillBo> findWarehouseOutputBillByCode(@ApiParam(value = "出库单号", type = "query") @RequestParam String outputBillNo) {
        try {
            WarehouseOutputBillBo warehouseOutputBillBo = new WarehouseOutputBillBo();
            WarehouseOutputBill warehouseOutputBillByCode = warehouseOutputBillService.findWarehouseOutputBillByCode(outputBillNo);
            BeanUtils.copyProperties(warehouseOutputBillByCode, warehouseOutputBillBo);
            return ResultGenerator.success(warehouseOutputBillBo);
        } catch (Exception e) {
            return ResultGenerator.fail("【通过出库单号获取出库信息:】" + e.getMessage());
        }
    }

    @ApiOperation(value = "确认出库")
    @PostMapping("/deduction")
    public Result<String> output(@RequestBody @Valid @ApiParam(value = "出库单对象") WarehouseOutputBillBo warehouseOutputBillBo) {
        try {
            WarehouseOutputBill warehouseOutputBill = new WarehouseOutputBill();
            BeanUtils.copyProperties(warehouseOutputBillBo, warehouseOutputBill,"outputBillDetails");
            List<WarehouseOutputBillDetail> outputBillDetails = new ArrayList<>();
            warehouseOutputBillBo.getOutputBillDetails().forEach(entity->{
                WarehouseOutputBillDetail warehouseOutputBillDetail = new WarehouseOutputBillDetail();
                BeanUtils.copyProperties(entity,warehouseOutputBillDetail);
                warehouseOutputBillDetail.setOutputBillId(warehouseOutputBill.getId());
                warehouseOutputBillDetail.setOutputBillNo(warehouseOutputBill.getBillNo());
                outputBillDetails.add(warehouseOutputBillDetail);
            });
            warehouseOutputBill.setOutputBillDetails(outputBillDetails);
            //审核通过，扣减库存
            warehouseOutputBillService.auditDeductionAtomic(warehouseOutputBill);
            return ResultGenerator.success();
        } catch (Exception e) {
            return ResultGenerator.fail(e.getMessage());
        }
    }

    @ApiOperation(value = "拒绝出库")
    @PostMapping("/rejectApply")
    public Result<String> rejectApply(@RequestBody @Valid @ApiParam(value = "出库单对象") WarehouseOutputBillBo warehouseOutputBillBo) {
        try {
            WarehouseOutputBill warehouseOutputBill = new WarehouseOutputBill();
            BeanUtils.copyProperties(warehouseOutputBillBo, warehouseOutputBill,"outputBillDetails");
            List<WarehouseOutputBillDetail> outputBillDetails = new ArrayList<>();
            warehouseOutputBillBo.getOutputBillDetails().forEach(entity->{
                WarehouseOutputBillDetail warehouseOutputBillDetail = new WarehouseOutputBillDetail();
                BeanUtils.copyProperties(entity,warehouseOutputBillDetail);
                warehouseOutputBillDetail.setOutputBillId(warehouseOutputBill.getId());
                warehouseOutputBillDetail.setOutputBillNo(warehouseOutputBill.getBillNo());
                outputBillDetails.add(warehouseOutputBillDetail);
            });
            warehouseOutputBill.setOutputBillDetails(outputBillDetails);
            //拒绝出库
            warehouseOutputBillService.rejectApply(warehouseOutputBill);
            return ResultGenerator.success();
        } catch (Exception e) {
            return ResultGenerator.fail(e.getMessage());
        }
    }

    @ApiOperation(value = "线边仓操作回滚")
    @PostMapping("/rollBackStore")
    public Result rollBackStore(@RequestBody @Valid @ApiParam(value = "线边仓回滚对象") StoreDataBo storeDataBo) {
        return warehouseSupplierService.rollBackStore(storeDataBo);
    }

    @PostMapping("/getDistinctMaterialCode")
    public Result<Set<String>> getDistinctMaterialCode(@RequestParam int page, @RequestParam int pageSize) {
        try {
            Set<String> set = warehouseSupplierService.getDistinctMaterialCode(page, pageSize);
            return ResultGenerator.success(set);
        } catch (Exception e) {
            return ResultGenerator.fail("【getDistinctMaterialCode:】" + e.getMessage());
        }
    }
}
