package com.aps.macroplanner.output;

import java.util.List;

/**
 * 轻量级 JSON 字符串构建器 — 无外部依赖, 兼容 Java 8。
 *
 * <p>提供以下方法:</p>
 * <ul>
 *   <li>{@link #obj()} / {@link #endObj()} — 开始/结束 JSON 对象</li>
 *   <li>{@link #arr()} / {@link #endArr()} — 开始/结束 JSON 数组</li>
 *   <li>{@link #key(String)} — 写入键</li>
 *   <li>{@link #val(String)} / {@link #val(double)} / {@link #val(int)} / {@link #val(boolean)} / {@link #valNull()} — 写入值</li>
 * </ul>
 *
 * <h3>使用示例</h3>
 * <pre>{@code
 *   JsonBuilder jb = new JsonBuilder();
 *   jb.obj()
 *     .key("name").val("Alice")
 *     .key("age").val(30)
 *     .key("scores").arr()
 *       .val(95.5).val(88.0)
 *     .endArr()
 *   .endObj();
 *   String json = jb.toString();
 * }</pre>
 */
public class JsonBuilder {

    private final StringBuilder sb = new StringBuilder();
    private boolean firstInContainer = true;

    /** 开始 JSON 对象 { */
    public JsonBuilder obj() {
        sb.append("{");
        firstInContainer = true;
        return this;
    }

    /** 结束 JSON 对象 } */
    public JsonBuilder endObj() {
        sb.append("}");
        return this;
    }

    /** 开始 JSON 数组 [ */
    public JsonBuilder arr() {
        sb.append("[");
        firstInContainer = true;
        return this;
    }

    /** 结束 JSON 数组 ] */
    public JsonBuilder endArr() {
        sb.append("]");
        return this;
    }

    /** 写入键 "key": */
    public JsonBuilder key(String key) {
        if (!firstInContainer) sb.append(",");
        sb.append("\"").append(escape(key)).append("\":");
        firstInContainer = true;
        return this;
    }

    /** 写入字符串值 */
    public JsonBuilder val(String value) {
        comma();
        if (value == null) {
            sb.append("null");
        } else {
            sb.append("\"").append(escape(value)).append("\"");
        }
        return this;
    }

    /** 写入 double 值 (有限小数的 JSON 数字) */
    public JsonBuilder val(double value) {
        comma();
        if (Double.isNaN(value) || Double.isInfinite(value)) {
            sb.append("null");
        } else if (Math.abs(value - Math.round(value)) < 1e-9) {
            sb.append((long) value);
        } else {
            sb.append(String.format("%.6f", value));
        }
        return this;
    }

    /** 写入 int 值 */
    public JsonBuilder val(int value) {
        comma();
        sb.append(value);
        return this;
    }

    /** 写入 long 值 */
    public JsonBuilder val(long value) {
        comma();
        sb.append(value);
        return this;
    }

    /** 写入 boolean 值 */
    public JsonBuilder val(boolean value) {
        comma();
        sb.append(value);
        return this;
    }

    /** 写入 null */
    public JsonBuilder valNull() {
        comma();
        sb.append("null");
        return this;
    }

    /**
     * 写入可选的 double 值 (null 时输出 null)。
     */
    public JsonBuilder valOpt(Double value) {
        if (value == null) {
            return valNull();
        }
        return val(value.doubleValue());
    }

    /**
     * 写入 JSON 对象列表 (每个元素调用 toJson 方法)。
     */
    public <T extends JsonSerializable> JsonBuilder valArray(List<T> items) {
        arr();
        for (int i = 0; i < items.size(); i++) {
            if (i > 0) sb.append(",");
            items.get(i).toJson(this);
        }
        endArr();
        return this;
    }

    /** 在值前插入逗号 (如果不是第一个) */
    private void comma() {
        if (!firstInContainer) sb.append(",");
        firstInContainer = false;
    }

    /** JSON 字符串转义 */
    private static String escape(String s) {
        StringBuilder out = new StringBuilder(s.length() + 8);
        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            switch (c) {
                case '"':  out.append("\\\""); break;
                case '\\': out.append("\\\\"); break;
                case '\b': out.append("\\b");  break;
                case '\f': out.append("\\f");  break;
                case '\n': out.append("\\n");  break;
                case '\r': out.append("\\r");  break;
                case '\t': out.append("\\t");  break;
                default:
                    if (c < 0x20) {
                        out.append(String.format("\\u%04x", (int) c));
                    } else {
                        out.append(c);
                    }
            }
        }
        return out.toString();
    }

    @Override
    public String toString() {
        return sb.toString();
    }

    // ==================== 序列化接口 ====================

    /**
     * 可序列化为 JSON 的对象接口。
     */
    public interface JsonSerializable {
        void toJson(JsonBuilder jb);
    }
}