package com.ruoyi.warehouse.service.impl;

import java.math.BigDecimal;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.service.ISysUserService;
import com.ruoyi.warehouse.domain.InRecord;
import com.ruoyi.warehouse.domain.OutRecord;
import com.ruoyi.warehouse.domain.ProductInfo;
import com.ruoyi.warehouse.domain.StockCheckRecord;
import com.ruoyi.warehouse.domain.StockInfo;
import com.ruoyi.warehouse.domain.WarehouseArea;
import com.ruoyi.warehouse.domain.agent.AgentCandidate;
import com.ruoyi.warehouse.domain.agent.AgentPlan;
import com.ruoyi.warehouse.domain.agent.AgentResultItem;
import com.ruoyi.warehouse.service.IAgentService;
import com.ruoyi.warehouse.service.IInRecordService;
import com.ruoyi.warehouse.service.IOutRecordService;
import com.ruoyi.warehouse.service.IProductInfoService;
import com.ruoyi.warehouse.service.IStockCheckRecordService;
import com.ruoyi.warehouse.service.IStockInfoService;
import com.ruoyi.warehouse.service.IWarehouseAreaService;

@Service
public class AgentServiceImpl implements IAgentService
{
    private static final String ACTION_QUERY_STOCK = "query_stock";
    private static final String ACTION_CREATE_IN = "create_in_record";
    private static final String ACTION_CONFIRM_IN = "confirm_in_record";
    private static final String ACTION_CREATE_OUT = "create_out_record";
    private static final String ACTION_CREATE_CHECK = "create_stock_check";
    private static final String ACTION_CREATE_PRODUCT = "create_product";
    private static final String ACTION_CREATE_AREA = "create_area";
    private static final String ACTION_UNKNOWN = "unknown";

    private static final Pattern NUMBER_PATTERN = Pattern.compile("([0-9]+(?:\\.[0-9]+)?)");
    private static final Pattern IN_NO_PATTERN = Pattern.compile("(IN\\d+)", Pattern.CASE_INSENSITIVE);
    private static final Pattern INDEX_PATTERN = Pattern.compile("第\\s*([0-9一二两三四五六七八九十]+)\\s*(个|条|项)?");

    @Value("${agent.openai.base-url}")
    private String baseUrl;

    @Value("${agent.openai.api-key}")
    private String apiKey;

    @Value("${agent.openai.model}")
    private String model;

    @Autowired
    private IWarehouseAreaService areaService;

    @Autowired
    private IProductInfoService productService;

    @Autowired
    private IStockInfoService stockInfoService;

    @Autowired
    private IInRecordService inRecordService;

    @Autowired
    private IOutRecordService outRecordService;

    @Autowired
    private IStockCheckRecordService stockCheckRecordService;

    @Autowired
    private ISysUserService userService;

    @Override
    public AgentPlan analyze(String text, List<AgentResultItem> contextResults, String username)
    {
        if (StringUtils.isBlank(text))
        {
            throw new ServiceException("请输入要操作的内容");
        }

        AgentPlan plan = null;
        List<String> warnings = new ArrayList<>();
        if (StringUtils.isBlank(apiKey))
        {
            warnings.add("未配置 OPENAI_API_KEY，已使用基础规则解析");
        }
        else
        {
            try
            {
                plan = callModel(text, contextResults);
            }
            catch (Exception e)
            {
                warnings.add("大模型解析失败，已使用基础规则解析：" + e.getMessage());
            }
        }
        if (plan == null)
        {
            plan = fallbackParse(text);
        }
        plan.getWarnings().addAll(warnings);
        return normalizePlan(plan, text, username, contextResults);
    }

    @Override
    @Transactional
    public AgentPlan execute(AgentPlan plan, String username)
    {
        if (plan == null || StringUtils.isBlank(plan.getAction()))
        {
            throw new ServiceException("缺少可执行的操作草稿");
        }
        AgentPlan checkedPlan = normalizePlan(plan, null, username, null);
        if (!checkedPlan.isExecutable())
        {
            throw new ServiceException(StringUtils.defaultIfBlank(checkedPlan.getMessage(), "当前草稿不能执行"));
        }

        if (ACTION_QUERY_STOCK.equals(checkedPlan.getAction()))
        {
            checkedPlan.setMessage("查询完成");
            checkedPlan.setNeedConfirm(false);
            return checkedPlan;
        }
        if (ACTION_CREATE_IN.equals(checkedPlan.getAction()))
        {
            InRecord record = new InRecord();
            record.setAreaId(checkedPlan.getAreaId());
            record.setProductId(checkedPlan.getProductId());
            record.setInType(checkedPlan.getInType());
            record.setInNum(checkedPlan.getQuantity());
            record.setInOperator(checkedPlan.getOperatorName());
            record.setRemark(checkedPlan.getRemark());
            record.setOperator(username);
            inRecordService.insertInRecord(record);
            checkedPlan.setRecordId(record.getId());
            checkedPlan.setRecordNo(record.getInNo());
            checkedPlan.setMessage("已生成待入库记录：" + record.getInNo());
            checkedPlan.setNeedConfirm(false);
            return checkedPlan;
        }
        if (ACTION_CONFIRM_IN.equals(checkedPlan.getAction()))
        {
            inRecordService.confirmInRecord(checkedPlan.getRecordId(), username);
            checkedPlan.setMessage("已确认入库：" + checkedPlan.getRecordNo());
            checkedPlan.setNeedConfirm(false);
            return checkedPlan;
        }
        if (ACTION_CREATE_OUT.equals(checkedPlan.getAction()))
        {
            OutRecord record = new OutRecord();
            record.setAreaId(checkedPlan.getAreaId());
            record.setProductId(checkedPlan.getProductId());
            record.setOutType(checkedPlan.getOutType());
            record.setOutNum(checkedPlan.getQuantity());
            record.setOutOperator(checkedPlan.getOperatorName());
            record.setRemark(checkedPlan.getRemark());
            record.setOperator(username);
            outRecordService.insertOutRecord(record);
            checkedPlan.setRecordId(record.getId());
            checkedPlan.setRecordNo(record.getOutNo());
            checkedPlan.setMessage("已完成出库并生成记录：" + record.getOutNo());
            checkedPlan.setNeedConfirm(false);
            return checkedPlan;
        }
        if (ACTION_CREATE_CHECK.equals(checkedPlan.getAction()))
        {
            StockCheckRecord record = new StockCheckRecord();
            record.setAreaId(checkedPlan.getAreaId());
            record.setProductId(checkedPlan.getProductId());
            record.setRealNum(checkedPlan.getQuantity());
            record.setCheckUser(checkedPlan.getOperatorName());
            record.setReason(checkedPlan.getRemark());
            stockCheckRecordService.insertStockCheckRecord(record);
            checkedPlan.setRecordId(record.getId());
            checkedPlan.setRecordNo(record.getCheckNo());
            checkedPlan.setMessage("已生成待确认盘库记录：" + record.getCheckNo());
            checkedPlan.setNeedConfirm(false);
            return checkedPlan;
        }
        if (ACTION_CREATE_PRODUCT.equals(checkedPlan.getAction()))
        {
            ProductInfo product = new ProductInfo();
            product.setProductName(checkedPlan.getProductName());
            product.setBrand(checkedPlan.getBrand());
            product.setCategory(checkedPlan.getCategory());
            product.setSpec(checkedPlan.getSpec());
            product.setUnit(checkedPlan.getUnit());
            product.setRemark(checkedPlan.getRemark());
            productService.insertProductInfo(product);
            checkedPlan.setProductId(product.getId());
            checkedPlan.setMessage("已添加产品：" + product.getProductName());
            checkedPlan.setNeedConfirm(false);
            if (checkedPlan.getNextPlan() != null)
            {
                checkedPlan.getNextPlan().setProductId(product.getId());
                fillProduct(checkedPlan.getNextPlan(), product);
                normalizePlan(checkedPlan.getNextPlan(), null, username, null);
                checkedPlan.setMessage("已添加产品，并生成下一步草稿");
            }
            return checkedPlan;
        }
        if (ACTION_CREATE_AREA.equals(checkedPlan.getAction()))
        {
            WarehouseArea area = new WarehouseArea();
            area.setAreaName(checkedPlan.getAreaName());
            area.setRemark(checkedPlan.getRemark());
            areaService.insertWarehouseArea(area);
            checkedPlan.setAreaId(area.getId());
            checkedPlan.setMessage("已添加库区：" + area.getAreaName());
            checkedPlan.setNeedConfirm(false);
            if (checkedPlan.getNextPlan() != null)
            {
                checkedPlan.getNextPlan().setAreaId(area.getId());
                checkedPlan.getNextPlan().setAreaName(area.getAreaName());
                normalizePlan(checkedPlan.getNextPlan(), null, username, null);
                checkedPlan.setMessage("已添加库区，并生成下一步草稿");
            }
            return checkedPlan;
        }
        throw new ServiceException("暂不支持该操作");
    }

    private AgentPlan normalizePlan(AgentPlan plan, String originalText, String username, List<AgentResultItem> contextResults)
    {
        if (StringUtils.isBlank(plan.getAction()))
        {
            plan.setAction(ACTION_UNKNOWN);
        }
        if (requiresOperator(plan.getAction()) && StringUtils.isBlank(plan.getOperatorName()))
        {
            plan.setOperatorName(resolveNickName(username));
            plan.getWarnings().add("未识别到人员，默认使用当前登录用户");
        }

        if (ACTION_CREATE_IN.equals(plan.getAction()) && plan.getInType() == null)
        {
            plan.setInType(2);
            plan.getWarnings().add("未识别入库类型，默认采购入库");
        }
        if (ACTION_CREATE_OUT.equals(plan.getAction()) && plan.getOutType() == null)
        {
            plan.setOutType(1);
            plan.getWarnings().add("未识别出库类型，默认生产出库");
        }

        if (ACTION_CONFIRM_IN.equals(plan.getAction()))
        {
            resolveInRecord(plan, originalText);
            return plan;
        }
        if (ACTION_QUERY_STOCK.equals(plan.getAction()))
        {
            resolveArea(plan, originalText, false);
            resolveProduct(plan, originalText, false);
            fillStockResults(plan);
            plan.setNeedConfirm(false);
            plan.setExecutable(true);
            plan.setMessage(plan.getResults().isEmpty() ? stockNotFoundMessage(plan) : "查询到 " + plan.getResults().size() + " 条库存");
            if (StringUtils.isBlank(plan.getSummary()))
            {
                plan.setSummary("查询库存");
            }
            return plan;
        }

        if (ACTION_CREATE_IN.equals(plan.getAction()) || ACTION_CREATE_OUT.equals(plan.getAction()) || ACTION_CREATE_CHECK.equals(plan.getAction()))
        {
            resolveReferencedResult(plan, originalText, contextResults);
            resolveArea(plan, originalText, true);
            resolveProduct(plan, originalText, true);
            if ((ACTION_CREATE_IN.equals(plan.getAction()) || ACTION_CREATE_CHECK.equals(plan.getAction()))
                    && plan.getAreaId() == null && StringUtils.isNotBlank(plan.getAreaName()) && noAreaCandidates(plan))
            {
                AgentPlan areaPlan = buildAreaPlanFrom(plan);
                areaPlan.setNextPlan(copyOperationPlan(plan));
                normalizePlan(areaPlan, originalText, username, contextResults);
                areaPlan.setMessage("库区不存在，请先确认添加库区，添加后会继续生成操作草稿");
                return areaPlan;
            }
            if (ACTION_CREATE_IN.equals(plan.getAction()) && plan.getProductId() == null && plan.getCandidates().isEmpty())
            {
                AgentPlan productPlan = buildProductPlanFrom(plan);
                productPlan.setNextPlan(copyInPlan(plan));
                normalizePlan(productPlan, originalText, username, contextResults);
                productPlan.setMessage("产品信息不存在，请先确认添加产品，添加后会继续生成入库草稿");
                return productPlan;
            }
            validateQuantity(plan);
            plan.setNeedConfirm(true);
            plan.setExecutable(plan.getAreaId() != null && plan.getProductId() != null && validQuantity(plan) && plan.getCandidates().isEmpty());
            fillCurrentStock(plan);
            suggestAlternativeStockAreas(plan);
            fillSummary(plan);
            if (!plan.isExecutable() && StringUtils.isBlank(plan.getMessage()))
            {
                fillUnableToExecuteMessage(plan);
            }
            return plan;
        }

        if (ACTION_CREATE_PRODUCT.equals(plan.getAction()))
        {
            normalizeProductPlan(plan);
            ProductInfo sameProduct = findSameProduct(plan);
            if (sameProduct != null)
            {
                plan.setProductId(sameProduct.getId());
                plan.setExecutable(false);
                plan.setNeedConfirm(false);
                plan.setMessage("该产品已存在：" + sameProduct.getProductName());
                return plan;
            }
            plan.setNeedConfirm(true);
            plan.setExecutable(StringUtils.isNotBlank(plan.getProductName()));
            if (StringUtils.isBlank(plan.getMessage()))
            {
                plan.setMessage(plan.isExecutable() ? "请确认是否添加该产品" : "请补充产品名称");
            }
            fillSummary(plan);
            return plan;
        }

        if (ACTION_CREATE_AREA.equals(plan.getAction()))
        {
            WarehouseArea sameArea = findSameArea(plan.getAreaName());
            if (sameArea != null)
            {
                plan.setAreaId(sameArea.getId());
                plan.setExecutable(false);
                plan.setNeedConfirm(false);
                plan.setMessage("该库区已存在：" + sameArea.getAreaName());
                return plan;
            }
            plan.setNeedConfirm(true);
            plan.setExecutable(StringUtils.isNotBlank(plan.getAreaName()));
            if (StringUtils.isBlank(plan.getMessage()))
            {
                plan.setMessage(plan.isExecutable() ? "请确认是否添加该库区" : "请补充库区名称");
            }
            fillSummary(plan);
            return plan;
        }

        plan.setExecutable(false);
        plan.setNeedConfirm(false);
        fillActionCandidates(plan);
        plan.setMessage(plan.getCandidates().isEmpty() ? "暂时只能处理库存查询、入库登记、确认入库、出库、盘库、新增产品和新增库区" : "我不确定你要做什么，请选择操作类型后再说一次");
        return plan;
    }

    private AgentPlan callModel(String text, List<AgentResultItem> contextResults) throws Exception
    {
        JSONObject body = new JSONObject();
        body.put("model", model);
        JSONArray input = new JSONArray();
        input.add(message("system", systemPrompt()));
        input.add(message("user", buildUserInput(text, contextResults)));
        body.put("input", input);
        JSONObject format = new JSONObject();
        format.put("type", "json_object");
        JSONObject textFormat = new JSONObject();
        textFormat.put("format", format);
        body.put("text", textFormat);

        HttpClient client = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(30)).build();
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(normalizeEndpoint(baseUrl)))
                .timeout(Duration.ofSeconds(30))
                .header("Authorization", "Bearer " + apiKey)
                .header("Content-Type", "application/json")
                .POST(HttpRequest.BodyPublishers.ofString(body.toJSONString(), StandardCharsets.UTF_8))
                .build();
        HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8));
        if (response.statusCode() < 200 || response.statusCode() >= 300)
        {
            throw new ServiceException("HTTP " + response.statusCode());
        }
        String output = extractOutputText(response.body());
        if (StringUtils.isBlank(output))
        {
            throw new ServiceException("模型未返回内容");
        }
        return JSON.parseObject(extractJson(output), AgentPlan.class);
    }

    private JSONObject message(String role, String content)
    {
        JSONObject message = new JSONObject();
        message.put("role", role);
        message.put("content", content);
        return message;
    }

    private String systemPrompt()
    {
        return "你是库存管理系统的意图解析器，只返回一个 JSON 对象，不要解释。"
                + "action 只能是 query_stock, create_in_record, confirm_in_record, create_out_record, create_stock_check, create_product, create_area, unknown。"
                + "字段包括 action, areaName, productName, brand, category, spec, unit, quantity, inType, outType, operatorName, recordNo, remark, summary, referenceIndex。"
                + "如果用户说第几个、第二个、第2条等，referenceIndex 返回从 1 开始的序号。"
                + "入库类型 inType：1生产入库，2采购入库，3归还入库，4退货入库。"
                + "出库类型 outType：1生产出库，2退货出库，3销售出库。"
                + "新增产品时尽量从用户输入提取 productName, brand, category, spec, unit；如果用户未提供 category，优先从 existingCategories 选择合适类别，不合适时推断一个简短合理的类别。"
                + "除 category 可按规则推断外，不要编造其他字段；无法识别就填 null。新增库区提取 areaName。";
    }

    private String buildUserInput(String text, List<AgentResultItem> contextResults)
    {
        JSONObject payload = new JSONObject();
        payload.put("text", text);
        payload.put("contextResults", contextResults == null ? new ArrayList<>() : contextResults);
        payload.put("existingCategories", existingCategories());
        return payload.toJSONString();
    }

    private String normalizeEndpoint(String configuredBaseUrl)
    {
        String url = StringUtils.defaultIfBlank(configuredBaseUrl, "http://192.168.28.10:18080").trim();
        while (url.endsWith("/"))
        {
            url = url.substring(0, url.length() - 1);
        }
        if (url.endsWith("/v1"))
        {
            return url + "/responses";
        }
        if (url.endsWith("/v1/responses"))
        {
            return url;
        }
        return url + "/v1/responses";
    }

    private String extractOutputText(String responseBody)
    {
        JSONObject root = JSON.parseObject(responseBody);
        String outputText = root.getString("output_text");
        if (StringUtils.isNotBlank(outputText))
        {
            return outputText;
        }
        StringBuilder builder = new StringBuilder();
        JSONArray output = root.getJSONArray("output");
        if (output != null)
        {
            for (int i = 0; i < output.size(); i++)
            {
                JSONObject item = output.getJSONObject(i);
                JSONArray content = item == null ? null : item.getJSONArray("content");
                if (content == null)
                {
                    continue;
                }
                for (int j = 0; j < content.size(); j++)
                {
                    JSONObject contentItem = content.getJSONObject(j);
                    if (contentItem != null && StringUtils.isNotBlank(contentItem.getString("text")))
                    {
                        builder.append(contentItem.getString("text"));
                    }
                }
            }
        }
        return builder.toString();
    }

    private String extractJson(String output)
    {
        String text = output.trim();
        int start = text.indexOf('{');
        int end = text.lastIndexOf('}');
        if (start >= 0 && end > start)
        {
            return text.substring(start, end + 1);
        }
        return text;
    }

    private AgentPlan fallbackParse(String text)
    {
        String source = StringUtils.defaultString(text);
        AgentPlan plan = new AgentPlan();
        if ((source.contains("添加") || source.contains("新增") || source.contains("录入")) && source.contains("库区"))
        {
            plan.setAction(ACTION_CREATE_AREA);
            plan.setAreaName(extractAreaName(source));
        }
        else if ((source.contains("添加") || source.contains("新增") || source.contains("录入")) && source.contains("产品"))
        {
            plan.setAction(ACTION_CREATE_PRODUCT);
            fillProductDraft(plan, source);
        }
        else if (source.contains("确认") && source.contains("入库"))
        {
            plan.setAction(ACTION_CONFIRM_IN);
        }
        else if (source.contains("出库"))
        {
            plan.setAction(ACTION_CREATE_OUT);
            fillProductDraft(plan, source);
        }
        else if (source.contains("盘"))
        {
            plan.setAction(ACTION_CREATE_CHECK);
            fillProductDraft(plan, source);
        }
        else if (source.contains("入库"))
        {
            plan.setAction(ACTION_CREATE_IN);
            fillProductDraft(plan, source);
        }
        else if (source.contains("库存") || source.contains("查询") || source.contains("查"))
        {
            plan.setAction(ACTION_QUERY_STOCK);
        }
        else
        {
            plan.setAction(ACTION_UNKNOWN);
        }
        plan.setQuantity(extractQuantity(source));
        plan.setReferenceIndex(extractReferenceIndex(source));
        if (ACTION_QUERY_STOCK.equals(plan.getAction()))
        {
            plan.setProductName(extractStockKeyword(source));
        }
        plan.setRecordNo(extractInNo(source));
        plan.setInType(resolveInType(source));
        plan.setOutType(resolveOutType(source));
        plan.setRemark(source);
        return plan;
    }

    private Integer extractReferenceIndex(String text)
    {
        Matcher matcher = INDEX_PATTERN.matcher(StringUtils.defaultString(text));
        if (matcher.find())
        {
            return parseIndex(matcher.group(1));
        }
        return null;
    }

    private Integer parseIndex(String value)
    {
        if (StringUtils.isBlank(value))
        {
            return null;
        }
        String text = value.trim();
        if (text.matches("\\d+"))
        {
            return Integer.valueOf(text);
        }
        if ("一".equals(text))
        {
            return 1;
        }
        if ("二".equals(text) || "两".equals(text))
        {
            return 2;
        }
        if ("三".equals(text))
        {
            return 3;
        }
        if ("四".equals(text))
        {
            return 4;
        }
        if ("五".equals(text))
        {
            return 5;
        }
        if ("六".equals(text))
        {
            return 6;
        }
        if ("七".equals(text))
        {
            return 7;
        }
        if ("八".equals(text))
        {
            return 8;
        }
        if ("九".equals(text))
        {
            return 9;
        }
        if ("十".equals(text))
        {
            return 10;
        }
        if (text.startsWith("十"))
        {
            Integer tail = parseIndex(text.substring(1));
            return tail == null ? 10 : 10 + tail;
        }
        if (text.endsWith("十"))
        {
            Integer head = parseIndex(text.substring(0, text.length() - 1));
            return head == null ? null : head * 10;
        }
        int tenIndex = text.indexOf("十");
        if (tenIndex > 0)
        {
            Integer head = parseIndex(text.substring(0, tenIndex));
            Integer tail = parseIndex(text.substring(tenIndex + 1));
            return head == null ? null : head * 10 + (tail == null ? 0 : tail);
        }
        return null;
    }

    private String extractStockKeyword(String text)
    {
        String keyword = StringUtils.defaultString(text);
        keyword = keyword.replaceAll("帮我|请|一下|查一下|查询|查|库存|有多少|多少|还有|的", " ");
        keyword = keyword.replaceAll("\\s+", " ").trim();
        return StringUtils.isBlank(keyword) ? null : keyword;
    }

    private void fillProductDraft(AgentPlan plan, String text)
    {
        String content = StringUtils.defaultString(text)
                .replaceAll("帮我|请|添加|新增|录入|一个|一条|产品|商品|物料|入库|出库|盘库|盘点|采购|生产|销售|退货|归还", " ")
                .replaceAll("[，,;；、]", ",")
                .replaceAll("\\s+", " ")
                .trim();
        if (StringUtils.isBlank(content))
        {
            return;
        }
        String[] parts = content.split(",");
        List<String> values = new ArrayList<>();
        for (String part : parts)
        {
            String value = part.trim();
            if (StringUtils.isNotBlank(value) && !value.matches("[0-9]+(?:\\.[0-9]+)?(个|件|箱|支|台|套|包)?"))
            {
                values.add(value);
            }
        }
        if (!values.isEmpty() && StringUtils.isBlank(plan.getProductName()))
        {
            plan.setProductName(values.get(0));
        }
        if (values.size() > 1 && StringUtils.isBlank(plan.getBrand()))
        {
            plan.setBrand(values.get(1));
        }
        if (values.size() > 2 && StringUtils.isBlank(plan.getSpec()))
        {
            plan.setSpec(values.get(2));
        }
        if (values.size() > 3 && StringUtils.isBlank(plan.getCategory()))
        {
            plan.setCategory(values.get(3));
        }
        if (StringUtils.isBlank(plan.getUnit()))
        {
            plan.setUnit(extractUnit(text));
        }
    }

    private String extractAreaName(String text)
    {
        String areaName = StringUtils.defaultString(text)
                .replaceAll("帮我|请|添加|新增|录入|一个|一条|库区|仓库|区域", " ")
                .replaceAll("[，,;；、]", " ")
                .replaceAll("\\s+", " ")
                .trim();
        return StringUtils.isBlank(areaName) ? null : areaName;
    }

    private String extractUnit(String text)
    {
        Matcher matcher = Pattern.compile("[0-9]+(?:\\.[0-9]+)?\\s*(个|件|箱|支|台|套|包|卷|瓶|袋|张|本)").matcher(StringUtils.defaultString(text));
        if (matcher.find())
        {
            return matcher.group(1);
        }
        return null;
    }

    private BigDecimal extractQuantity(String text)
    {
        Matcher matcher = NUMBER_PATTERN.matcher(StringUtils.defaultString(text));
        BigDecimal quantity = null;
        while (matcher.find())
        {
            if (matcher.start() > 0 && text.charAt(matcher.start() - 1) == '第')
            {
                continue;
            }
            quantity = new BigDecimal(matcher.group(1));
        }
        return quantity;
    }

    private String extractInNo(String text)
    {
        Matcher matcher = IN_NO_PATTERN.matcher(StringUtils.defaultString(text));
        if (matcher.find())
        {
            return matcher.group(1).toUpperCase(Locale.ROOT);
        }
        return null;
    }

    private Integer resolveInType(String text)
    {
        if (StringUtils.isBlank(text))
        {
            return null;
        }
        if (text.contains("生产"))
        {
            return 1;
        }
        if (text.contains("归还"))
        {
            return 3;
        }
        if (text.contains("退货"))
        {
            return 4;
        }
        return text.contains("入库") ? 2 : null;
    }

    private Integer resolveOutType(String text)
    {
        if (StringUtils.isBlank(text))
        {
            return null;
        }
        if (text.contains("生产"))
        {
            return 1;
        }
        if (text.contains("退货"))
        {
            return 2;
        }
        return text.contains("出库") ? 3 : null;
    }

    private void resolveArea(AgentPlan plan, String originalText, boolean required)
    {
        if (plan.getAreaId() != null)
        {
            WarehouseArea area = areaService.selectWarehouseAreaById(plan.getAreaId());
            if (area != null)
            {
                plan.setAreaName(area.getAreaName());
                return;
            }
        }
        List<WarehouseArea> areas = areaService.selectWarehouseAreaAll();
        List<WarehouseArea> matches = new ArrayList<>();
        for (WarehouseArea area : areas)
        {
            if (matchesText(plan.getAreaName(), area.getAreaName(), area.getAreaCode())
                    || matchesText(originalText, area.getAreaName(), area.getAreaCode()))
            {
                matches.add(area);
            }
        }
        if (matches.size() == 1)
        {
            WarehouseArea area = matches.get(0);
            plan.setAreaId(area.getId());
            plan.setAreaName(area.getAreaName());
        }
        else if (matches.size() > 1)
        {
            for (WarehouseArea area : first(matches, 5))
            {
                plan.getCandidates().add(new AgentCandidate(area.getId(), "area", area.getAreaName(), area.getAreaCode()));
            }
            plan.setMessage("库区不唯一，请补充更明确的库区");
        }
        else if (required)
        {
            plan.getWarnings().add("未识别到库区");
        }
    }

    private void resolveProduct(AgentPlan plan, String originalText, boolean required)
    {
        if (plan.getProductId() != null)
        {
            ProductInfo product = productService.selectProductInfoById(plan.getProductId());
            if (product != null)
            {
                fillProduct(plan, product);
                return;
            }
        }
        List<ScoredProduct> matches = new ArrayList<>();
        for (ProductInfo product : productService.selectProductInfoAll())
        {
            int score = productScore(plan, originalText, product);
            if (score > 0)
            {
                matches.add(new ScoredProduct(product, score));
            }
        }
        matches.sort(Comparator.comparingInt(ScoredProduct::getScore).reversed());
        if (matches.isEmpty())
        {
            if (required)
            {
                plan.getWarnings().add("未识别到产品");
            }
            return;
        }
        int topScore = matches.get(0).getScore();
        List<ScoredProduct> topMatches = new ArrayList<>();
        for (ScoredProduct match : matches)
        {
            if (match.getScore() == topScore)
            {
                topMatches.add(match);
            }
        }
        if (topMatches.size() == 1)
        {
            fillProduct(plan, topMatches.get(0).getProduct());
            return;
        }
        for (ScoredProduct match : first(topMatches, 5))
        {
            ProductInfo product = match.getProduct();
            plan.getCandidates().add(new AgentCandidate(product.getId(), "product", product.getProductName(), productDetail(product)));
        }
        if (!ACTION_QUERY_STOCK.equals(plan.getAction()))
        {
            fillProductChoices(plan, topMatches);
        }
        plan.setMessage(plan.getResults().isEmpty()
                ? "产品不唯一，请选择候选产品，或补充名称、规格、品牌、类别"
                : "找到多个匹配产品，请在下方选择要操作的库存项");
    }

    private void resolveReferencedResult(AgentPlan plan, String originalText, List<AgentResultItem> contextResults)
    {
        if (plan.getReferenceIndex() == null)
        {
            plan.setReferenceIndex(extractReferenceIndex(originalText));
        }
        if (plan.getReferenceIndex() == null)
        {
            return;
        }
        if (contextResults == null || contextResults.isEmpty())
        {
            plan.setMessage("没有可引用的上次查询结果，请先查询库存");
            return;
        }
        int index = plan.getReferenceIndex() - 1;
        if (index < 0 || index >= contextResults.size())
        {
            plan.setMessage("上次查询结果没有第 " + plan.getReferenceIndex() + " 项");
            return;
        }
        AgentResultItem item = contextResults.get(index);
        plan.setStockId(item.getId());
        plan.setAreaId(item.getAreaId());
        plan.setProductId(item.getProductId());
        plan.setAreaName(item.getAreaName());
        plan.setProductName(item.getProductName());
        plan.setBrand(item.getBrand());
        plan.setCategory(item.getCategory());
        plan.setSpec(item.getSpec());
        plan.setUnit(item.getUnit());
        plan.setCurrentStock(item.getStockNum());
        plan.getWarnings().add("已引用上次查询的第 " + plan.getReferenceIndex() + " 项");
    }

    private AgentPlan buildProductPlanFrom(AgentPlan source)
    {
        AgentPlan plan = new AgentPlan();
        plan.setAction(ACTION_CREATE_PRODUCT);
        plan.setProductName(source.getProductName());
        plan.setBrand(source.getBrand());
        plan.setCategory(source.getCategory());
        plan.setSpec(source.getSpec());
        plan.setUnit(source.getUnit());
        plan.setRemark(source.getRemark());
        return plan;
    }

    private AgentPlan buildAreaPlanFrom(AgentPlan source)
    {
        AgentPlan plan = new AgentPlan();
        plan.setAction(ACTION_CREATE_AREA);
        plan.setAreaName(source.getAreaName());
        plan.setRemark(source.getRemark());
        return plan;
    }

    private AgentPlan copyInPlan(AgentPlan source)
    {
        AgentPlan plan = new AgentPlan();
        plan.setAction(ACTION_CREATE_IN);
        plan.setAreaId(source.getAreaId());
        plan.setAreaName(source.getAreaName());
        plan.setQuantity(source.getQuantity());
        plan.setInType(source.getInType());
        plan.setOperatorName(source.getOperatorName());
        plan.setRemark(source.getRemark());
        return plan;
    }

    private AgentPlan copyOperationPlan(AgentPlan source)
    {
        AgentPlan plan = new AgentPlan();
        plan.setAction(source.getAction());
        plan.setAreaId(source.getAreaId());
        plan.setProductId(source.getProductId());
        plan.setAreaName(source.getAreaName());
        plan.setProductName(source.getProductName());
        plan.setBrand(source.getBrand());
        plan.setCategory(source.getCategory());
        plan.setSpec(source.getSpec());
        plan.setUnit(source.getUnit());
        plan.setQuantity(source.getQuantity());
        plan.setInType(source.getInType());
        plan.setOutType(source.getOutType());
        plan.setOperatorName(source.getOperatorName());
        plan.setRemark(source.getRemark());
        return plan;
    }

    private void normalizeProductPlan(AgentPlan plan)
    {
        if (StringUtils.isNotBlank(plan.getProductName()))
        {
            plan.setProductName(plan.getProductName().trim());
        }
        if (StringUtils.isNotBlank(plan.getBrand()))
        {
            plan.setBrand(plan.getBrand().trim());
        }
        if (StringUtils.isNotBlank(plan.getCategory()))
        {
            plan.setCategory(plan.getCategory().trim());
        }
        if (StringUtils.isNotBlank(plan.getSpec()))
        {
            plan.setSpec(plan.getSpec().trim());
        }
        if (StringUtils.isNotBlank(plan.getUnit()))
        {
            plan.setUnit(plan.getUnit().trim());
        }
        if (StringUtils.isBlank(plan.getCategory()) && StringUtils.isNotBlank(plan.getProductName()))
        {
            ProductInfo draft = new ProductInfo();
            draft.setProductName(plan.getProductName());
            draft.setBrand(plan.getBrand());
            draft.setSpec(plan.getSpec());
            draft.setUnit(plan.getUnit());
            String category = productService.inferProductCategory(draft);
            if (StringUtils.isNotBlank(category))
            {
                plan.setCategory(category);
                plan.getWarnings().add("未提供类别，已自动分类为：" + category);
            }
        }
    }

    private List<String> existingCategories()
    {
        Set<String> categories = new LinkedHashSet<>();
        for (ProductInfo product : productService.selectProductInfoAll())
        {
            if (StringUtils.isNotBlank(product.getCategory()))
            {
                categories.add(product.getCategory().trim());
            }
            if (categories.size() >= 80)
            {
                break;
            }
        }
        return new ArrayList<>(categories);
    }

    private boolean requiresOperator(String action)
    {
        return ACTION_CREATE_IN.equals(action)
                || ACTION_CONFIRM_IN.equals(action)
                || ACTION_CREATE_OUT.equals(action)
                || ACTION_CREATE_CHECK.equals(action);
    }

    private boolean noAreaCandidates(AgentPlan plan)
    {
        for (AgentCandidate candidate : plan.getCandidates())
        {
            if ("area".equals(candidate.getType()))
            {
                return false;
            }
        }
        return true;
    }

    private void fillUnableToExecuteMessage(AgentPlan plan)
    {
        if (plan.getProductId() == null && hasProductClue(plan) && noProductCandidates(plan))
        {
            plan.setMessage("没找到产品：" + productClue(plan) + "。请先确认产品名称、品牌、类别或规格是否已维护。");
            return;
        }
        if (plan.getAreaId() == null && StringUtils.isNotBlank(plan.getAreaName()) && noAreaCandidates(plan))
        {
            plan.setMessage("没找到库区：" + plan.getAreaName() + "。请先维护库区后再操作。");
            return;
        }
        if (ACTION_CREATE_OUT.equals(plan.getAction()) && plan.getProductId() != null && plan.getResults().isEmpty())
        {
            String product = StringUtils.defaultIfBlank(plan.getProductName(), "该产品");
            plan.setMessage("没找到可出库库存：" + product + "。请确认产品是否已有库存，或选择正确库区。");
            return;
        }
        if (plan.getCandidates() != null && !plan.getCandidates().isEmpty())
        {
            plan.setMessage("存在多个候选，请先选择要操作的数据");
            return;
        }
        if (!validQuantity(plan))
        {
            plan.setMessage(ACTION_CREATE_CHECK.equals(plan.getAction()) ? "未识别到实际盘点数量" : "未识别到有效数量");
            return;
        }
        plan.setMessage("信息不完整，请补充后再执行");
    }

    private boolean noProductCandidates(AgentPlan plan)
    {
        for (AgentCandidate candidate : plan.getCandidates())
        {
            if ("product".equals(candidate.getType()))
            {
                return false;
            }
        }
        return true;
    }

    private boolean hasProductClue(AgentPlan plan)
    {
        return StringUtils.isNotBlank(plan.getProductName())
                || StringUtils.isNotBlank(plan.getBrand())
                || StringUtils.isNotBlank(plan.getCategory())
                || StringUtils.isNotBlank(plan.getSpec());
    }

    private String productClue(AgentPlan plan)
    {
        return firstNotBlank(plan.getProductName(), plan.getBrand(), plan.getCategory(), plan.getSpec(), "未识别产品");
    }

    private String stockNotFoundMessage(AgentPlan plan)
    {
        List<String> parts = new ArrayList<>();
        if (StringUtils.isNotBlank(plan.getAreaName()))
        {
            parts.add("库区：" + plan.getAreaName());
        }
        if (hasProductClue(plan))
        {
            parts.add("产品：" + productClue(plan));
        }
        if (parts.isEmpty())
        {
            return "未查询到库存数据";
        }
        return "未查询到符合条件的库存数据（" + String.join("，", parts) + "）";
    }

    private void fillActionCandidates(AgentPlan plan)
    {
        plan.getCandidates().add(new AgentCandidate(1L, "action", "查库存", "例如：查一下路由器库存"));
        plan.getCandidates().add(new AgentCandidate(2L, "action", "入库登记", "例如：采购入库路由器10个到一号库"));
        plan.getCandidates().add(new AgentCandidate(3L, "action", "出库", "例如：第二个出库1个"));
        plan.getCandidates().add(new AgentCandidate(4L, "action", "盘库", "例如：盘点路由器实际5个"));
        plan.getCandidates().add(new AgentCandidate(5L, "action", "新增产品", "例如：添加产品纸，心心相印，3层120抽"));
        plan.getCandidates().add(new AgentCandidate(6L, "action", "新增库区", "例如：新增库区一号库"));
    }

    private ProductInfo findSameProduct(AgentPlan plan)
    {
        for (ProductInfo product : productService.selectProductInfoAll())
        {
            if (sameText(product.getProductName(), plan.getProductName())
                    && sameText(product.getBrand(), plan.getBrand())
                    && sameText(product.getCategory(), plan.getCategory())
                    && sameText(product.getSpec(), plan.getSpec()))
            {
                return product;
            }
        }
        return null;
    }

    private WarehouseArea findSameArea(String areaName)
    {
        if (StringUtils.isBlank(areaName))
        {
            return null;
        }
        for (WarehouseArea area : areaService.selectWarehouseAreaAll())
        {
            if (sameText(area.getAreaName(), areaName))
            {
                return area;
            }
        }
        return null;
    }

    private boolean sameText(String left, String right)
    {
        return StringUtils.defaultString(left).trim().equalsIgnoreCase(StringUtils.defaultString(right).trim());
    }

    private int productScore(AgentPlan plan, String originalText, ProductInfo product)
    {
        int score = 0;
        score += fieldScore(plan.getProductName(), product.getProductName(), 8);
        score += fieldScore(plan.getBrand(), product.getBrand(), 4);
        score += fieldScore(plan.getCategory(), product.getCategory(), 4);
        score += fieldScore(plan.getSpec(), product.getSpec(), 4);
        score += fieldScore(plan.getUnit(), product.getUnit(), 1);
        String fullInfo = productFullText(product);
        if (containsIgnoreCase(originalText, fullInfo) || containsIgnoreCase(fullInfo, originalText))
        {
            score += 2;
        }
        else
        {
            score += containsField(originalText, product.getProductName()) ? 4 : 0;
            score += containsField(originalText, product.getBrand()) ? 2 : 0;
            score += containsField(originalText, product.getCategory()) ? 2 : 0;
            score += containsField(originalText, product.getSpec()) ? 2 : 0;
        }
        return score;
    }

    private int fieldScore(String input, String target, int exactScore)
    {
        if (StringUtils.isBlank(input) || StringUtils.isBlank(target))
        {
            return 0;
        }
        if (input.trim().equalsIgnoreCase(target.trim()))
        {
            return exactScore;
        }
        if (containsIgnoreCase(input, target) || containsIgnoreCase(target, input))
        {
            return Math.max(1, exactScore / 2);
        }
        return 0;
    }

    private boolean matchesText(String input, String... values)
    {
        if (StringUtils.isBlank(input))
        {
            return false;
        }
        for (String value : values)
        {
            if (containsField(input, value))
            {
                return true;
            }
        }
        return false;
    }

    private boolean containsField(String text, String field)
    {
        return StringUtils.isNotBlank(text) && StringUtils.isNotBlank(field) && containsIgnoreCase(text, field);
    }

    private boolean containsIgnoreCase(String text, String keyword)
    {
        if (StringUtils.isBlank(text) || StringUtils.isBlank(keyword))
        {
            return false;
        }
        return text.toLowerCase(Locale.ROOT).contains(keyword.toLowerCase(Locale.ROOT));
    }

    private void fillProduct(AgentPlan plan, ProductInfo product)
    {
        plan.setProductId(product.getId());
        plan.setProductName(product.getProductName());
        plan.setBrand(product.getBrand());
        plan.setCategory(product.getCategory());
        plan.setSpec(product.getSpec());
        plan.setUnit(product.getUnit());
    }

    private String productFullText(ProductInfo product)
    {
        return StringUtils.defaultString(product.getProductName()) + " "
                + StringUtils.defaultString(product.getBrand()) + " "
                + StringUtils.defaultString(product.getCategory()) + " "
                + StringUtils.defaultString(product.getSpec()) + " "
                + StringUtils.defaultString(product.getUnit());
    }

    private String productDetail(ProductInfo product)
    {
        List<String> parts = new ArrayList<>();
        addPart(parts, product.getBrand());
        addPart(parts, product.getCategory());
        addPart(parts, product.getSpec());
        addPart(parts, product.getUnit());
        return String.join(" / ", parts);
    }

    private void addPart(List<String> parts, String value)
    {
        if (StringUtils.isNotBlank(value))
        {
            parts.add(value);
        }
    }

    private void validateQuantity(AgentPlan plan)
    {
        if (!validQuantity(plan))
        {
            plan.getWarnings().add(ACTION_CREATE_CHECK.equals(plan.getAction()) ? "未识别到实际盘点数量" : "未识别到有效数量");
        }
    }

    private boolean validQuantity(AgentPlan plan)
    {
        if (plan.getQuantity() == null)
        {
            return false;
        }
        if (ACTION_CREATE_CHECK.equals(plan.getAction()))
        {
            return plan.getQuantity().signum() >= 0;
        }
        return plan.getQuantity().signum() > 0;
    }

    private void fillStockResults(AgentPlan plan)
    {
        StockInfo query = new StockInfo();
        query.setAreaId(plan.getAreaId());
        query.setProductId(plan.getProductId());
        if (plan.getProductId() == null)
        {
            query.setProductName(firstNotBlank(plan.getProductName(), plan.getBrand(), plan.getCategory(), plan.getSpec()));
        }
        List<StockInfo> stockList = stockInfoService.selectStockInfoList(query);
        int count = 0;
        for (StockInfo stock : stockList)
        {
            if (count++ >= 20)
            {
                plan.getWarnings().add("结果较多，仅展示前 20 条");
                break;
            }
            plan.getResults().add(toResult(stock));
        }
    }

    private AgentResultItem toResult(StockInfo stock)
    {
        AgentResultItem item = new AgentResultItem();
        item.setId(stock.getId());
        item.setAreaId(stock.getAreaId());
        item.setProductId(stock.getProductId());
        item.setAreaName(stock.getAreaName());
        item.setProductName(stock.getProductName());
        item.setBrand(stock.getBrand());
        item.setCategory(stock.getCategory());
        item.setSpec(stock.getSpec());
        item.setUnit(stock.getUnit());
        item.setStockNum(stock.getStockNum());
        return item;
    }

    private AgentResultItem toProductResult(ProductInfo product)
    {
        AgentResultItem item = new AgentResultItem();
        item.setProductId(product.getId());
        item.setProductName(product.getProductName());
        item.setBrand(product.getBrand());
        item.setCategory(product.getCategory());
        item.setSpec(product.getSpec());
        item.setUnit(product.getUnit());
        return item;
    }

    private void fillProductChoices(AgentPlan plan, List<ScoredProduct> matches)
    {
        int count = 0;
        for (ScoredProduct match : first(matches, 10))
        {
            ProductInfo product = match.getProduct();
            StockInfo query = new StockInfo();
            query.setAreaId(plan.getAreaId());
            query.setProductId(product.getId());
            List<StockInfo> stockList = stockInfoService.selectStockInfoList(query);
            if (stockList.isEmpty())
            {
                if (!ACTION_CREATE_OUT.equals(plan.getAction()))
                {
                    plan.getResults().add(toProductResult(product));
                    count++;
                }
            }
            else
            {
                for (StockInfo stock : stockList)
                {
                    if (count++ >= 20)
                    {
                        plan.getWarnings().add("匹配结果较多，仅展示前 20 条");
                        return;
                    }
                    plan.getResults().add(toResult(stock));
                }
            }
        }
    }

    private void fillCurrentStock(AgentPlan plan)
    {
        if (plan.getAreaId() == null || plan.getProductId() == null)
        {
            return;
        }
        StockInfo query = new StockInfo();
        query.setAreaId(plan.getAreaId());
        query.setProductId(plan.getProductId());
        List<StockInfo> stockList = stockInfoService.selectStockInfoList(query);
        BigDecimal current = stockList.isEmpty() || stockList.get(0).getStockNum() == null ? BigDecimal.ZERO : stockList.get(0).getStockNum();
        plan.setCurrentStock(current);
        if (plan.getQuantity() != null)
        {
            if (ACTION_CREATE_IN.equals(plan.getAction()))
            {
                plan.setAfterStock(current.add(plan.getQuantity()));
            }
            else if (ACTION_CREATE_OUT.equals(plan.getAction()))
            {
                plan.setAfterStock(current.subtract(plan.getQuantity()));
                if (current.compareTo(plan.getQuantity()) < 0)
                {
                    plan.setExecutable(false);
                    plan.setMessage("库存不足，当前库存：" + current);
                }
            }
            else if (ACTION_CREATE_CHECK.equals(plan.getAction()))
            {
                plan.setAfterStock(plan.getQuantity());
            }
        }
    }

    private void suggestAlternativeStockAreas(AgentPlan plan)
    {
        if (!ACTION_CREATE_OUT.equals(plan.getAction()) || plan.getProductId() == null || plan.isExecutable()
                || (plan.getAreaId() == null && (StringUtils.isNotBlank(plan.getAreaName()) || !noAreaCandidates(plan))))
        {
            return;
        }
        StockInfo query = new StockInfo();
        query.setProductId(plan.getProductId());
        List<StockInfo> stockList = stockInfoService.selectStockInfoList(query);
        for (StockInfo stock : stockList)
        {
            if (stock.getStockNum() != null && stock.getStockNum().signum() > 0
                    && (plan.getAreaId() == null || !stock.getAreaId().equals(plan.getAreaId())))
            {
                plan.getResults().add(toResult(stock));
            }
            if (plan.getResults().size() >= 10)
            {
                break;
            }
        }
        if (!plan.getResults().isEmpty())
        {
            plan.setNeedConfirm(false);
            plan.setExecutable(false);
            plan.setMessage("当前库区库存不足或没有库存，其他库区有库存。请说“第几个出库多少个”。");
        }
    }

    private void fillSummary(AgentPlan plan)
    {
        if (StringUtils.isNotBlank(plan.getSummary()))
        {
            return;
        }
        String product = StringUtils.defaultIfBlank(plan.getProductName(), "未识别产品");
        String area = StringUtils.defaultIfBlank(plan.getAreaName(), "未识别库区");
        String quantity = plan.getQuantity() == null ? "未识别数量" : plan.getQuantity().stripTrailingZeros().toPlainString();
        if (ACTION_CREATE_IN.equals(plan.getAction()))
        {
            plan.setSummary("登记入库：" + area + "，" + product + "，数量 " + quantity);
        }
        else if (ACTION_CREATE_OUT.equals(plan.getAction()))
        {
            plan.setSummary("执行出库：" + area + "，" + product + "，数量 " + quantity);
        }
        else if (ACTION_CREATE_CHECK.equals(plan.getAction()))
        {
            plan.setSummary("登记盘库：" + area + "，" + product + "，实际数量 " + quantity);
        }
        else if (ACTION_CREATE_PRODUCT.equals(plan.getAction()))
        {
            plan.setSummary("添加产品：" + product);
        }
        else if (ACTION_CREATE_AREA.equals(plan.getAction()))
        {
            plan.setSummary("添加库区：" + StringUtils.defaultIfBlank(plan.getAreaName(), "未识别库区"));
        }
    }

    private void resolveInRecord(AgentPlan plan, String originalText)
    {
        if (StringUtils.isBlank(plan.getRecordNo()))
        {
            plan.setRecordNo(extractInNo(originalText));
        }
        if (StringUtils.isBlank(plan.getRecordNo()))
        {
            plan.setExecutable(false);
            plan.setNeedConfirm(false);
            plan.setMessage("请提供要确认的入库单号");
            return;
        }
        InRecord query = new InRecord();
        query.setInNo(plan.getRecordNo());
        List<InRecord> records = inRecordService.selectInRecordList(query);
        if (records.isEmpty())
        {
            plan.setExecutable(false);
            plan.setNeedConfirm(false);
            plan.setMessage("未找到入库单：" + plan.getRecordNo());
            return;
        }
        InRecord record = records.get(0);
        plan.setRecordId(record.getId());
        plan.setRecordNo(record.getInNo());
        plan.setAreaId(record.getAreaId());
        plan.setProductId(record.getProductId());
        plan.setAreaName(record.getAreaName());
        plan.setProductName(record.getProductName());
        plan.setBrand(record.getBrand());
        plan.setCategory(record.getCategory());
        plan.setSpec(record.getSpec());
        plan.setUnit(record.getUnit());
        plan.setQuantity(record.getInNum());
        plan.setNeedConfirm(true);
        plan.setExecutable(!Integer.valueOf(1).equals(record.getInStatus()));
        plan.setSummary("确认入库：" + record.getInNo());
        plan.setMessage(plan.isExecutable() ? "请确认是否执行入库" : "该入库单已经确认");
    }

    private String resolveNickName(String username)
    {
        if (StringUtils.isBlank(username))
        {
            return username;
        }
        SysUser user = userService.selectUserByUserName(username);
        if (user != null && StringUtils.isNotBlank(user.getNickName()))
        {
            return user.getNickName();
        }
        return username;
    }

    private String firstNotBlank(String... values)
    {
        for (String value : values)
        {
            if (StringUtils.isNotBlank(value))
            {
                return value;
            }
        }
        return null;
    }

    private <T> List<T> first(List<T> source, int limit)
    {
        if (source.size() <= limit)
        {
            return source;
        }
        return source.subList(0, limit);
    }

    private static class ScoredProduct
    {
        private final ProductInfo product;
        private final int score;

        private ScoredProduct(ProductInfo product, int score)
        {
            this.product = product;
            this.score = score;
        }

        public ProductInfo getProduct()
        {
            return product;
        }

        public int getScore()
        {
            return score;
        }
    }
}
