package com.smqjh.agent.mcp;

import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Locale;

final class MonthlySettlementPlanner {
    private static final List<Enterprise> ENTERPRISES = List.of(
        new Enterprise(54, "1", "招商银行贵阳分行"),
        new Enterprise(55, "2", "中数未来"),
        new Enterprise(58, "5", "铜仁移动")
    );

    ObjectNode plan(String enterpriseInput, String month) {
        Enterprise enterprise = findEnterprise(enterpriseInput);
        if (enterprise == null) {
            throw new IllegalArgumentException("未找到月结企业: " + enterpriseInput);
        }
        LocalDate start = parseMonth(month);
        LocalDate end = start.plusMonths(1);

        ObjectNode root = Jsons.object();
        root.put("title", enterprise.name() + " " + month + " 月结处理计划");
        root.put("enterpriseName", enterprise.name());
        root.put("channelId", enterprise.channelId());
        root.put("channelNo", enterprise.channelNo());
        root.put("month", month);
        root.put("startTime", start + " 00:00:00");
        root.put("endTime", end + " 00:00:00");
        root.put("settlementScope", "企业用户定时月结；所有已付款订单；逻辑删除订单不参与。");
        ArrayNode exportRows = exports(enterprise, start, end);
        root.set("columns", Jsons.MAPPER.valueToTree(new String[] {"name", "method", "adminEndpoint", "params", "backendEvidence", "note"}));
        root.set("rows", exportRows);
        root.set("exports", exportRows);
        root.set("rules", rules());
        root.set("invoiceStates", invoiceStates());
        root.put("adminTenantRule", "顶级 admin 登录/调用不需要 tenantCode；非 admin 仍需要 tenantCode 或租户上下文。");
        root.put("mcpUsage", "后续可由 Agent 先调用本工具生成计划，再调用导出接口、只读 SQL 和 Excel 处理工具生成结算报告。");
        return root;
    }

    ObjectNode enterprises() {
        ObjectNode root = Jsons.object();
        ArrayNode rows = Jsons.MAPPER.createArrayNode();
        for (Enterprise enterprise : ENTERPRISES) {
            ObjectNode row = Jsons.object();
            row.put("channelId", enterprise.channelId());
            row.put("channelNo", enterprise.channelNo());
            row.put("enterpriseName", enterprise.name());
            row.put("settlementType", "企业用户定时月结");
            row.put("scope", "所有已付款订单，排除逻辑删除订单");
            rows.add(row);
        }
        root.put("title", "月结企业清单");
        root.set("columns", Jsons.MAPPER.valueToTree(new String[] {"channelId", "channelNo", "enterpriseName", "settlementType", "scope"}));
        root.set("rows", rows);
        root.put("rowCount", rows.size());
        root.put("note", "来自管理员确认的 sm_channel 月结企业配置；顶级 admin 不需要 tenantCode。");
        return root;
    }

    private ArrayNode exports(Enterprise enterprise, LocalDate start, LocalDate end) {
        ArrayNode exports = Jsons.MAPPER.createArrayNode();
        exports.add(exportSpec(
            "员工列表积分情况",
            "GET",
            "/plt/admin/enterprise/export",
            "channelIdList[0]=" + enterprise.channelId(),
            "业务代码证据：smqjh-system /api/v1/members/enterprise/export；积分充值表 sm_points_recharge；会员表 sm_member。",
            "用于员工、手机号、充值积分、消费积分、可用积分核对；汇总时按 user_id + channel_id。"
        ));
        exports.add(exportSpec(
            "订单表",
            "GET/POST",
            "/plt/platform/order/export",
            "channelIdList[0]=" + enterprise.channelId() + "&orderStatus=all&startTime=" + start + "%2000:00:00&endTime=" + end + "%2000:00:00",
            "业务代码证据：OrderController POST /api/v1/order/export?exportType=ORDER；OmsOrderMapper.exportOrderList；oms_order。",
            "导出后需要按 is_payed=1 和 COALESCE(delete_status,0)=0 口径核对，金额差异标记需人工确认。"
        ));
        exports.add(exportSpec(
            "商品订单表",
            "GET/POST",
            "/plt/platform/order/export",
            "channelIdList[0]=" + enterprise.channelId() + "&orderStatus=all&exportType=PRODUCT&startTime=" + start + "%2000:00:00&endTime=" + end + "%2000:00:00",
            "业务代码证据：OrderController POST /api/v1/order/export?exportType=PRODUCT；OmsOrderMapper.exportProductList；oms_order_item + tz_sku。",
            "从商品表补齐海博编码、商品编码、SKU 编码；汇总商品总额、数量和规格。"
        ));
        exports.add(exportSpec(
            "运费账单表",
            "GET",
            "/plt/platform/sku/freightStatisticsExcel",
            "channelIds[0]=" + enterprise.channelId(),
            "业务代码证据：运费导出入口由后台提供；优先按订单号和配送单号与 oms_order 关联。",
            "汇总总运费；订单号无法关联或金额不一致时标记需人工确认。"
        ));
        exports.add(exportSpec(
            "对账汇总表模板",
            "GET",
            "/plt/platform/sku/skuStatisticsExcel",
            "channelIds[0]=" + enterprise.channelId(),
            "业务代码证据：后台对账汇总导出模板；Agent 负责补充汇总公式和蓝色核对区。",
            "业务系统导出的模板本身可用，但缺少自动汇总计算和小蓝表核对区。"
        ));
        return exports;
    }

    private ObjectNode exportSpec(String name, String method, String endpoint, String params, String evidence, String note) {
        ObjectNode item = Jsons.object();
        item.put("name", name);
        item.put("method", method);
        item.put("adminEndpoint", endpoint);
        item.put("params", params);
        item.put("backendEvidence", evidence);
        item.put("note", note);
        return item;
    }

    private ArrayNode rules() {
        ArrayNode rules = Jsons.MAPPER.createArrayNode();
        rules.add("商品总额 = 已付款商品订单明细小计汇总。");
        rules.add("总运费 = 运费账单按订单号或配送单号匹配后汇总。");
        rules.add("负数积分抵扣表示充值转换为积分后的抵扣金额。");
        rules.add("商品金额、运费、积分抵扣、现金支付任意差异不为 0，标记为“需人工确认”。");
        rules.add("只标记差异，不自动修改业务系统数据。");
        rules.add("结算报告生成后发送客户核对，再打印盖章、开电子发票、等待客户付款。");
        return rules;
    }

    private ArrayNode invoiceStates() {
        ArrayNode states = Jsons.MAPPER.createArrayNode();
        states.add("待客户核对");
        states.add("待打印盖章");
        states.add("待开电子发票");
        states.add("待客户付款");
        states.add("已完成");
        return states;
    }

    private Enterprise findEnterprise(String input) {
        String normalized = input == null ? "" : input.trim().toLowerCase(Locale.ROOT);
        return ENTERPRISES.stream()
            .filter(item -> item.name().toLowerCase(Locale.ROOT).contains(normalized)
                || item.channelNo().equals(normalized)
                || String.valueOf(item.channelId()).equals(normalized))
            .findFirst()
            .orElse(null);
    }

    private LocalDate parseMonth(String month) {
        if (month == null || !month.matches("\\d{4}-\\d{2}")) {
            throw new IllegalArgumentException("month 必须是 YYYY-MM");
        }
        return LocalDate.parse(month + "-01", DateTimeFormatter.ISO_LOCAL_DATE);
    }

    private record Enterprise(int channelId, String channelNo, String name) {
    }
}
