package com.ruoyi.web.sales.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.web.service.TokenService;
import com.ruoyi.web.base.domain.BaseEmployee;
import com.ruoyi.web.base.domain.BaseLine;
import com.ruoyi.web.base.domain.BaseMaterial;
import com.ruoyi.web.base.domain.BaseMarket;
import com.ruoyi.web.base.service.IBaseEmployeeService;
import com.ruoyi.web.base.service.IBaseLineService;
import com.ruoyi.web.base.service.IBaseMaterialService;
import com.ruoyi.web.base.service.IBaseMarketService;
import com.ruoyi.web.sales.domain.*;
import com.ruoyi.web.sales.service.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import static com.ruoyi.common.core.domain.AjaxResult.success;
import static com.ruoyi.common.utils.SecurityUtils.getUsername;

@RestController
@Api(tags = "销售订单")
@RequestMapping("/sales-order")
public class SalesOrderController {

    @Autowired
    private ISalesOrderService salesOrderService;
    @Autowired
    private ISalesOrderGoodsService salesOrderGoodsService;
    @Autowired
    private IBaseCustomerService customerService;
    @Autowired
    private IRelCustomerMarketService relCustomerMarketService;
    @Autowired
    private IBaseMaterialService baseMaterialService;
    @Autowired
    private IBaseEmployeeService baseEmployeeService;
    @Autowired
    private IBaseLineService baseLineService;
    @Autowired
    private IBaseMarketService baseMarketService;
    @Autowired
    private ISalesPriceService salesPriceService;
    @Autowired
    private ISalesPriceItemService salesPriceItemService;
    @Autowired
    private TokenService tokenService;

    @ApiOperation("销售订单新增")
    @PostMapping("/add")
    @Transactional
    public AjaxResult add(@RequestBody SalesOrder order, HttpServletRequest request) throws Exception {
        String orgId = tokenService.getLoginOrgId(request);
        validateBeforeSave(order, orgId, true);
        fillCustomerAndMarketInfo(order, orgId);
        recalcGoodsSubTotalsAndOrderTotal(order);
        order.setOrgId(orgId);
        order.setDelFlag("0");
        order.setAuditStatus(1);
        String username = getUsername();
        order.setId(null);
        order.setCreateBy(username);
        order.setCreateTime(new Date());
        order.setUpdateBy(null);
        order.setUpdateTime(null);
        salesOrderService.save(order);
        saveGoods(order, orgId, username);
        return success();
    }

    @ApiOperation("销售订单修改")
    @PostMapping("/edit")
    @Transactional
    public AjaxResult edit(@RequestBody SalesOrder order, HttpServletRequest request) throws Exception {
        if (order.getId() == null) {
            throw new Exception("id不能为空");
        }
        SalesOrder old = salesOrderService.getById(order.getId());
        if (old == null || !"0".equals(old.getDelFlag())) {
            throw new Exception("销售订单不存在");
        }
        if (old.getAuditStatus() != null && old.getAuditStatus() == 1) {
            throw new Exception("已审核的销售订单不能修改，请先反审核");
        }
        String orgId = tokenService.getLoginOrgId(request);
        validateBeforeSave(order, orgId, false);
        fillCustomerAndMarketInfo(order, orgId);
        recalcGoodsSubTotalsAndOrderTotal(order);
        order.setOrgId(orgId);
        order.setAuditStatus(1);
        String username = getUsername();
        order.setCreateBy(old.getCreateBy());
        order.setCreateTime(old.getCreateTime());
        order.setUpdateBy(username);
        order.setUpdateTime(new Date());
        salesOrderService.updateById(order);
        /** 修改保存：先按原单据编号物理删除旧物料清单，再插入本次提交的明细 */
        String oldOrderNum = StringUtils.isNotBlank(old.getOrderNum()) ? old.getOrderNum().trim() : null;
        deleteSalesOrderGoodsByOrderNum(orgId, oldOrderNum);
        saveGoods(order, orgId, username);
        return success();
    }

    @ApiOperation("销售订单删除")
    @PostMapping("/delete")
    public AjaxResult delete(@RequestBody Map<String, String> params) throws Exception {
        String ids = params.get("ids");
        for (String id : ids.split(",")) {
            SalesOrder order = salesOrderService.getById(id);
            if (order == null || !"0".equals(order.getDelFlag())) {
                continue;
            }
            if (order.getAuditStatus() != null && order.getAuditStatus() == 1) {
                throw new Exception("已审核的销售订单不能删除，请先反审核");
            }
            // 同步删除子表明细
            String orgId = order.getOrgId();
            String orderNum = order.getOrderNum();
            deleteSalesOrderGoodsByOrderNum(orgId, orderNum);

            SalesOrder up = new SalesOrder();
            up.setId(Integer.valueOf(id));
            up.setDelFlag("2");
            up.setUpdateBy(getUsername());
            up.setUpdateTime(new Date());
            salesOrderService.updateById(up);
        }
        return success();
    }

    @ApiOperation("销售订单详情")
    @PostMapping("/listById")
    public AjaxResult listById(@ApiParam("详情参数: id") @RequestBody Map<String, String> params, HttpServletRequest request) {
        String id = params.get("id");
        SalesOrder order = salesOrderService.getById(id);
        if (order == null) {
            return success(null);
        }
        String orgId = tokenService.getLoginOrgId(request);
        List<SalesOrderGoods> goods = salesOrderGoodsService.list(new QueryWrapper<SalesOrderGoods>()
                .eq("org_id", orgId)
                .eq("order_num", order.getOrderNum())
                .eq("del_flag", "0"));
        enrichGoodsFromMaterial(goods, orgId);
        order.setGoods(goods);
        enrichSalesOrderDisplay(order, orgId);
        return success(order);
    }

    @ApiOperation("销售订单分页")
    @GetMapping("/page")
    public AjaxResult page(@RequestParam("pageNum") Integer pageNum,
                           @RequestParam("pageSize") Integer pageSize,
                           SalesOrder query,
                           HttpServletRequest request) {
        String orgId = tokenService.getLoginOrgId(request);
        QueryWrapper<SalesOrder> wrapper = buildWrapper(query, orgId);
        Page<SalesOrder> page = salesOrderService.page(new Page<SalesOrder>(pageNum, pageSize), wrapper);
        for (SalesOrder row : page.getRecords()) {
            enrichSalesOrderDisplay(row, orgId);
        }
        return success(page);
    }

    @ApiOperation("销售订单列表")
    @PostMapping("/list")
    public AjaxResult list(@RequestBody SalesOrder query, HttpServletRequest request) {
        String orgId = tokenService.getLoginOrgId(request);
        List<SalesOrder> list = salesOrderService.list(buildWrapper(query, orgId));
        for (SalesOrder row : list) {
            enrichSalesOrderDisplay(row, orgId);
        }
        return success(list);
    }

    @ApiOperation("销售订单导出")
    @PostMapping("/export")
    public void export(HttpServletResponse response, SalesOrder query, HttpServletRequest request) {
        String orgId = tokenService.getLoginOrgId(request);
        List<SalesOrder> list = salesOrderService.list(buildWrapper(query, orgId));
        for (SalesOrder row : list) {
            enrichSalesOrderDisplay(row, orgId);
        }
        ExcelUtil<SalesOrder> util = new ExcelUtil<SalesOrder>(SalesOrder.class);
        util.exportExcel(response, list, "销售订单");
    }

    @ApiOperation("销售订单审核")
    @PostMapping("/audit")
    public AjaxResult audit(@RequestBody Map<String, String> params) throws Exception {
        String id = params.get("id");
        SalesOrder order = getActiveById(id);
        order.setAuditStatus(1);
        order.setUpdateBy(getUsername());
        order.setUpdateTime(new Date());
        return success(salesOrderService.updateById(order));
    }

    @ApiOperation("销售订单反审核")
    @PostMapping("/unaudit")
    public AjaxResult unaudit(@RequestBody Map<String, String> params) throws Exception {
        String id = params.get("id");
        SalesOrder order = getActiveById(id);
        order.setAuditStatus(0);
        order.setUpdateBy(getUsername());
        order.setUpdateTime(new Date());
        return success(salesOrderService.updateById(order));
    }

    @ApiOperation("销售订单打印数据")
    @PostMapping("/print")
    public AjaxResult print(@RequestBody Map<String, String> params, HttpServletRequest request) throws Exception {
        String id = params.get("id");
        SalesOrder order = getActiveById(id);
        String orgId = tokenService.getLoginOrgId(request);
        List<SalesOrderGoods> goods = salesOrderGoodsService.list(new QueryWrapper<SalesOrderGoods>()
                .eq("org_id", orgId)
                .eq("order_num", order.getOrderNum())
                .eq("del_flag", "0"));
        enrichGoodsFromMaterial(goods, orgId);
        order.setGoods(goods);
        enrichSalesOrderDisplay(order, orgId);
        return success(order);
    }

    @ApiOperation("获取新增销售订单页面数据")
    @PostMapping("/getAddPageData")
    public AjaxResult getAddPageData(HttpServletRequest request) throws Exception {
        String orgId = tokenService.getLoginOrgId(request);
        String tomorrow = LocalDate.now().plusDays(1).format(DateTimeFormatter.ISO_LOCAL_DATE);
        Map<String, Object> data = new HashMap<String, Object>();
        data.put("documentDate", tomorrow);
        data.put("saleDate", tomorrow);
        data.put("orderNum", generateSalesOrderNum(orgId));
        return success(data);
    }

    @ApiOperation("按货品编号、客户编号、单据日期查询物料及价格")
    @PostMapping("/getGoodsPriceInfo")
    public AjaxResult getGoodsPriceInfo(@RequestBody Map<String, String> params, HttpServletRequest request) throws Exception {
        String goodsNum = params.get("goodsNum");
        String customerNum = params.get("customerNum");
        String documentDate = params.get("documentDate");
        if (StringUtils.isAnyBlank(goodsNum, customerNum, documentDate)) {
            throw new Exception("货品编号、客户编号、单据日期不能为空");
        }
        String orgId = tokenService.getLoginOrgId(request);
        String safeDate = documentDate.trim().replace("'", "''");

        BaseMaterial material = baseMaterialService.getOne(new QueryWrapper<BaseMaterial>()
                .eq("org_id", orgId)
                .eq("goods_num", goodsNum.trim())
                .eq("del_flag", "0")
                .last("limit 1"));
        if (material == null) {
            throw new Exception("未找到该货品编号对应物料");
        }

        RelCustomerMarket rel = relCustomerMarketService.getOne(new QueryWrapper<RelCustomerMarket>()
                .eq("org_id", orgId)
                .eq("customer_num", customerNum.trim())
                .eq("del_flag", "0")
                .orderByDesc("id")
                .last("limit 1"));
        if (rel == null || StringUtils.isBlank(rel.getMarketNum())) {
            throw new Exception("该客户未维护市场信息");
        }

        BaseMarket market = baseMarketService.getOne(new QueryWrapper<BaseMarket>()
                .eq("org_id", orgId)
                .eq("market_num", rel.getMarketNum())
                .eq("del_flag", "0")
                .last("limit 1"));
        if (market == null || StringUtils.isBlank(market.getPriceType())) {
            throw new Exception("该市场未维护价格类型");
        }

        String priceType = market.getPriceType().trim();
        SalesPrice price = salesPriceService.getOne(new QueryWrapper<SalesPrice>()
                .eq("org_id", orgId)
                .eq("del_flag", "0")
                .eq("price_type", priceType)
                .eq("effective_date", safeDate)
                .orderByDesc("id")
                .last("limit 1"), false);
        SalesPriceItem priceItem = null;
        if (price != null && StringUtils.isNotBlank(price.getPriceNum())) {
            priceItem = salesPriceItemService.getOne(new QueryWrapper<SalesPriceItem>()
                    .eq("org_id", orgId)
                    .eq("price_num", price.getPriceNum())
                    .eq("material_num", goodsNum.trim())
                    .eq("del_flag", "0")
                    .orderByDesc("id")
                    .last("limit 1"), false);
        }

        Map<String, Object> data = new HashMap<String, Object>();
        data.put("goodsNum", material.getGoodsNum());
        data.put("goodsName", material.getGoodsName());
        data.put("goodsSpec", material.getGoodsSpec());
        data.put("baseUnit", material.getUnit());
        data.put("assUnit", material.getAssistantUnit());
        data.put("customerNum", customerNum.trim());
        data.put("marketNum", rel.getMarketNum());
        data.put("priceType", priceType);
        data.put("documentDate", safeDate);
        data.put("priceNum", priceItem == null ? null : priceItem.getPriceNum());
        data.put("unitPrice", priceItem == null || priceItem.getUnitPrice() == null ? BigDecimal.ZERO : priceItem.getUnitPrice());
        data.put("pickupPrice", priceItem == null ? null : priceItem.getPickupPrice());
        return success(data);
    }

    @ApiOperation("物流线-市场-客户三级树（el-tree）")
    @GetMapping("/lineMarketCustomer")
    public AjaxResult lineMarketCustomerTree(HttpServletRequest request) {
        String orgId = tokenService.getLoginOrgId(request);
        QueryWrapper<BaseLine> lineQw = new QueryWrapper<BaseLine>()
                .eq("org_id", orgId)
                .and(w -> w.eq("del_flag", "0").or().isNull("del_flag"))
                .orderByAsc("line_num")
                .orderByAsc("id");
        List<BaseLine> lines = baseLineService.list(lineQw);

        QueryWrapper<BaseMarket> marketQw = new QueryWrapper<BaseMarket>()
                .eq("org_id", orgId)
                .and(w -> w.eq("del_flag", "0").or().isNull("del_flag"))
                .orderByAsc("market_num")
                .orderByAsc("id");
        List<BaseMarket> allMarkets = baseMarketService.list(marketQw);
        Map<String, List<BaseMarket>> marketsByLineNum = allMarkets.stream()
                .filter(m -> StringUtils.isNotBlank(m.getLineNum()))
                .collect(Collectors.groupingBy(m -> m.getLineNum().trim(), LinkedHashMap::new, Collectors.toList()));

        QueryWrapper<RelCustomerMarket> relQw = new QueryWrapper<RelCustomerMarket>()
                .eq("org_id", orgId)
                .and(w -> w.eq("del_flag", "0").or().isNull("del_flag"))
                .orderByDesc("id");
        List<RelCustomerMarket> allRels = relCustomerMarketService.list(relQw);

        List<BaseCustomer> customers = customerService.list(new QueryWrapper<BaseCustomer>()
                .eq("org_id", orgId)
                .and(w -> w.eq("del_flag", "0").or().isNull("del_flag")));
        Map<String, String> customerNameMap = customers.stream()
                .filter(c -> StringUtils.isNotBlank(c.getCustomerNum()))
                .collect(Collectors.toMap(BaseCustomer::getCustomerNum,
                        c -> c.getCustomerName() != null ? c.getCustomerName() : "",
                        (a, b) -> a, LinkedHashMap::new));

        Map<String, List<RelCustomerMarket>> relsByLineAndMarket = new LinkedHashMap<String, List<RelCustomerMarket>>();
        for (RelCustomerMarket r : allRels) {
            if (StringUtils.isBlank(r.getLineNum()) || StringUtils.isBlank(r.getMarketNum())) {
                continue;
            }
            String key = r.getLineNum().trim() + "\0" + r.getMarketNum().trim();
            relsByLineAndMarket.computeIfAbsent(key, k -> new ArrayList<RelCustomerMarket>()).add(r);
        }

        List<Map<String, Object>> tree = new ArrayList<Map<String, Object>>();
        for (BaseLine line : lines) {
            String lineNum = line.getLineNum() == null ? "" : line.getLineNum().trim();
            Map<String, Object> lineNode = new LinkedHashMap<String, Object>();
            lineNode.put("id", "line:" + lineNum + ":" + line.getId());
            lineNode.put("label", StringUtils.isNotBlank(line.getLineName()) ? line.getLineName() : lineNum);
            lineNode.put("type", "line");
            lineNode.put("lineNum", lineNum);
            lineNode.put("lineName", line.getLineName());

            List<Map<String, Object>> marketChildren = new ArrayList<Map<String, Object>>();
            List<BaseMarket> markets = marketsByLineNum.getOrDefault(lineNum, new ArrayList<BaseMarket>());
            for (BaseMarket market : markets) {
                String marketNum = market.getMarketNum() == null ? "" : market.getMarketNum().trim();
                Map<String, Object> marketNode = new LinkedHashMap<String, Object>();
                marketNode.put("id", "market:" + lineNum + ":" + marketNum + ":" + market.getId());
                marketNode.put("label", StringUtils.isNotBlank(market.getMarketName()) ? market.getMarketName() : marketNum);
                marketNode.put("type", "market");
                marketNode.put("lineNum", lineNum);
                marketNode.put("marketNum", marketNum);
                marketNode.put("marketName", market.getMarketName());

                String relKey = lineNum + "\0" + marketNum;
                List<RelCustomerMarket> rels = relsByLineAndMarket.getOrDefault(relKey, new ArrayList<RelCustomerMarket>());
                Set<String> seenCustomer = new LinkedHashSet<String>();
                List<Map<String, Object>> customerChildren = new ArrayList<Map<String, Object>>();
                for (RelCustomerMarket rel : rels) {
                    String customerNum = rel.getCustomerNum() == null ? "" : rel.getCustomerNum().trim();
                    if (StringUtils.isBlank(customerNum) || !seenCustomer.add(customerNum)) {
                        continue;
                    }
                    String customerName = StringUtils.isNotBlank(rel.getCustomerName())
                            ? rel.getCustomerName()
                            : customerNameMap.getOrDefault(customerNum, customerNum);
                    Map<String, Object> custNode = new LinkedHashMap<String, Object>();
                    custNode.put("id", "customer:" + lineNum + ":" + marketNum + ":" + customerNum + ":" + rel.getId());
                    custNode.put("label", customerName);
                    custNode.put("type", "customer");
                    custNode.put("lineNum", lineNum);
                    custNode.put("marketNum", marketNum);
                    custNode.put("customerNum", customerNum);
                    custNode.put("customerName", customerName);
                    custNode.put("relId", rel.getId());
                    custNode.put("leaf", true);
                    customerChildren.add(custNode);
                }
                marketNode.put("children", customerChildren);
                marketChildren.add(marketNode);
            }
            lineNode.put("children", marketChildren);
            tree.add(lineNode);
        }
        return success(tree);
    }

    private QueryWrapper<SalesOrder> buildWrapper(SalesOrder query, String orgId) {
        QueryWrapper<SalesOrder> wrapper = new QueryWrapper<SalesOrder>()
                .eq("org_id", orgId)
                .eq("del_flag", "0");
        if (query == null) {
            return wrapper;
        }
        if (query.getDocumentDateStart() != null) {
            wrapper.ge("document_date", query.getDocumentDateStart());
        }
        if (query.getDocumentDateEnd() != null) {
            wrapper.le("document_date", query.getDocumentDateEnd());
        }
        if (query.getSaleDateStart() != null) {
            wrapper.ge("sale_date", query.getSaleDateStart());
        }
        if (query.getSaleDateEnd() != null) {
            wrapper.le("sale_date", query.getSaleDateEnd());
        }
        if (StringUtils.isNotBlank(query.getCustomerName())) {
            wrapper.like("customer_name", query.getCustomerName());
        }
        if (StringUtils.isNotBlank(query.getEmployeeNum())) {
            wrapper.like("employee_num", query.getEmployeeNum());
        }
        if (StringUtils.isNotBlank(query.getLineNum())) {
            wrapper.like("line_num", query.getLineNum());
        }
        if (StringUtils.isNotBlank(query.getMarketNum())) {
            wrapper.like("market_num", query.getMarketNum());
        }
        if (query.getAuditStatus() != null) {
            wrapper.eq("audit_status", query.getAuditStatus());
        }
        wrapper.orderByDesc("id");
        return wrapper;
    }

    private void validateBeforeSave(SalesOrder order, String orgId, boolean isAdd) throws Exception {
        if (order == null) {
            throw new Exception("参数不能为空");
        }
        if (order.getCustomerNum() != null) {
            order.setCustomerNum(order.getCustomerNum().trim());
        }
        if (order.getOrderNum() != null) {
            order.setOrderNum(order.getOrderNum().trim());
        }
        if (StringUtils.isAnyBlank(order.getOrderNum(), order.getCustomerNum())) {
            throw new Exception("单据编号、客户编号不能为空");
        }
        QueryWrapper<SalesOrder> numWrapper = new QueryWrapper<SalesOrder>()
                .eq("order_num", order.getOrderNum())
                .eq("del_flag", "0");
        if (!isAdd && order.getId() != null) {
            numWrapper.ne("id", order.getId());
        }
        if (salesOrderService.count(numWrapper) > 0) {
            throw new Exception("该单据编号已存在");
        }
        if (order.getGoods() == null || order.getGoods().isEmpty()) {
            throw new Exception("货品清单不能为空");
        }
        BaseCustomer customer = customerService.getOne(new QueryWrapper<BaseCustomer>()
                .eq("org_id", orgId)
                .eq("customer_num", order.getCustomerNum())
                .eq("del_flag", "0")
                .last("limit 1"));
        if (customer == null) {
            throw new Exception("客户编号不存在");
        }
        if (StringUtils.isNotBlank(order.getEmployeeNum())) {
            BaseEmployee emp = baseEmployeeService.getOne(new QueryWrapper<BaseEmployee>()
                    .eq("org_id", orgId)
                    .eq("employee_num", order.getEmployeeNum().trim())
                    .eq("del_flag", "0")
                    .last("limit 1"));
            if (emp == null) {
                throw new Exception("业务员编号不存在");
            }
        }
    }

    private void fillCustomerAndMarketInfo(SalesOrder order, String orgId) throws Exception {
        BaseCustomer customer = customerService.getOne(new QueryWrapper<BaseCustomer>()
                .eq("org_id", orgId)
                .eq("customer_num", order.getCustomerNum())
                .eq("del_flag", "0")
                .last("limit 1"));
        if (customer == null) {
            throw new Exception("客户编号不存在");
        }
        order.setCustomerName(customer.getCustomerName());

        /** 仅按客户编号解析市场、物流线（取客户市场维护表中最新一条），不依赖前端传入 */
        RelCustomerMarket rel = relCustomerMarketService.getOne(new QueryWrapper<RelCustomerMarket>()
                .eq("org_id", orgId)
                .eq("customer_num", order.getCustomerNum())
                .eq("del_flag", "0")
                .orderByDesc("id")
                .last("limit 1"));
        if (rel != null) {
            order.setMarketNum(rel.getMarketNum());
            order.setLineNum(rel.getLineNum());
        } else {
            order.setMarketNum(null);
            order.setLineNum(null);
        }
    }

    private void enrichSalesOrderDisplay(SalesOrder order, String orgId) {
        if (order == null) {
            return;
        }
        order.setReceivableCustomer(null);
        order.setEmployeeName(null);
        if (StringUtils.isNotBlank(order.getCustomerNum())) {
            BaseCustomer c = customerService.getOne(new QueryWrapper<BaseCustomer>()
                    .eq("org_id", orgId)
                    .eq("customer_num", order.getCustomerNum())
                    .eq("del_flag", "0")
                    .last("limit 1"));
            if (c != null) {
                order.setReceivableCustomer(c.getReceivableCustomer());
                if (StringUtils.isBlank(order.getCustomerName())) {
                    order.setCustomerName(c.getCustomerName());
                }
            }
        }
        if (StringUtils.isNotBlank(order.getEmployeeNum())) {
            BaseEmployee e = baseEmployeeService.getOne(new QueryWrapper<BaseEmployee>()
                    .eq("org_id", orgId)
                    .eq("employee_num", order.getEmployeeNum().trim())
                    .eq("del_flag", "0")
                    .last("limit 1"));
            if (e != null) {
                order.setEmployeeName(e.getEmployeeName());
            }
        }
    }

    private void enrichGoodsFromMaterial(List<SalesOrderGoods> goods, String orgId) {
        if (goods == null || goods.isEmpty()) {
            return;
        }
        for (SalesOrderGoods g : goods) {
            if (StringUtils.isBlank(g.getGoodsNum())) {
                continue;
            }
            BaseMaterial m = baseMaterialService.getOne(new QueryWrapper<BaseMaterial>()
                    .eq("org_id", orgId)
                    .eq("goods_num", g.getGoodsNum())
                    .eq("del_flag", "0")
                    .last("limit 1"));
            if (m == null) {
                continue;
            }
            if (StringUtils.isBlank(g.getGoodsName())) {
                g.setGoodsName(m.getGoodsName());
            }
            if (StringUtils.isBlank(g.getGoodsSpec())) {
                g.setGoodsSpec(m.getGoodsSpec());
            }
            if (StringUtils.isBlank(g.getBaseUnit())) {
                g.setBaseUnit(m.getUnit());
            }
            if (StringUtils.isBlank(g.getAssUnit())) {
                g.setAssUnit(m.getAssistantUnit());
            }
            if (StringUtils.isBlank(g.getConversionValue())) {
                g.setConversionValue(m.getConversionValue());
            }
        }
    }

    /**
     * 单据编号规则：
     * XSDD + 当前日期后一天的yyyyMMdd + 3位机器标识 + 3位递增序号（不足补零，从001开始）
     */
    private String generateSalesOrderNum(String orgId) throws Exception {
        if (StringUtils.isBlank(orgId)) {
            throw new Exception("orgId不能为空");
        }
        String tomorrowYmd = LocalDate.now().plusDays(1).format(DateTimeFormatter.BASIC_ISO_DATE);
        String machineCode = getMachineCode3Digits();
        String base = "XSDD" + tomorrowYmd + machineCode;

        // 取该 base 前缀下当前最大序号（最后3位），若不存在则从 001 开始
        SalesOrder last = salesOrderService.getOne(new QueryWrapper<SalesOrder>()
                .eq("org_id", orgId)
                .eq("del_flag", "0")
                // 由于订单编号固定前缀格式，这里用 like 匹配前缀即可
                .like("order_num", base)
                .orderByDesc("order_num")
                .last("limit 1"));

        int startSeq = 1;
        if (last != null && StringUtils.isNotBlank(last.getOrderNum()) && last.getOrderNum().length() >= 3) {
            String suffix = last.getOrderNum().substring(last.getOrderNum().length() - 3);
            try {
                startSeq = Integer.parseInt(suffix) + 1;
            } catch (Exception ignored) {
                startSeq = 1;
            }
        }

        for (int seq = startSeq; seq <= 999; seq++) {
            String candidate = base + String.format("%03d", seq);
            long occupied = salesOrderService.count(new QueryWrapper<SalesOrder>()
                    .eq("org_id", orgId)
                    .eq("order_num", candidate)
                    .eq("del_flag", "0"));
            if (occupied == 0) {
                return candidate;
            }
        }
        throw new Exception("无法生成唯一销售订单编号");
    }

    /**
     * 生成 3 位机器标识：优先取网卡 MAC（取前向量 hash），取不到则使用主机名 hash。
     */
    private String getMachineCode3Digits() {
        try {
            byte[] mac = null;
            for (NetworkInterface ni : Collections.list(NetworkInterface.getNetworkInterfaces())) {
                if (ni == null || !ni.isUp() || ni.isLoopback() || ni.isVirtual()) {
                    continue;
                }
                byte[] addr = ni.getHardwareAddress();
                if (addr != null && addr.length > 0) {
                    mac = addr;
                    break;
                }
            }

            int val = 0;
            if (mac != null) {
                for (byte b : mac) {
                    val = (val * 31 + (b & 0xff)) % 1000;
                }
            } else {
                String host = InetAddress.getLocalHost().getHostName();
                val = Math.abs(host.hashCode()) % 1000;
            }
            return String.format("%03d", val);
        } catch (Exception e) {
            // 极端情况下兜底，确保接口不因机器标识失败而报错
            return "001";
        }
    }

    /** 小计=单价×基本计量数量；总计金额=各明细小计之和 */
    private void recalcGoodsSubTotalsAndOrderTotal(SalesOrder order) {
        List<SalesOrderGoods> goods = order.getGoods();
        if (goods == null || goods.isEmpty()) {
            order.setTotalAmount(null);
            return;
        }
        BigDecimal sum = BigDecimal.ZERO;
        boolean any = false;
        for (SalesOrderGoods g : goods) {
            BigDecimal line = null;

            // 优先按 unitPrice * baseNum 计算
            BigDecimal p = parseMoney(g.getUnitPrice());
            BigDecimal q = parseMoney(g.getBaseNum());
            if (p != null && q != null) {
                line = p.multiply(q);
            }

            if (line != null) {
                g.setSubTotal(formatMoney(line));
                sum = sum.add(line);
                any = true;
                continue;
            }

            // unitPrice 缺失时：不要清空，直接沿用已存在的小计 sub_total
            BigDecimal existing = parseMoney(g.getSubTotal());
            if (existing != null) {
                g.setSubTotal(formatMoney(existing));
                sum = sum.add(existing);
                any = true;
            } else {
                g.setSubTotal(null);
            }
        }

        if (any) {
            order.setTotalAmount(formatMoney(sum));
        } else {
            order.setTotalAmount(null);
        }
    }

    private BigDecimal parseMoney(String s) {
        if (StringUtils.isBlank(s)) {
            return null;
        }
        try {
            return new BigDecimal(s.trim().replace(",", ""));
        } catch (Exception e) {
            return null;
        }
    }

    private String formatMoney(BigDecimal n) {
        if (n == null) {
            return null;
        }
        return n.stripTrailingZeros().toPlainString();
    }

    /** 按单据编号将原明细逻辑删除（修改订单时先标记旧清单 del_flag=2） */
    private void deleteSalesOrderGoodsByOrderNum(String orgId, String orderNum) {
        if (StringUtils.isBlank(orgId) || StringUtils.isBlank(orderNum)) {
            return;
        }
        SalesOrderGoods up = new SalesOrderGoods();
        up.setDelFlag("2");
        up.setUpdateBy(getUsername());
        up.setUpdateTime(new Date());
        salesOrderGoodsService.update(up, new QueryWrapper<SalesOrderGoods>()
                .eq("org_id", orgId)
                .eq("order_num", orderNum)
                .eq("del_flag", "0"));
    }

    private void saveGoods(SalesOrder order, String orgId, String username) {
        List<SalesOrderGoods> goods = order.getGoods();
        if (goods == null) {
            goods = Collections.emptyList();
        }
        Date now = new Date();
        for (SalesOrderGoods g : goods) {
            g.setId(null);
            g.setOrgId(orgId);
            g.setOrderNum(order.getOrderNum());
            g.setDelFlag("0");
            g.setCreateBy(username);
            g.setCreateTime(now);
            g.setUpdateBy(null);
            g.setUpdateTime(null);
            salesOrderGoodsService.save(g);
        }
    }

    private SalesOrder getActiveById(String id) throws Exception {
        SalesOrder order = salesOrderService.getById(id);
        if (order == null || !"0".equals(order.getDelFlag())) {
            throw new Exception("销售订单不存在");
        }
        return order;
    }
}
