package cn.iocoder.foodnexus.module.erp.controller.admin.purchase;

import cn.hutool.core.collection.CollUtil;
import cn.iocoder.foodnexus.framework.apilog.core.annotation.ApiAccessLog;
import cn.iocoder.foodnexus.framework.common.enums.CheckTaskStatus;
import cn.iocoder.foodnexus.framework.common.enums.UserSystemEnum;
import cn.iocoder.foodnexus.framework.common.pojo.CommonResult;
import cn.iocoder.foodnexus.framework.common.pojo.PageParam;
import cn.iocoder.foodnexus.framework.common.pojo.PageResult;
import cn.iocoder.foodnexus.framework.common.util.CommonUtil;
import cn.iocoder.foodnexus.framework.common.util.collection.MapUtils;
import cn.iocoder.foodnexus.framework.common.util.number.MoneyUtils;
import cn.iocoder.foodnexus.framework.common.util.number.NumberUtils;
import cn.iocoder.foodnexus.framework.common.util.object.BeanUtils;
import cn.iocoder.foodnexus.framework.excel.core.util.ExcelUtils;
import cn.iocoder.foodnexus.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.foodnexus.module.erp.api.enums.ErpDeliveryStatus;
import cn.iocoder.foodnexus.module.erp.api.service.ErpCustomerApi;
import cn.iocoder.foodnexus.module.erp.api.service.ErpSupplierApi;
import cn.iocoder.foodnexus.module.erp.api.vo.warehouse.WarehouseInfo;
import cn.iocoder.foodnexus.module.erp.controller.admin.purchase.vo.order.ErpPurchaseOrderExportVO;
import cn.iocoder.foodnexus.module.erp.controller.admin.purchase.vo.order.ErpPurchaseOrderPageReqVO;
import cn.iocoder.foodnexus.module.erp.controller.admin.purchase.vo.order.ErpPurchaseOrderRespVO;
import cn.iocoder.foodnexus.module.erp.controller.admin.purchase.vo.supplier.SupplierPurchaseOrderDeliveryReqVO;
import cn.iocoder.foodnexus.module.erp.dal.dataobject.purchase.ErpPurchaseOrderDO;
import cn.iocoder.foodnexus.module.erp.dal.dataobject.purchase.ErpPurchaseOrderItemDO;
import cn.iocoder.foodnexus.module.erp.dal.dataobject.purchase.ErpSupplierDO;
import cn.iocoder.foodnexus.module.erp.service.purchase.ErpPurchaseOrderService;
import cn.iocoder.foodnexus.module.erp.service.purchase.ErpSupplierService;
import cn.iocoder.foodnexus.module.order.api.CheckTaskApi;
import cn.iocoder.foodnexus.module.order.api.CustomerOrderApi;
import cn.iocoder.foodnexus.module.order.dto.CustomerAddressInfo;
import cn.iocoder.foodnexus.module.order.dto.CustomerOrderDTO;
import cn.iocoder.foodnexus.module.order.dto.CustomerOrderItemDTO;
import cn.iocoder.foodnexus.module.order.enums.CustomerOrderStatus;
import cn.iocoder.foodnexus.module.product.api.dto.ProductInfo;
import cn.iocoder.foodnexus.module.product.dal.dataobject.spu.ProductSpuDO;
import cn.iocoder.foodnexus.module.product.service.category.ProductCategoryService;
import cn.iocoder.foodnexus.module.product.service.spu.ProductSpuService;
import cn.iocoder.foodnexus.module.system.annotations.AppSystemAuth;
import cn.iocoder.foodnexus.module.system.api.user.AdminUserApi;
import cn.iocoder.foodnexus.module.system.api.user.dto.AdminUserRespDTO;
import cn.iocoder.foodnexus.module.system.service.dept.DeptService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;

import static cn.iocoder.foodnexus.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
import static cn.iocoder.foodnexus.framework.common.pojo.CommonResult.success;
import static cn.iocoder.foodnexus.framework.common.util.collection.CollectionUtils.convertMultiMap;
import static cn.iocoder.foodnexus.framework.common.util.collection.CollectionUtils.convertSet;

@Tag(name = "管理后台 - ERP 采购订单")
@RestController
@Validated
public class ErpPurchaseOrderController {

    @Resource
    private ErpPurchaseOrderService purchaseOrderService;
    @Resource
    private ErpSupplierService supplierService;

    @Resource
    private AdminUserApi adminUserApi;

    @Autowired
    private CustomerOrderApi customerOrderApi;

    @Autowired
    private ErpCustomerApi customerApi;

    @Autowired
    private ErpSupplierApi supplierApi;

    @Autowired
    private DeptService deptService;

    @GetMapping("/erp/purchase-order/get")
    @Operation(summary = "获得采购订单")
    @Parameter(name = "id", description = "编号", required = true, example = "1024")
    @PreAuthorize("@ss.hasPermission('erp:purchase-order:query')")
    public CommonResult<ErpPurchaseOrderRespVO> getPurchaseOrder(@RequestParam("id") Long id) {
        ErpPurchaseOrderDO purchaseOrder = purchaseOrderService.getPurchaseOrder(id);
        if (purchaseOrder == null) {
            return success(null);
        }
        return success(buildPurchaseOrderVOPageResult(CommonUtil.asList(purchaseOrder), true).get(0));
    }

    @GetMapping("/erp/purchase-order/page")
    @Operation(summary = "获得采购订单分页")
    @PreAuthorize("@ss.hasPermission('erp:purchase-order:query')")
    public CommonResult<PageResult<ErpPurchaseOrderRespVO>> getPurchaseOrderPage(@Valid ErpPurchaseOrderPageReqVO pageReqVO) {
        PageResult<ErpPurchaseOrderDO> pageResult = purchaseOrderService.getPurchaseOrderPage(pageReqVO);
        return success(new PageResult<>(buildPurchaseOrderVOPageResult(pageResult.getList(), false), pageResult.getTotal()));
    }

    @PostMapping("/erp/purchase-order/arrival")
    @Operation(summary = "到货")
    @Parameter(name = "ids", description = "编号", required = true)
    public CommonResult<Boolean> arrival(@RequestParam("ids") List<Long> ids) {
        purchaseOrderService.delivery(SupplierPurchaseOrderDeliveryReqVO.transform(ids), null,
                ErpDeliveryStatus.ALREADY, ErpDeliveryStatus.ARRIVAL, CustomerOrderStatus.SUPPLIER_ARRIVE);
        return success(Boolean.TRUE);
    }

    @GetMapping("/erp/purchase-order/export-excel")
    @Operation(summary = "导出采购订单 Excel")
    @PreAuthorize("@ss.hasPermission('erp:purchase-order:export')")
    @ApiAccessLog(operateType = EXPORT)
    public void exportPurchaseOrderExcel(@Valid ErpPurchaseOrderPageReqVO pageReqVO,
                                    HttpServletResponse response) throws IOException {
        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
        List<ErpPurchaseOrderRespVO> list = buildPurchaseOrderVOPageResult(purchaseOrderService.getPurchaseOrderPage(pageReqVO).getList(), false);
        // 导出 Excel
        ExcelUtils.write(response, "采购订单.xls", "数据", ErpPurchaseOrderExportVO.class,
                BeanUtils.toBean(list, ErpPurchaseOrderExportVO.class, item -> {
                    item.setTotalPriceYuan(item.getTotalPrice().divide(BigDecimal.valueOf(100)));
                    item.setDepositPriceYuan(MoneyUtils.fenToYuan(item.getDepositPrice()));
                    item.setDeliveryStatusStr(ErpDeliveryStatus.getNameByStatus(item.getDeliveryStatus()));
                    item.setCheckTaskStatusStr(CheckTaskStatus.getNameByStatus(item.getCheckTaskStatus()));

                    if (CommonUtil.isNotEmpty(item.getAddressInfo())) {
                        CustomerAddressInfo addressInfo = item.getAddressInfo();
                        item.setAddressInfoStr(String.format("%s %s %s %s",
                                addressInfo.getProvinceName(),
                                addressInfo.getCityName(),
                                addressInfo.getRegionName(),
                                addressInfo.getAddress()));
                    }

                    if (CommonUtil.isNotEmpty(item.getWarehouseInfo())) {
                        WarehouseInfo warehouseInfo = item.getWarehouseInfo();
                        item.setWarehouseStr(String.format("%s %s %s %s",
                                warehouseInfo.getAddress(),
                                warehouseInfo.getName(),
                                warehouseInfo.getPrincipal(),
                                warehouseInfo.getTelephone()));
                    }

                    item.setDeliveryModeStr(item.getDeliveryMode().getLabel());
                }));
    }


    /* ----- 供应商接口 ----- */
    @GetMapping("/supplier/purchase-order/get")
    @Operation(summary = "供应商 - 获得采购订单")
    @Parameter(name = "id", description = "编号", required = true, example = "1024")
    @AppSystemAuth(UserSystemEnum.SUPPLIER)
    public CommonResult<ErpPurchaseOrderRespVO> supplierGetPurchaseOrder(@RequestParam("id") Long id) {
        ErpPurchaseOrderDO purchaseOrder = purchaseOrderService.getPurchaseOrder(id);
        if (purchaseOrder == null) {
            return success(null);
        }
        return success(buildPurchaseOrderVOPageResult(CommonUtil.asList(purchaseOrder), true).get(0));
    }

    @GetMapping("/supplier/purchase-order/page")
    @Operation(summary = "供应商 - 获得采购订单分页")
    @AppSystemAuth(UserSystemEnum.SUPPLIER)
    public CommonResult<PageResult<ErpPurchaseOrderRespVO>> supplierGetPurchaseOrderPage(@Valid ErpPurchaseOrderPageReqVO pageReqVO) {
        pageReqVO.setSupplierId(supplierApi.querySupplierIdByUserId(SecurityFrameworkUtils.getLoginUserId()));
        PageResult<ErpPurchaseOrderDO> pageResult = purchaseOrderService.getPurchaseOrderPage(pageReqVO);
        return success(new PageResult<>(buildPurchaseOrderVOPageResult(pageResult.getList(), false), pageResult.getTotal()));
    }

    @GetMapping("/supplier/purchase-ordercount")
    @Operation(summary = "供应商 - 根据配送状态统计数量")
    @AppSystemAuth(UserSystemEnum.SUPPLIER)
    public CommonResult<Map<String, Long>> supplierQueryCount(@Valid ErpPurchaseOrderPageReqVO pageReqVO) {
        pageReqVO.setSupplierId(supplierApi.querySupplierIdByUserId(SecurityFrameworkUtils.getLoginUserId()));
        return success(purchaseOrderService.queryCountByDeliveryStatus(pageReqVO));
    }

    @PostMapping("/supplier/purchase-order/accepting-orders")
    @Operation(summary = "供应商 - 接单")
    @Parameter(name = "ids", description = "编号", required = true)
    @AppSystemAuth(UserSystemEnum.SUPPLIER)
    public CommonResult<Boolean> supplierAcceptingOrders(@RequestParam("ids") List<Long> ids) {
        purchaseOrderService.delivery(SupplierPurchaseOrderDeliveryReqVO.transform(ids), supplierApi.querySupplierIdByUserId(SecurityFrameworkUtils.getLoginUserId()),
                ErpDeliveryStatus.MATCHED, ErpDeliveryStatus.NOT_YET, CustomerOrderStatus.SUPPLIER_ACCEPT_ORDER);
        return success(Boolean.TRUE);
    }

    @PostMapping("/supplier/purchase-order/delivery")
    @Operation(summary = "供应商 - 发货")
    @Parameter(name = "ids", description = "编号", required = true)
    @AppSystemAuth(UserSystemEnum.SUPPLIER)
    public CommonResult<Boolean> supplierPurchaseOrderDelivery(@RequestBody @Valid SupplierPurchaseOrderDeliveryReqVO.Item reqVO) {
        SupplierPurchaseOrderDeliveryReqVO delivery = new SupplierPurchaseOrderDeliveryReqVO();
        delivery.setIds(CommonUtil.asList(reqVO));
        purchaseOrderService.delivery(delivery, supplierApi.querySupplierIdByUserId(SecurityFrameworkUtils.getLoginUserId()),
                ErpDeliveryStatus.NOT_YET, ErpDeliveryStatus.ALREADY, CustomerOrderStatus.SUPPLIER_SHIP);
        return success(Boolean.TRUE);
    }


    private List<ErpPurchaseOrderRespVO> buildPurchaseOrderVOPageResult(List<ErpPurchaseOrderDO> list, boolean isDetails) {
        if (CollUtil.isEmpty(list)) {
            return new ArrayList<>();
        }
        // 1.1 订单项
        List<ErpPurchaseOrderItemDO> purchaseOrderItemList = purchaseOrderService.getPurchaseOrderItemListByOrderIds(
                convertSet(list, ErpPurchaseOrderDO::getId));
        Map<Long, List<ErpPurchaseOrderItemDO>> purchaseOrderItemMap = convertMultiMap(purchaseOrderItemList, ErpPurchaseOrderItemDO::getOrderId);
        // 1.2 产品信息
        // Set<Long> productIds = convertSet(purchaseOrderItemList, ErpPurchaseOrderItemDO::getProductId);
        // Map<Long, ProductSpuDO> productMap = productService.getProductVOMap(productIds);
        // Map<Long, String> categoryMap = productCategoryService.getMap(CommonUtil.listConvertSet(productMap.values(), ProductSpuDO::getCategoryId));
        // 1.3 供应商信息
        Map<Long, ErpSupplierDO> supplierMap = supplierService.getSupplierMap(
                convertSet(list, ErpPurchaseOrderDO::getSupplierId));
        // 1.4 管理员信息
        Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(
                convertSet(list, purchaseOrder -> Long.parseLong(purchaseOrder.getCreator())));
        Map<Long, CustomerOrderDTO> customerOrderMap = customerOrderApi.getOrderMap(
                convertSet(list, ErpPurchaseOrderDO::getCustomerOrderId));
        Map<Long, String> deptNameMap = deptService.queryNameMapByIds(CommonUtil.listConvertSet(new ArrayList<>(customerOrderMap.values()), CustomerOrderDTO::getCustomerDeptId), Boolean.TRUE);
        Map<Long, CustomerOrderItemDTO> customerOrderItemMap;
        /*Map<Long, String> checkResultMap;*/
        List<CustomerOrderItemDTO> customerOrderItems = customerOrderApi.queryItemsByIds(CommonUtil.listConvert(purchaseOrderItemList, ErpPurchaseOrderItemDO::getCustomerOrderItemId));
        customerOrderItemMap = CommonUtil.listConvertMap(customerOrderItems, CustomerOrderItemDTO::getId);
        if (isDetails) {
            /*checkResultMap = checkTaskApi.getCheckResultMapByPurchaseOrderItemIds(CommonUtil.listConvertSet(purchaseOrderItemList,
                    ErpPurchaseOrderItemDO::getId));*/
            // TODO 退款待定
        } else {
            /*checkResultMap = new HashMap<>();*/
        }
        // 2. 开始拼接
        return BeanUtils.toBean(list, ErpPurchaseOrderRespVO.class, purchaseOrder -> {
            purchaseOrder.setItems(BeanUtils.toBean(purchaseOrderItemMap.get(purchaseOrder.getId()), ErpPurchaseOrderRespVO.Item.class,
                    item -> {
                MapUtils.findAndThen(customerOrderItemMap, item.getCustomerOrderItemId(), customerOrderItem -> {
                    item.setSignedQuantity(customerOrderItem.getSignedQuantity());
                    item.setSignedTotal(customerOrderItem.getSignedTotal());
                    item.setProductInfo(customerOrderItem.getProductInfo());
                    item.setReturnsCount(customerOrderItem.getReturnsQuantity());
                    item.setReturnsTotal(customerOrderItem.getReturnsTotal());
                });
                if (isDetails) {
                    /*MapUtils.findAndThen(checkResultMap, item.getId(), item::setCheckResult);*/
                }}));
            purchaseOrder.setProductNames(CollUtil.join(purchaseOrder.getItems(), "，", item ->
                    Optional.ofNullable(item.getProductInfo()).map(ProductInfo::getName).orElse("")));
            purchaseOrder.setActualAmount(NumberUtils.addInt(purchaseOrder.getItems(), i -> i.getSignedTotal() - i.getReturnsTotal()));
            purchaseOrder.setSignedTotal(NumberUtils.addInt(purchaseOrder.getItems(), ErpPurchaseOrderRespVO.Item::getSignedTotal));
            MapUtils.findAndThen(supplierMap, purchaseOrder.getSupplierId(), supplier -> purchaseOrder.setSupplierName(supplier.getName()));
            MapUtils.findAndThen(userMap, Long.parseLong(purchaseOrder.getCreator()), user -> purchaseOrder.setCreatorName(user.getNickname()));
            MapUtils.findAndThen(customerOrderMap, purchaseOrder.getCustomerOrderId(), customerOrder -> {
                purchaseOrder.setAddressInfo(customerOrder.getAddressInfo());
                purchaseOrder.setWarehouseInfo(customerOrder.getWarehouseInfo());
                purchaseOrder.setPlanDeliveryStartTime(customerOrder.getPlanDeliveryStartTime());
                purchaseOrder.setPlanDeliveryEndTime(customerOrder.getPlanDeliveryEndTime());
                purchaseOrder.setCustomerOrderCode(customerOrder.getCode());
                purchaseOrder.setCustomerId(customerOrder.getCustomerId());
                purchaseOrder.setCustomerName(customerApi.queryNameStrById(customerOrder.getCustomerId()));
                purchaseOrder.setCustomerDeptId(customerOrder.getCustomerDeptId());
                purchaseOrder.setDeliveryMode(customerOrder.getDeliveryMode());
            });
            MapUtils.findAndThen(deptNameMap, purchaseOrder.getCustomerDeptId(), purchaseOrder::setCustomerDeptName);
        });
    }

}