import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 第8课第六节的完整示例：办件详情页并行查三个服务，单项超时或失败时降级，整页仍能返回。
 * 运行：java reference/DetailPageExample.java（Java 17 或 21）。
 * 预期：打印“申请人：张三 | 材料：暂不可用 | 审批记录：暂不可用”，耗时约 300ms（不是 300+200+600），最后一行“检查通过”。
 * 用 sleep 模拟远程调用：材料服务抛异常，审批服务比超时设定慢。
 */
public class DetailPageExample {

    // ① 自己的线程池：有界队列、线程有名字、满了由调用者自己执行（第5、7课）
    static final ThreadPoolExecutor QUERY_POOL = new ThreadPoolExecutor(
            8, 8, 60, TimeUnit.SECONDS,
            new ArrayBlockingQueue<>(200),
            namedThreads("detail-query-"),
            new ThreadPoolExecutor.CallerRunsPolicy());

    public static void main(String[] args) throws Exception {
        long start = System.nanoTime();
        String page = loadDetail("A-001");
        long ms = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);
        System.out.println(page + "（耗时 " + ms + "ms）");

        QUERY_POOL.shutdown();
        if (!QUERY_POOL.awaitTermination(5, TimeUnit.SECONDS)) throw new AssertionError("线程池没有按时关闭");
        if (!page.equals("申请人：张三 | 材料：暂不可用 | 审批记录：暂不可用")) throw new AssertionError("结果不符：" + page);
        if (ms < 280 || ms > 550) throw new AssertionError("耗时应约等于 300ms 的最长有效等待，实际 " + ms);
        System.out.println("检查通过");
    }

    static String loadDetail(String applyNo) {
        // ② 三个互不依赖的查询同时发出；每一项各自兜底，一项失败不拖垮整页
        CompletableFuture<String> applicant = CompletableFuture
                .supplyAsync(() -> queryApplicant(applyNo), QUERY_POOL)
                .completeOnTimeout("暂不可用", 500, TimeUnit.MILLISECONDS)   // ③ 超时给默认值
                .exceptionally(ex -> "暂不可用");                           // ④ 出错给默认值

        CompletableFuture<String> materials = CompletableFuture
                .supplyAsync(() -> queryMaterials(applyNo), QUERY_POOL)
                .completeOnTimeout("暂不可用", 500, TimeUnit.MILLISECONDS)
                .exceptionally(ex -> "暂不可用");

        CompletableFuture<String> records = CompletableFuture
                .supplyAsync(() -> queryRecords(applyNo), QUERY_POOL)
                .completeOnTimeout("暂不可用", 300, TimeUnit.MILLISECONDS)
                .exceptionally(ex -> "暂不可用");

        // ⑤ 等三项都有结果（正常、默认值都算），再组装
        CompletableFuture.allOf(applicant, materials, records).join();
        return "申请人：" + applicant.join() + " | 材料：" + materials.join() + " | 审批记录：" + records.join();
    }

    static String queryApplicant(String applyNo) { sleep(300); return "张三"; }
    static String queryMaterials(String applyNo) { sleep(200); throw new IllegalStateException("材料服务不可用"); }
    static String queryRecords(String applyNo)   { sleep(600); return "审批2条"; }

    static void sleep(long ms) {
        try {
            Thread.sleep(ms);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new IllegalStateException(e);
        }
    }

    static java.util.concurrent.ThreadFactory namedThreads(String prefix) {
        AtomicInteger seq = new AtomicInteger();
        return r -> new Thread(r, prefix + seq.incrementAndGet());
    }
}
