package cn.iocoder.yudao.module.system.controller.admin.biz;

import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import cn.iocoder.yudao.module.system.controller.admin.biz.vo.ImportResultVO;
import cn.iocoder.yudao.module.system.controller.admin.biz.vo.common.TenantIdsReqVO;
import cn.iocoder.yudao.module.system.controller.admin.biz.vo.materialio.*;
import cn.iocoder.yudao.module.system.controller.admin.biz.vo.materialio.inbound.MaterialInboundOrderExportExcelVO;
import cn.iocoder.yudao.module.system.controller.admin.biz.vo.materialio.inbound.MaterialInboundOrderItemRespVO;
import cn.iocoder.yudao.module.system.controller.admin.biz.vo.materialio.inbound.MaterialInboundOrderRespVO;
import cn.iocoder.yudao.module.system.controller.admin.biz.vo.materialio.inboundreturn.MaterialInboundReturnOrderPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.biz.vo.materialio.inboundreturn.MaterialInboundReturnOrderPageRespVO;
import cn.iocoder.yudao.module.system.controller.admin.biz.vo.materialio.inboundreturn.MaterialInboundReturnOrderRespVO;
import cn.iocoder.yudao.module.system.controller.admin.biz.vo.materialio.inventory.MaterialInventoryFlowReqVO;
import cn.iocoder.yudao.module.system.controller.admin.biz.vo.materialio.inventory.MaterialInventoryFlowRespVO;
import cn.iocoder.yudao.module.system.controller.admin.biz.vo.materialio.inventory.MaterialInventoryReportExcelVO;
import cn.iocoder.yudao.module.system.controller.admin.biz.vo.materialio.inventory.MaterialInventoryReportPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.biz.vo.materialio.inventory.MaterialInventoryReportRespVO;
import cn.iocoder.yudao.module.system.controller.admin.biz.vo.materialio.outbound.MaterialOutboundByInboundReqVO;
import cn.iocoder.yudao.module.system.controller.admin.biz.vo.materialio.outbound.MaterialOutboundOrderExportExcelVO;
import cn.iocoder.yudao.module.system.controller.admin.biz.vo.materialio.outbound.MaterialOutboundOrderRespVO;
import cn.iocoder.yudao.module.system.controller.admin.biz.vo.materialio.outboundreturn.MaterialOutboundReturnOrderPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.biz.vo.materialio.outboundreturn.MaterialOutboundReturnOrderPageRespVO;
import cn.iocoder.yudao.module.system.controller.admin.biz.vo.materialio.outboundreturn.MaterialOutboundReturnOrderRespVO;
import cn.iocoder.yudao.module.system.dal.dataobject.biz.MaterialInboundOrderDO;
import cn.iocoder.yudao.module.system.dal.dataobject.biz.MaterialOutboundOrderDO;
import cn.iocoder.yudao.module.system.service.biz.MaterialIoService;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;

/**
 * 管理后台 - 物资出入库 Controller
 */
@Tag(name = "管理后台 - 物资出入库")
@RestController
@RequestMapping("/material-io")
@Validated
public class MaterialIoController {

    @Resource
    private MaterialIoService materialIoService;

    @PostMapping("/inbound")
    @Operation(summary = "物资入库")
    @TenantIgnore
    public CommonResult<Long> inbound(@Valid @RequestBody MaterialIoOrderSaveReqVO reqVO) {
        return success(materialIoService.inbound(reqVO));
    }

    @PostMapping("/outbound")
    @Operation(summary = "物资出库")
    @TenantIgnore
    public CommonResult<Long> outbound(@Valid @RequestBody MaterialIoOrderSaveReqVO reqVO) {
        return success(materialIoService.outbound(reqVO));
    }

    @PostMapping("/outbound-by-inbound")
    @Operation(summary = "根据入库单生成出库单")
    @TenantIgnore
    public CommonResult<Long> outboundByInbound(@Valid @RequestBody MaterialOutboundByInboundReqVO reqVO) {
        return success(materialIoService.outboundByInbound(reqVO));
    }

    @PostMapping("/outbound-return")
    @Operation(summary = "出库退回")
    @TenantIgnore
    public CommonResult<Long> outboundReturn(@Valid @RequestBody MaterialIoOrderSaveReqVO reqVO) {
        return success(materialIoService.outboundReturn(reqVO));
    }

    @PostMapping("/inbound-return")
    @Operation(summary = "入库退回")
    @TenantIgnore
    public CommonResult<Long> inboundReturn(@Valid @RequestBody MaterialIoOrderSaveReqVO reqVO) {
        return success(materialIoService.inboundReturn(reqVO));
    }

    @PutMapping("/update")
    @Operation(summary = "编辑单据")
    @TenantIgnore
    public CommonResult<Boolean> update(@Valid @RequestBody MaterialIoOrderSaveReqVO reqVO) {
        materialIoService.update(reqVO);
        return success(true);
    }

    @GetMapping("/page")
    @Operation(summary = "分页查询")
    @TenantIgnore
    public CommonResult<PageResult<MaterialIoOrderPageRespVO>> page(@Valid MaterialIoOrderPageReqVO reqVO) {
        if (reqVO.getTenantIds() == null || reqVO.getTenantIds().length == 0) {
            reqVO.setTenantIds(new Long[]{TenantContextHolder.getTenantId()});
        }
        return success(materialIoService.page(reqVO));
    }

    @GetMapping("/inbound-batch-list")
    @Operation(summary = "入库单(批次)查询列表（不分页，供出库选择）")
    @TenantIgnore
    public CommonResult<List<MaterialInBalanceRespVO>> inboundBatchList(@Valid MaterialInBalanceListReqVO reqVO) {
        if (reqVO.getTenantId() == null) {
            reqVO.setTenantId(TenantContextHolder.getTenantId());
        }
        return success(materialIoService.listInboundBatches(reqVO));
    }

    @GetMapping("/inbound-list")
    @Operation(summary = "入库单下拉列表")
    @TenantIgnore
    public CommonResult<List<MaterialInboundOrderDO>> inboundList(@Valid TenantIdsReqVO tenantIdsReqVO) {
        if (tenantIdsReqVO.getTenantIds() == null || tenantIdsReqVO.getTenantIds().length == 0) {
            tenantIdsReqVO.setTenantIds(new Long[]{TenantContextHolder.getTenantId()});
        }
        return success(materialIoService.inboundList(tenantIdsReqVO.getTenantIds()));
    }

    @GetMapping("/outbound-list")
    @Operation(summary = "出库单下拉列表")
    @TenantIgnore
    public CommonResult<List<MaterialOutboundOrderDO>> outboundList(@Valid TenantIdsReqVO tenantIdsReqVO) {
        if (tenantIdsReqVO.getTenantIds() == null || tenantIdsReqVO.getTenantIds().length == 0) {
            tenantIdsReqVO.setTenantIds(new Long[]{TenantContextHolder.getTenantId()});
        }
        return success(materialIoService.outboundList(tenantIdsReqVO.getTenantIds()));
    }

    @GetMapping("/inbound/get")
    @Operation(summary = "获得入库单详情")
    @Parameter(name = "id", description = "编号", required = true, example = "1")
    @TenantIgnore
    public CommonResult<MaterialInboundOrderRespVO> getInboundOrder(@RequestParam("id") Long id) {
        return success(materialIoService.getInboundOrder(id));
    }

    @GetMapping("/inbound/export")
    @Operation(summary = "导出入库单（单据明细）")
    @Parameter(name = "id", description = "编号", required = true, example = "1")
    @TenantIgnore
    public void exportInboundOrder(@RequestParam("id") Long id, HttpServletResponse response) throws IOException {
        MaterialInboundOrderRespVO order = materialIoService.getInboundOrder(id);

        List<MaterialInboundOrderExportExcelVO> excelList = new ArrayList<>();
        if (order.getItems() != null) {
            for (MaterialInboundOrderItemRespVO item : order.getItems()) {
                MaterialInboundOrderExportExcelVO row = new MaterialInboundOrderExportExcelVO();
                row.setOrderNo(order.getOrderNo());
                row.setOrderDate(order.getOrderDate());
                row.setSupplierName(item.getSupplierName());
                row.setRemark(order.getRemark());
                row.setRefInStoreName(item.getRefInStoreName());
                row.setCategoryName(item.getCategoryName());
                row.setMaterialNumber(item.getMaterialNumber());
                row.setMaterialName(item.getMaterialName());
                row.setMaterialUnit(item.getMaterialUnit());
                row.setProduceDate(item.getProduceDate());
                row.setInQty(item.getInQty());
                row.setInUnitPrice(item.getInUnitPrice());
                row.setAmount(item.getAmount());
                excelList.add(row);
            }
        }

        String fileName = (order.getOrderNo() != null ? order.getOrderNo() : "入库单") + ".xlsx";
        ExcelUtils.write(response, fileName, "数据", MaterialInboundOrderExportExcelVO.class, excelList);
    }

    @GetMapping("/outbound/get")
    @Operation(summary = "获得出库单详情")
    @Parameter(name = "id", description = "编号", required = true, example = "1")
    @TenantIgnore
    public CommonResult<MaterialOutboundOrderRespVO> getOutboundOrder(@RequestParam("id") Long id) {
        return success(materialIoService.getOutboundOrder(id));
    }

    @GetMapping("/outbound/export")
    @Operation(summary = "导出出库单（单据明细）")
    @Parameter(name = "id", description = "编号", required = true, example = "1")
    @TenantIgnore
    public void exportOutboundOrder(@RequestParam("id") Long id, HttpServletResponse response) throws IOException {
        MaterialOutboundOrderRespVO order = materialIoService.getOutboundOrder(id);

        List<MaterialOutboundOrderExportExcelVO> excelList = new ArrayList<>();
        if (order.getItems() != null) {
            for (cn.iocoder.yudao.module.system.controller.admin.biz.vo.materialio.outbound.MaterialOutboundOrderItemRespVO item : order.getItems()) {
                MaterialOutboundOrderExportExcelVO row = new MaterialOutboundOrderExportExcelVO();
                row.setOrderNo(order.getOrderNo());
                row.setOrderDate(order.getOrderDate());
                row.setOutDeptName(order.getOutDeptName());
                row.setOutUser(order.getOutUser());
                row.setOutReason(order.getOutReason());
                row.setRemark(order.getRemark());
                row.setRefInStoreName(item.getRefInStoreName());
                row.setRefInOrderNo(item.getRefInOrderNo());
                row.setMaterialNumber(item.getMaterialNumber());
                row.setMaterialName(item.getMaterialName());
                row.setMaterialUnit(item.getMaterialUnit());
                row.setProduceDate(item.getProduceDate());
                row.setQuantity(item.getQuantity());
                row.setInUnitPrice(item.getInUnitPrice());
                row.setSaleUnitPrice(item.getSaleUnitPrice());
                row.setAmount(item.getAmount());
                excelList.add(row);
            }
        }

        String fileName = (order.getOrderNo() != null ? order.getOrderNo() : "出库单") + ".xlsx";
        ExcelUtils.write(response, fileName, "数据", MaterialOutboundOrderExportExcelVO.class, excelList);
    }

    @DeleteMapping("/delete")
    @Operation(summary = "删除单据（级联删除明细；不冲销库存）")
    @Parameter(name = "id", description = "单据ID", required = true)
    @TenantIgnore
    public CommonResult<Boolean> delete(@RequestParam("id") Long id) {
        materialIoService.delete(id);
        return success(true);
    }

    @GetMapping("/outbound-return/get")
    @Operation(summary = "获得出库退回单详情")
    @Parameter(name = "id", description = "退回单ID", required = true)
    @TenantIgnore
    public CommonResult<MaterialOutboundReturnOrderRespVO> getOutboundReturn(@RequestParam("id") Long id) {
        // 实现获取出库退回单详情的逻辑
        return success(materialIoService.getOutboundReturn(id));
    }

    @GetMapping("/inbound-return/get")
    @Operation(summary = "获得入库退回单详情")
    @Parameter(name = "id", description = "退回单ID", required = true)
    @TenantIgnore
    public CommonResult<MaterialInboundReturnOrderRespVO> getInboundReturn(@RequestParam("id") Long id) {
        // 实现获取入库退回单详情的逻辑
        return success(materialIoService.getInboundReturn(id));
    }

    @GetMapping("/outbound-return/page")
    @Operation(summary = "出库退回单分页查询")
    @TenantIgnore
    public CommonResult<PageResult<MaterialOutboundReturnOrderPageRespVO>> pageOutboundReturn(@Valid MaterialOutboundReturnOrderPageReqVO reqVO) {
        if (reqVO.getTenantIds() == null || reqVO.getTenantIds().length == 0) {
            reqVO.setTenantIds(new Long[]{TenantContextHolder.getTenantId()});
        }
        return success(materialIoService.pageOutboundReturn(reqVO));
    }

    @GetMapping("/inbound-return/page")
    @Operation(summary = "入库退回单分页查询")
    @TenantIgnore
    public CommonResult<PageResult<MaterialInboundReturnOrderPageRespVO>> pageInboundReturn(@Valid MaterialInboundReturnOrderPageReqVO reqVO) {
        if (reqVO.getTenantIds() == null || reqVO.getTenantIds().length == 0) {
            reqVO.setTenantIds(new Long[]{TenantContextHolder.getTenantId()});
        }
        return success(materialIoService.pageInboundReturn(reqVO));
    }

    @GetMapping("/stats/inventory/page")
    @Operation(summary = "库存查询报表分页")
    @TenantIgnore
    public CommonResult<PageResult<MaterialInventoryReportRespVO>> pageInventoryReport(@Valid MaterialInventoryReportPageReqVO reqVO) {
        if (reqVO.getTenantIds() == null || reqVO.getTenantIds().length == 0) {
            reqVO.setTenantIds(new Long[]{TenantContextHolder.getTenantId()});
        }
        return success(materialIoService.pageInventoryReport(reqVO));
    }

    @GetMapping("/stats/inventory/export")
    @Operation(summary = "库存查询报表导出")
    @TenantIgnore
    public void exportInventoryReport(@Valid MaterialInventoryReportPageReqVO reqVO, HttpServletResponse response) throws IOException {
        if (reqVO.getTenantIds() == null || reqVO.getTenantIds().length == 0) {
            reqVO.setTenantIds(new Long[]{TenantContextHolder.getTenantId()});
        }

        List<MaterialInventoryReportRespVO> list = materialIoService.listInventoryReport(reqVO);
        List<MaterialInventoryReportExcelVO> excelList = BeanUtils.toBean(list, MaterialInventoryReportExcelVO.class);
        ExcelUtils.write(response, "库存查询报表.xlsx", "数据", MaterialInventoryReportExcelVO.class, excelList);
    }

    @PostMapping("/stats/inventory/flow")
    @Operation(summary = "库存流水查询")
    @TenantIgnore
    public CommonResult<MaterialInventoryFlowRespVO> getInventoryFlow(@Valid @RequestBody MaterialInventoryFlowReqVO reqVO) {
        return success(materialIoService.getInventoryFlow(reqVO));
    }

    @GetMapping("/inbound/import-template")
    @Operation(summary = "下载入库导入模板")
    @TenantIgnore
    public void inboundImportTemplate(HttpServletResponse response) throws IOException {
        materialIoService.exportInboundImportTemplate(response);
    }

    @GetMapping("/outbound/import-template")
    @Operation(summary = "下载出库导入模板")
    @TenantIgnore
    public void outboundImportTemplate(HttpServletResponse response) throws IOException {
        materialIoService.exportOutboundImportTemplate(response);
    }

    @PostMapping("/inbound/import")
    @Operation(summary = "导入入库数据")
    @TenantIgnore
    public CommonResult<ImportResultVO> importInbound(@RequestParam("file") MultipartFile file) throws IOException {
        return success(materialIoService.importInbound(file));
    }

    @PostMapping("/outbound/import")
    @Operation(summary = "导入出库数据")
    @TenantIgnore
    public CommonResult<ImportResultVO> importOutbound(@RequestParam("file") MultipartFile file) throws IOException {
        return success(materialIoService.importOutbound(file));
    }
}
