package jnpf.attendance.schedule;

import org.slf4j.Logger;

import java.time.LocalDate;
import java.util.List;

/**
 * 智能排班算法「可测试观测」日志：统一前缀 {@value #MARKER}，供测试/实施在日志中 grep 穿透黑盒决策。
 *
 * <p>每条 INFO 日志均带 {@code testIssue}，与测试侧「三大不可验证痛点」对齐：
 *
 * <ul>
 *   <li>{@link #TEST_ISSUE_1_SIMILAR_HISTORICAL_DATES 问题1} — 相似历史日期筛选策略（步骤触发、样本集、兜底）；</li>
 *   <li>{@link #TEST_ISSUE_2_HALF_HOUR_DEMAND_MATRIX 问题2} — 半小时岗位需求矩阵（波动阈值、中位数/P75、追溯）；</li>
 *   <li>{@link #TEST_ISSUE_3_STAFF_ASSIGNMENT 问题3} — 人员分配（硬/软约束、通岗补缺、固定班放松链等）。</li>
 * </ul>
 *
 * <p>说明：线上若仅打印 ERROR，本类统一用 {@link org.slf4j.Logger#error} 输出，便于验收/测试穿透；体量仍大时请用 traceId/排班单次开关过滤。
 */
public final class SchedulingForTestCheckLog {

    /** 测试检索标签（与现有 {@link AutoSchedulePipelineLog#MARKER} 区分开）。 */
    public static final String MARKER = "[for_test_check]";

    /**
     * 测试反馈「问题1」：相似历史日期筛选不可观测 — 日志值 {@value}（检索：{@code testIssue=1}）。
     */
    public static final String TEST_ISSUE_1_SIMILAR_HISTORICAL_DATES = "1";

    /**
     * 测试反馈「问题2」：半小时岗位需求矩阵生成不可观测 — 日志值 {@value}（检索：{@code testIssue=2}）。
     */
    public static final String TEST_ISSUE_2_HALF_HOUR_DEMAND_MATRIX = "2";

    /**
     * 测试反馈「问题3」：人员分配决策链不可观测 — 日志值 {@value}（检索：{@code testIssue=3}）。
     */
    public static final String TEST_ISSUE_3_STAFF_ASSIGNMENT = "3";

    /** 单行内相似日列表等元素过多时的默认截断条数（避免单次日志爆表）。 */
    public static final int DEFAULT_DATE_CAP = 48;

    private SchedulingForTestCheckLog() {}

    /**
     * @param testIssue 对应测试问题编号，见 {@link #TEST_ISSUE_1_SIMILAR_HISTORICAL_DATES} 等常量。
     * @param subPhase  同一场景下的子节点/子阶段，便于串联一次排班流水线。
     */
    public static void info(Logger log, String testIssue, String subPhase, String detail) {
        if (log == null || !log.isErrorEnabled()) {
            return;
        }
        log.error("{} testIssue={} subPhase={} | {}", MARKER, testIssue, subPhase, detail);
    }

    /**
     * 将日期列表格式化为短字符串，超出 {@code cap} 条时追加 {@code …(+N)}。
     */
    public static String formatDatesBrief(List<LocalDate> dates, int cap) {
        if (dates == null || dates.isEmpty()) {
            return "[]";
        }
        int n = dates.size();
        int show = Math.min(cap, n);
        StringBuilder sb = new StringBuilder(n * 14);
        sb.append('[');
        for (int i = 0; i < show; i++) {
            if (i > 0) {
                sb.append(',');
            }
            sb.append(dates.get(i));
        }
        sb.append(']');
        if (n > cap) {
            sb.append("…(+").append(n - cap).append(')');
        }
        return sb.toString();
    }

    /** 单行化多行表格：便于采集端按行 ingest。 */
    public static String singleLineTsv(String tsvTable, int maxChars) {
        if (tsvTable == null || tsvTable.isEmpty()) {
            return "";
        }
        String ln = tsvTable.replace('\n', '¤').replace('\t', '`');
        if (maxChars > 0 && ln.length() > maxChars) {
            return ln.substring(0, maxChars) + "…(truncated_chars=" + maxChars + ')';
        }
        return ln;
    }
}
