include(Resources.id("mtrsteamloco:scripts/display_helper.js"));
importPackage(java.awt);
importPackage(java.awt.geom);
importPackage(java.io);
importPackage(java.net);
importPackage(java.util);

importPackage(java.lang);
importPackage(java.util.concurrent);

let selectedPlatformId = null;

let g;
let slotCfg = {
    "version": 1,
    "texSize": [400, 100],
    "slots": [{
        "name": "main",
        "texArea": [0, 0, 400, 100],
        "pos": [[[-1.5, 1, 0], [-1.5, 0, 0], [2.5, 0, 0], [2.5, 1, 0]]],
        "offsets": [[0.01, 0, 0]]
    }]
};
let dhBase = new DisplayHelper(slotCfg);
let activeLCDs = [];
let asyncPool = null;

function create(ctx, state, blockEntity) {
    state.dh = dhBase.create();
    state.font = Resources.readFont(Resources.id("mtrsteamloco:eyecandies/font/dotgothic.ttf"));
    state.rate = new RateLimit(0.2);
    state.hassyahyo = Resources.readBufferedImage(Resources.id("mtrsteamloco:eyecandies/hassyahyo/hassyahyo.png"));
    state.hassyahyo_alpha = Resources.readBufferedImage(Resources.id("mtrsteamloco:eyecandies/hassyahyo/hassyahyo_alpha.png"));

    activeLCDs.push({ ctx: ctx, state: state, blockEntity: blockEntity });

    if (Resources.ANTE_FLAG && asyncPool === null) {
        asyncPool = Executors.newScheduledThreadPool(1);
        asyncPool.scheduleAtFixedRate(new java.lang.Runnable({
            run: () => {
                for (let i = 0; i < activeLCDs.length; i++) {
                    let entry = activeLCDs[i];
                    if (!entry.state.dh || entry.state.dh.closed) continue;

                    try {
                        tick(entry.ctx, entry.state, entry.blockEntity);
                        entry.ctx.drawCalls.put(
                            i,
                            new ClusterDrawCall(entry.state.dh.model, new Matrix4f())
                        );
                    } catch (e) {
                        print("描画中に例外が発生しました: " + e);
                    }
                }
            }
        }), 0, 1000 / 2, TimeUnit.MILLISECONDS);
        // --- 遅延情報の定期更新スケジューラ ---
        asyncPool.scheduleAtFixedRate(new java.lang.Runnable({
            run: function () {
                fetchDelaysFromURL(function (json) {
                    let delayMsgs = generateDelayMessages(json);
                    for (let i = 0; i < activeLCDs.length; i++) {
                        activeLCDs[i].state.delayMessages = delayMsgs;
                    }
                });
            }
        }), 0, 30, TimeUnit.SECONDS);  // 30秒間隔で更新
    }
}

function dispose(ctx, state, blockEntity) {
    for (let i = activeLCDs.length - 1; i >= 0; i--) {
        if (activeLCDs[i].blockEntity.equals(blockEntity)) {
            activeLCDs.splice(i, 1);
            break;
        }
    }

    // もし全てのLCDが撤去されて配列が空になったら、ThreadPoolをシャットダウン
    if (activeLCDs.length === 0 && asyncPool !== null) {
        asyncPool.shutdown();
        asyncPool = null;
    }
    state.dh.close();
}

function use(ctx, state, blockEntity, player) {
    let thisPos = blockEntity.getWorldPosVector3f();
    let station = MinecraftClient.getStationAt(thisPos);
    let platformMap = station
        ? MTRClientData.DATA_CACHE.requestStationIdToPlatforms(station.id)
        : new java.util.HashMap();

    let platformIds = Array.from(platformMap.keySet());

    let idLong;
    let id;

    let configValues = {};
    for (let i = 0; i < platformIds.length; i++) {
        idLong = platformIds[i];
        id = idLong.longValue();
        let key = "platform_" + id;

        let savedValue = blockEntity.getCustomConfig(key);
        //print("savedValue:" + key + " = " + savedValue);
        let parsedValue = String(savedValue).toLowerCase() === "true";

        configValues[key] = parsedValue;
        //print("読み込み:" + key + " = " + parsedValue);
    }

    blockEntity.registerCustomConfig({
        getKeys: function () {
            return Object.keys(configValues);
        },
        respond: function (key) {
            return configValues[key] ? "true" : "false";
        }
    });

    let builder = IScreen.ClothConfig2.createConfigBuilder();
    builder.setTitle(ComponentUtil.literal("ホーム選択"));
    let category = builder.getOrCreateCategory(ComponentUtil.literal("プラットフォーム"));
    let entryBuilder = builder.entryBuilder();

    for (let i = 0; i < platformIds.length; i++) {
        idLong = platformIds[i];
        id = idLong.longValue();
        let platform = platformMap.get(idLong);
        let name = platform.name;
        let key = "platform_" + id;

        let initialValue = configValues[key];

        let toggleEntry = entryBuilder
            .startBooleanToggle(ComponentUtil.literal(name), initialValue)
            .setDefaultValue(initialValue)
            .setSaveConsumer(function (value) {
                configValues[key] = value;
            });

        category.addEntry(toggleEntry.build());
    }

    builder.setSavingRunnable(function () {
        //print("保存処理を実行");
        for (let key in configValues) {
            let valueStr = configValues[key] ? "true" : "false";
            blockEntity.putCustomConfig(key, valueStr);
        }

        blockEntity.registerCustomConfig({
            getKeys: function () {
                return Object.keys(configValues);
            },
            respond: function (key) {
                return configValues[key] ? "true" : "false";
            }
        });

        //print("再登録完了");
    });


    MinecraftClient.setScreen(builder.build());
}

function formatMinutesToHHMM(totalMinutes) {
    const hour = Math.floor(totalMinutes / 60);
    const minute = totalMinutes % 60;
    const hh = (hour < 10 ? "0" + hour : "" + hour);
    const mm = (minute < 10 ? "0" + minute : "" + minute);
    return hh + ":" + mm;
}

function getRouteById(routeId) {
    const routesSet = MTRClientData.ROUTES;
    const routesArray = routesSet.toArray(); // Javaの配列になる
    for (let i = 0; i < routesArray.length; i++) {
        if (routesArray[i].id === routeId) {
            return routesArray[i];
        }
    }
    return null;
}

function getStationByPlatformId(platformId) {
    let stations = MTRClientData.STATIONS.iterator();
    while (stations.hasNext()) {
        let station = stations.next();
        let platforms = MTRClientData.DATA_CACHE.requestStationIdToPlatforms(station.id);
        if (!platforms) continue;
        let keys = platforms.keySet().iterator();
        while (keys.hasNext()) {
            let pid = keys.next();
            if (pid.longValue() === platformId) {
                return station;
            }
        }
    }
    return null;
}

function assyukuDraw(g, text, textSize, drawPos, width, font, textColor, xOffset) {
    let nextStaScale = 1.0;
    // 文字の幅を測定
    if (g.getFontMetrics(font.deriveFont(Font.PLAIN, textSize)).stringWidth(text) > width) {
        nextStaScale = (width) / g.getFontMetrics(font.deriveFont(Font.PLAIN, textSize)).stringWidth(text);
    }
    // 描画
    g.setFont(font.deriveFont(AffineTransform.getScaleInstance(nextStaScale, 1.0)).deriveFont(Font.PLAIN, textSize));
    g.setColor(textColor);
    g.drawString(text, xOffset, drawPos);
}

function fetchDelaysFromURL(callback) {
    try {
        let url = new URL("http://"); //system mapのURLに"/delays"を入れたものを書く,コンコース用も同様
        let con = url.openConnection();
        con.setRequestMethod("GET");
        con.setConnectTimeout(3000);
        con.setReadTimeout(5000);

        let reader = new BufferedReader(new InputStreamReader(con.getInputStream(), "UTF-8"));
        let line;
        let response = "";
        while ((line = reader.readLine()) !== null) {
            response += line;
        }
        reader.close();

        //print("取得したJSON文字列:\n" + response.substring(0, 500)); // 前半だけ表示
        let parsedJson = JSON.parse(String(response));
        callback(parsedJson);
    } catch (e) {
        print("遅延情報の取得エラー: " + e);
    }
}

function generateDelayMessages(json) {
    // 二重配列 ["[ [...], [...], ... ]"] に対処
    let entries = [];
    for (let i = 0; i < json.length; i++) {
        let item = json[i];
        if (item instanceof Array) {
            entries = entries.concat(item);
        } else {
            entries.push(item);
        }
    }

    // 遅延時間順で並べ替え
    entries.sort(function (a, b) {
        return b.delay - a.delay;
    });

    let msgs = [];
    for (let i = 0; i < entries.length && msgs.length < 3; i++) {
        let delay_entry = entries[i];

        // --- 安全チェック ---
        if (!delay_entry.delay || isNaN(delay_entry.delay)) continue;

        let delayM = Math.floor(delay_entry.delay / 1200);
        if (delayM === 0) continue;

        let name = delay_entry.name || "不明路線";
        let delay_destination = "？";
        if (delay_entry.destination && typeof delay_entry.destination === "string") {
            delay_destination = TextUtil.getCjkParts(delay_entry.destination.split("|")[0]);
        }

        let lineName = TextUtil.getCjkParts(name.replace(/\[.*?\]/g, "").trim());
        let message = "【" + lineName + " 遅延】" + lineName + "は、" + delay_destination + "行きに約" + delayM + "分の遅れが出ています。";

        msgs.push(message);
    }

    if (msgs.length === 0) {
        msgs.push("現在、各路線は平常運行です。");
    }

    return msgs;
}

function tick(ctx, state, blockEntity) {
    // print("tick() called!");
    if (!state.dh || state.dh.closed) {
        // print("DisplayHelper が閉じられています");
        return;
    }

    g = state.dh.graphicsFor("main");
    g.drawImage(state.hassyahyo, 0, 0, 400, 100, null);

    // プラットフォーム選択
    let selectedPlatformIds = [];
    let thisPos = blockEntity.getWorldPosVector3f();
    let station = MinecraftClient.getStationAt(thisPos);
    let platformMap = station
        ? MTRClientData.DATA_CACHE.requestStationIdToPlatforms(station.id)
        : new java.util.HashMap();
    let platformIds = Array.from(platformMap.keySet());
    for (let i = 0; i < platformIds.length; i++) {
        let idLong = platformIds[i];
        let id = idLong.longValue();
        let key = "platform_" + id;
        if (String(blockEntity.getCustomConfig(key)).toLowerCase() === "true") {
            selectedPlatformIds.push(idLong);
        }
    }

    // allTrains: 停車列車＋通過列車
    let allTrains = [];

    // --- 停車列車（あなたの描画ロジックを一切省略せずそのまま） ---
    for (let i = 0; i < selectedPlatformIds.length; i++) {
        let platformId = selectedPlatformIds[i];
        let schedules = MTRClientData.SCHEDULES_FOR_PLATFORM.get(platformId);
        if (!schedules) continue;

        let scheduleList = Array.from(schedules);
        scheduleList.sort(function (a, b) {
            return a.arrivalMillis - b.arrivalMillis;
        });

        for (let j = 0; j < scheduleList.length; j++) {
            let schedule = scheduleList[j];
            let platform = platformMap.get(platformId);
            let dwellTime = platform.dwellTime;
            let departureTimeMillis = schedule.arrivalMillis + dwellTime * 500;
            if (departureTimeMillis < Date.now() - 1000 * 60 * 60 * 24) {
                departureTimeMillis = Date.now() + departureTimeMillis;
            }
            allTrains.push({
                type: "停車",
                departureTimeMillis: departureTimeMillis,
                routeId: schedule.routeId,
                platformId: platformId,
                schedule: schedule // 既存描画ロジック用に渡す
            });
        }
    }

    // --- 通過列車 ---
    if (station) {
        let trains = MTRClientData.TRAINS;
        let iter = trains.iterator();
        //print("電車の数" + trains.size());
        while (iter.hasNext()) {
            let train = iter.next();
            //print("列車ID: " + train.id + " ループ開始");
            let path = train.path;
            if (!path) continue;

            let passedStationIds = new java.util.HashSet();
            for (let j = 0; j < path.size(); j++) {
                let pos = path.get(j).startingPos;
                let vec = new Vector3f(pos);
                let st = MinecraftClient.getStationAt(vec);
                if (st) passedStationIds.add(new java.lang.Long(st.id));
            }
            //print("passedStationIds: " + Array.from(passedStationIds).join(", "));

            let route = train.getThisRoute();
            if (!route) continue;

            let stopStationIds = new java.util.HashSet();
            for (let j = 0; j < route.platformIds.size(); j++) {
                let platId = route.platformIds.get(j).platformId;
                let st = getStationByPlatformId(platId);
                if (st) stopStationIds.add(new java.lang.Long(st.id));
            }

            // print("stopStationIds: " + Array.from(stopStationIds).join(", "));
            // print("現在駅ID: " + station.id);

            // // ログ出力：通過判定前
            // print("---- 通過判定チェック ----");
            // print("列車ID: " + train.id);
            // print("ルートID: " + route.id);
            // print("ルート名: " + route.name);
            // print("現在駅ID: " + station.id);
            // print("現在駅名: " + station.name);
            // print("通過駅に含まれる？: " + passedStationIds.contains(station.id));
            // print("停車駅に含まれる？: " + stopStationIds.contains(station.id));

            if (passedStationIds.contains(station.id) && !stopStationIds.contains(station.id)) {
                let estimatedPassTime = Date.now() + 1000;

                // ログ出力：通過列車として追加
                // print("→ 通過列車として追加されました");
                // print("通過予測時刻: " + estimatedPassTime);

                allTrains.push({
                    type: "通過",
                    departureTimeMillis: estimatedPassTime,
                    routeId: route.id,
                    platformId: -1,
                    schedule: null
                });
            }
        }
    }

    // --- 発車時刻順に統合ソート ---
    allTrains.sort((a, b) => a.departureTimeMillis - b.departureTimeMillis);

    // --- 描画処理（最大5件、あなたの停車列車描画ロジックをそのまま） ---
    let y = 30;
    const lineHeight = 60;

    let earliestTrain = null;

    for (let i = 0; i < allTrains.length; i++) {
        let t = allTrains[i];
    }
    for (let i = 0; i < allTrains.length && i < 5; i++) {
        let entry = allTrains[i];
        if (!earliestTrain || entry.departureTimeMillis < earliestTrain.departureTimeMillis) {
            earliestTrain = entry;
        }
        let route = getRouteById(entry.routeId);
        if (!route) continue;

        let routeType = route.lightRailRouteNumber.toString();
        let routeTypeJpn = TextUtil.getCjkParts(routeType).toString().trim();

        let Dest;
        let customDest = null;
        try {
            customDest = route.getDestination(route.platformIds.size() - 1);
        } catch (e) {
            customDest = null;
        }
        if (customDest) {
            Dest = customDest;
        } else {
            let LastPlatLong = new java.lang.Long(route.getLastPlatformId());
            Dest = "？";
            let stationIter = MTRClientData.STATIONS.iterator();
            let seenStationIds = new java.util.HashSet();
            while (stationIter.hasNext()) {
                let st = stationIter.next();
                if (seenStationIds.contains(st.id)) continue;
                seenStationIds.add(st.id);
                let platformsMap = MTRClientData.DATA_CACHE.requestStationIdToPlatforms(st.id);
                if (platformsMap) {
                    let keyIter = platformsMap.keySet().iterator();
                    while (keyIter.hasNext()) {
                        let platLong = keyIter.next();
                        if (platLong.equals(LastPlatLong)) {
                            Dest = st.name;
                            break;
                        }
                    }
                }
                if (Dest !== "？") break;
            }
        }

        if (!earliestTrain || entry.departureTimeMillis < earliestTrain.departureTimeMillis) {
            earliestTrain = entry;
        }

        let departureDate = new Date(entry.departureTimeMillis);
        let hh = departureDate.getHours();
        let mm = departureDate.getMinutes();
        let timeStr = (hh < 10 ? "0" + hh : hh) + ":" + (mm < 10 ? "0" + mm : mm);

        g.setFont(state.font.deriveFont(Font.PLAIN, 25));
        g.setColor(entry.type === "通過" ? Color.red : Color.white);
        g.drawString(timeStr, 80, y);

        // ラベル
        if (entry.type === "通過") {
            g.setColor(Color.red);
            g.drawString("通過", 240, y);
        } else {
            g.setColor(y === 30 ? Color.orange : Color.white);
            g.drawString(y === 30 ? "先発" : "次発", 5, y);
        }

        // --- あなたの日本語/英語切替・色分け・略称処理を完全再現 ---
        if (Date.now() % 20000 < 10000) {
            if (routeTypeJpn == "普通") {
                g.setColor(Color.lightGray);
                g.fillRect(150, y - 25, g.getFontMetrics(state.font.deriveFont(Font.PLAIN, 25)).stringWidth(TextUtil.getCjkParts(routeType)), 30);
                g.setColor(Color.white);
                g.drawString(TextUtil.getCjkParts(routeType), 150, y);
            } else if (routeTypeJpn == "快速") {
                g.setColor(Color.red);
                g.fillRect(150, y - 25, g.getFontMetrics(state.font.deriveFont(Font.PLAIN, 25)).stringWidth(TextUtil.getCjkParts(routeType)), 30);
                g.setColor(Color.white);
                g.drawString(TextUtil.getCjkParts(routeType), 150, y);
            } else if (routeTypeJpn == "区間快速") {
                g.setColor(Color.blue);
                g.fillRect(150, y - 25, g.getFontMetrics(state.font.deriveFont(Font.PLAIN, 25)).stringWidth("区快"), 30);
                g.setColor(Color.white);
                g.drawString("区快", 150, y);
            } else if (routeTypeJpn == "通勤快速") {
                g.setColor(Color.orange);
                g.fillRect(150, y - 25, g.getFontMetrics(state.font.deriveFont(Font.PLAIN, 25)).stringWidth("通快"), 30);
                g.setColor(Color.white);
                g.drawString("通快", 150, y);
            } else if (routeTypeJpn == "新快速") {
                g.setColor(Color.green);
                g.fillRect(150, y - 25, g.getFontMetrics(state.font.deriveFont(Font.PLAIN, 25)).stringWidth("新快"), 30);
                g.setColor(Color.white);
                g.drawString("新快", 150, y);
            } else if (routeTypeJpn == "各駅停車") {
                g.setColor(Color.cyan);
                g.fillRect(150, y - 25, g.getFontMetrics(state.font.deriveFont(Font.PLAIN, 25)).stringWidth("各停"), 30);
                g.setColor(Color.white);
                g.drawString("各停", 150, y);
            } else if (routeTypeJpn == "準急") {
                g.setColor(Color.green);
                g.fillRect(150, y - 25, g.getFontMetrics(state.font.deriveFont(Font.PLAIN, 25)).stringWidth(TextUtil.getCjkParts(routeType)), 30);
                g.setColor(Color.white);
                g.drawString(TextUtil.getCjkParts(routeType), 150, y);
            } else if (routeTypeJpn == "急行") {
                g.setColor(Color.red);
                g.fillRect(150, y - 25, g.getFontMetrics(state.font.deriveFont(Font.PLAIN, 25)).stringWidth(TextUtil.getCjkParts(routeType)), 30);
                g.setColor(Color.white);
                g.drawString(TextUtil.getCjkParts(routeType), 150, y);
            } else if (routeTypeJpn == "快速急行") {
                g.setColor(new Color(0.537, 0.0, 1.0));
                g.fillRect(150, y - 25, g.getFontMetrics(state.font.deriveFont(Font.PLAIN, 25)).stringWidth("快急"), 30);
                g.setColor(Color.white);
                g.drawString("快急", 150, y);
            } else {
                g.setColor(Color.white);
                g.drawString(TextUtil.getCjkParts(routeType), 150, y);
            }
            assyukuDraw(g, TextUtil.getCjkParts(Dest), 25, y, 150, state.font, Color.white, 240);
        } else {
            if (routeTypeJpn == "普通") {
                g.setColor(Color.lightGray);
                g.fillRect(150, y - 25, g.getFontMetrics(state.font.deriveFont(Font.PLAIN, 25)).stringWidth(TextUtil.getNonCjkParts(routeType)), 30);
                g.setColor(Color.white);
                g.drawString(TextUtil.getNonCjkParts(routeType), 150, y);
            } else if (routeTypeJpn == "快速") {
                g.setColor(Color.red);
                g.fillRect(150, y - 25, g.getFontMetrics(state.font.deriveFont(Font.PLAIN, 25)).stringWidth(TextUtil.getNonCjkParts(routeType)), 30);
                g.setColor(Color.white);
                g.drawString(TextUtil.getNonCjkParts(routeType), 150, y);
            } else if (routeTypeJpn == "区間快速") {
                g.setColor(Color.blue);
                g.fillRect(150, y - 25, g.getFontMetrics(state.font.deriveFont(Font.PLAIN, 25)).stringWidth("区快"), 30);
                g.setFont(state.font.deriveFont(Font.PLAIN, 10));
                g.setColor(Color.white);
                g.drawString("Semi", 160, y - 15);
                g.drawString("Rapid", 160, y);
            } else if (routeTypeJpn == "通勤快速") {
                g.setColor(Color.orange);
                g.fillRect(150, y - 25, g.getFontMetrics(state.font.deriveFont(Font.PLAIN, 25)).stringWidth("通快"), 30);
                g.setFont(state.font.deriveFont(Font.PLAIN, 10));
                g.setColor(Color.white);
                g.drawString("Com.", 160, y - 15);
                g.drawString("Rapid", 160, y);
            } else if (routeTypeJpn == "新快速") {
                g.setColor(Color.green);
                g.fillRect(150, y - 25, g.getFontMetrics(state.font.deriveFont(Font.PLAIN, 25)).stringWidth("新快"), 30);
                g.setFont(state.font.deriveFont(Font.PLAIN, 10));
                g.setColor(Color.white);
                g.drawString("New", 160, y - 15);
                g.drawString("Rapid", 160, y);
            } else if (routeTypeJpn == "各駅停車") {
                g.setColor(Color.cyan);
                g.fillRect(150, y - 25, g.getFontMetrics(state.font.deriveFont(Font.PLAIN, 25)).stringWidth("各停"), 30);
                g.setColor(Color.white);
                g.drawString(TextUtil.getNonCjkParts(routeType), 150, y);
            } else if (routeTypeJpn == "準急") {
                g.setColor(Color.green);
                g.fillRect(150, y - 25, g.getFontMetrics(state.font.deriveFont(Font.PLAIN, 25)).stringWidth("準急"), 30);
                g.setFont(state.font.deriveFont(Font.PLAIN, 10));
                g.setColor(Color.white);
                g.drawString("Semi", 160, y - 15);
                g.drawString("Exp.", 160, y);
            } else if (routeTypeJpn == "急行") {
                g.setColor(Color.red);
                g.fillRect(150, y - 25, g.getFontMetrics(state.font.deriveFont(Font.PLAIN, 25)).stringWidth(TextUtil.getNonCjkParts(routeType)), 30);
                g.setColor(Color.white);
                g.drawString("Exp.", 150, y);
            } else if (routeTypeJpn == "快速急行") {
                g.setColor(new Color(0.537, 0.0, 1.0));
                g.fillRect(150, y - 25, g.getFontMetrics(state.font.deriveFont(Font.PLAIN, 25)).stringWidth("快急"), 30);
                g.setFont(state.font.deriveFont(Font.PLAIN, 10));
                g.setColor(Color.white);
                g.drawString("Rapid", 160, y - 15);
                g.drawString("Exp.", 160, y);
            } else {
                g.setColor(Color.white);
                g.drawString(TextUtil.getNonCjkParts(routeType), 150, y);
            }
            if (TextUtil.getNonCjkParts(Dest).includes("-")) {
                assyukuDraw(g, TextUtil.getNonCjkParts(Dest).split("-")[0] + "-", 15, y - 15, 150, state.font, Color.white, 240);
                assyukuDraw(g, TextUtil.getNonCjkParts(Dest).split("-")[1], 15, y, 150, state.font, Color.white, 240 + g.getFontMetrics(state.font.deriveFont(Font.PLAIN, 15)).stringWidth(TextUtil.getNonCjkParts(Dest).split("-")[0]));
            } else {
                assyukuDraw(g, TextUtil.getNonCjkParts(Dest), 25, y, 150, state.font, Color.white, 240);
            }
        }

        y += lineHeight;
        if (y > 90) break;
    }
    for (let i = 0; i < allTrains.length; i++) {
        let t = allTrains[i];
    }

    let approachTime = earliestTrain.schedule
        ? earliestTrain.schedule.arrivalMillis
        : earliestTrain.departureTimeMillis; // 通過列車は departureTimeMillis を

    let now = Date.now();
    let timeDiff = approachTime - now;

    // ログ出力
    // print("=== 接近判定ログ ===");
    // print("現在時刻: " + now);
    // print("列車種別: " + earliestTrain.type);
    // print("接近基準時刻（到着または通過）: " + approachTime);
    // print("残りミリ秒: " + timeDiff);
    // print("残り秒: " + Math.floor(timeDiff / 1000));
    // --- 接近表示（停車・通過で切替） ---
    if (
        (approachTime - Date.now()) > 0 &&
        (approachTime - Date.now()) <= 30000
    ) {
        //print("→ 接近表示を出します");
        g.setFont(state.font.deriveFont(Font.PLAIN, 25));
        if (earliestTrain.type === "通過") {
            if (Date.now() % 2000 < 1000) {
                g.setColor(Color.orange);
                g.drawString("電車が通過します/Train approach", 5, 60);
            } else {
                g.setColor(Color.yellow);
                g.drawString("ホームドアから離れてください", 5, 60);
            }
        } else {
            if (Date.now() % 2000 < 1000) {
                g.setColor(Color.orange);
                g.drawString("電車が参ります/Train approach", 5, 60);
            } else {
                g.setColor(Color.yellow);
                g.drawString("ホームドアから離れてお待ち下さい", 5, 60);
            }
        }
    } else {
        //print("→ 接近表示を出しません（対象外）");
        // --- スクロール表示（停車駅・通過駅） ---
        let callingSta = [];
        let passingSta = [];
        if (earliestTrain.routeId !== null) {
            let route = getRouteById(earliestTrain.routeId);
            if (route) {
                for (let j = route.getPlatformIdIndex(selectedPlatformIds[0]) + 1; j < route.platformIds.size(); j++) {
                    let platId = route.platformIds.get(j).platformId;
                    let st = getStationByPlatformId(platId);
                    if (st) {
                        if (earliestTrain.type === "通過") {
                            passingSta.push(TextUtil.getCjkParts(st.name));
                        } else {
                            callingSta.push(TextUtil.getCjkParts(st.name));
                        }
                    }
                }
            }
        }
        let callingStaMsg = callingSta.length > 0 ? "停車駅:" + callingSta.join("、") : "";

        let baseMsgs = [
            "勝炭鉄道をご利用下さいまして、ありがとうございます。",
            "歩きスマホは大変危険です。おやめ下さいますよう、ご協力お願いします。",
            callingStaMsg
        ];

        let delayMsgs = (state.delayMessages && state.delayMessages.length > 0)
            ? state.delayMessages
            : [];

        let msgs = [];

        // 展開のロジック：交互に挿入
        var max = Math.max(delayMsgs.length, baseMsgs.length);
        for (var i = 0; i < max; i++) {
            if (i < delayMsgs.length) msgs.push(delayMsgs[i]);
            if (i < baseMsgs.length) msgs.push(baseMsgs[i]);
        }

        if (state.messageIndex === undefined) state.messageIndex = 0;
        if (state.scrollOffset === undefined) state.scrollOffset = 300;

        let curMsg = msgs[state.messageIndex % msgs.length];
        let sf = state.font.deriveFont(Font.PLAIN, 25);
        g.setFont(sf);
        g.setColor(Color.yellow);
        g.drawString(curMsg, state.scrollOffset, 60);
        let w = g.getFontMetrics(sf).stringWidth(curMsg);

        state.scrollOffset -= 20;
        if (state.scrollOffset < -w) {
            state.scrollOffset = 300;
            state.messageIndex++;
        }
    }

    g.drawImage(state.hassyahyo_alpha, 0, 0, 400, 100, null);
    state.dh.upload();
}

function render(ctx, state, blockEntity) {
    if (!Resources.ANTE_FLAG) {
        tick(ctx, state, blockEntity);
        ctx.drawModel(state.dh.model, null);
    }
}
