include("train_js_util.js");
include("train_color_util.js");
importPackage(java.awt);
importPackage(java.awt.geom);

function parseLineName(lineStr) {
    return getCJKLineName(getMatching(lineStr, true)) + "|" + getNonCJKLineName(getMatching(lineStr, false));
}

function getCJKLineName(lineStr) {
    let pattern = /^(\d+|[\u4e00-\u9fa5]+)线$/; // 正则表达式
    var match = lineStr.match(pattern); // 匹配字符串

    if (match && match[1]) {
        return match[1]; // 返回提取的部分
    } else {
        if (lineStr.endsWith("号线")) {
            let numberPart = lineStr.replace("号线", "");
            return parseInt(numberPart);
        } else {
            return null;
        }
    }
}

function getNonCJKLineName(lineStr) {
    let pattern = /^Line\s+(\d+|[A-Za-z]+)$/; // 正则表达式
    var match = lineStr.match(pattern); // 匹配字符串

    if (match && match[1]) {
        return match[1]; // 返回提取的部分
    } else {
        match = lineStr.match(/([A-Za-z\s]+)\sLine/);
        if (match && match[1]) {
            return match[1];
        } else {
            return lineStr;
        }
    }
}

function isNumLine(lineStr) {
    return String(getCJKLineName(TextUtil.getCjkParts(lineStr))) == String(getNonCJKLineName(TextUtil.getNonCjkParts(lineStr))) ? true : false;
}

const STATUS_MAP = {
    NO_ROUTE: "no_route",
    WAITING: "waiting_for_departure",
    DEPARTING: "leaving_depot",
    RUNNING: "on_route",
    ARRIVED: "arrived",
    CHANGING: "changing_route",
    RETURNING: "returning_to_depot"
};

/**
 * 获取绘制线路详情
 * @param {*} state
 * @param {*} train
 * @returns
 */
function getDrawableRoute(state, train, ctx) {
    let platformInfos = train.getThisRoutePlatforms();
    if (platformInfos.length == 0) return { routeName: "未知|Unknown", routeColor: Color.YELLOW };
    let route = platformInfos[0].route;
    let drawRoute = { routeName: route.name, name: route.name, routeColor: new Color(route.color), color: new Color(route.color) };
    let objRoute = mtrRouteToObj(route);
    let fullRouteStations = findLongestMatchingRoute(route.name, objRoute.drawStations);
    // ctx.setDebugInfo("objRoute", objRoute);
    // ctx.setDebugInfo("fullRouteStations", JSON.stringify({ fullRouteStations }));
    let [beginIndex, endIndex] = findStationIndices(objRoute.drawStations, fullRouteStations);
    if (endIndex == -1) endIndex = fullRouteStations.length - 1;
    let finalIndex = train.getThisRoutePlatformsNextIndex() + beginIndex;
    let finalThisRouteStations = [];
    let finalFullRouteStations = [];
    for (let i = 0; i < fullRouteStations.length; i++) {
        let thisStation = fullRouteStations[i];
        let { stationName, transInfo: transInfo } = thisStation;
        let arrivalTime = 0;
        try {
            arrivalTime = i >= beginIndex && i <= endIndex ? Math.round((platformInfos[i - beginIndex].distance - train.railProgress()) / (80 / 3.6) / 60) + 1 : -1;
        } catch (e) {
            arrivalTime = 1;
        }
        if (i < beginIndex || i > endIndex) {
            finalFullRouteStations.push({ stationName, transInfo: transInfo, flag: 3, arrivalTime: -1 });
        } else if (i < finalIndex) {
            finalThisRouteStations.push({ stationName, transInfo: transInfo, flag: 2, arrivalTime });
            finalFullRouteStations.push({ stationName, transInfo: transInfo, flag: 2, arrivalTime });
        } else if (i == finalIndex) {
            finalThisRouteStations.push({ stationName, transInfo: transInfo, flag: 1, arrivalTime });
            finalFullRouteStations.push({ stationName, transInfo: transInfo, flag: 1, arrivalTime });
        } else if (i > finalIndex) {
            finalThisRouteStations.push({ stationName, transInfo: transInfo, flag: 0, arrivalTime });
            finalFullRouteStations.push({ stationName, transInfo: transInfo, flag: 0, arrivalTime });
        }
    }
    return {
        routeName: route.name,
        trainStatus: getTrainStatus(train),
        name: route.name,
        routeColor: new Color(route.color),
        color: new Color(route.color),
        finalFullRouteStations,
        finalThisRouteStations,
        fullRouteIndex: finalIndex,
        thisRouteIndex: train.getThisRoutePlatformsNextIndex(),
        beginIndex,
        endIndex,
        fullRouteThisIndex: finalIndex - beginIndex
    };
}

function getTrainStatus(train) {
    if (train.getAllPlatforms().size() == 0) return STATUS_MAP.NO_ROUTE;
    if (!train.isOnRoute()) return STATUS_MAP.WAITING;
    if (train.getAllPlatformsNextIndex() === train.getAllPlatforms().size()) return STATUS_MAP.RETURNING;
    if (onPlatformRail(train)) return STATUS_MAP.ARRIVED;
    return STATUS_MAP.RUNNING;
}

/**
 * 获取列车是否位于站台轨道上，且该站台轨道是列车下一个停靠的站台。
 * @param {Train} train 要获取的列车。
 * @return {Boolean}
 */
function onPlatformRail(train) {
    let path1 = train.path().get(train.getRailIndex(train.getRailProgress(0), false)); // 车头所在轨道
    let path2 = train.path().get(train.getRailIndex(train.getRailProgress(train.trainCars() - 1), true)); // 车尾所在轨道
    let nextPlatformId = train.getAllPlatforms().get(train.getAllPlatformsNextIndex()).platform.id;
    return (path1.dwellTime != 0 && path1.savedRailBaseId == nextPlatformId) || (path2.dwellTime != 0 && path2.savedRailBaseId == nextPlatformId);
}

function findLongestMatchingRoute(targetRouteName, inputDrawStations) {
    // 1. 获取线路名称的核心部分
    let baseRouteName = TextUtil.getNonExtraParts(targetRouteName);
    // setDebugInfo("target route name " + baseRouteName);

    // 2. 提取输入站点的名称序列
    let inputNames = inputDrawStations.map((station) => station.stationName);

    // 3. 查找所有匹配的线路
    let matchingRoutes = [];
    for (let route of MTRClientData.ROUTES) {
        // 检查线路名称是否匹配
        // setDebugInfo("This route name " + route.name);
        let routeBaseName = TextUtil.getNonExtraParts(route.name);
        // setDebugInfo("This route final name " + routeBaseName);
        if (routeBaseName != baseRouteName) continue;

        // 转换为drawStations格式
        let routeObj = mtrRouteToObj(route);
        let routeStations = routeObj.drawStations;
        let routeNames = routeStations.map((s) => s.stationName);

        // setDebugInfo("Checking " + JSON.stringify(routeObj));

        // 检查是否包含子序列（正序匹配）
        let startIndex = findSubsequenceIndex(routeNames, inputNames);
        if (startIndex !== -1) {
            matchingRoutes.push({
                route: routeObj,
                stations: routeStations,
                length: routeStations.length
            });
            continue;
        }

        // 检查反序匹配（如果输入是逆序）
        let reversedInputNames = inputNames.reverse();
        let reverseIndex = findSubsequenceIndex(routeNames, reversedInputNames);
        if (reverseIndex !== -1) {
            matchingRoutes.push({
                route: routeObj,
                stations: routeStations.reverse(),
                length: routeStations.length
            });
        }
    }

    // 4. 选择最长的匹配线路
    if (matchingRoutes.length === 0) return [];
    let longestRoute = matchingRoutes[0];
    for (let i = 1; i < matchingRoutes.length; i++) {
        if (matchingRoutes[i].length > longestRoute.length) {
            longestRoute = matchingRoutes[i];
        }
    }

    // 5. 返回完整站点列表
    return longestRoute.stations;
}

function findStationIndices(currentStations, fullRouteStations) {
    // 1. 提取站点名称序列
    let currentNames = [];
    let fullNames = [];
    for (let s of currentStations) currentNames.push(s.stationName);
    for (let s of fullRouteStations) fullNames.push(s.stationName);

    let begin = findStationName(currentNames[0], fullNames);
    let end = findStationName(currentNames[currentNames.length - 1], fullNames);

    if (begin != -1 && end != -1) {
        setDebugInfo(` found ${currentNames} in ${fullNames}`);
        if (begin < end) return [begin, end];
        else return [end, begin];
    }
    // 3. 未找到匹配
    setDebugInfo(`not found ${currentNames} in ${fullNames}`);
    return [0, fullRouteStations.length - 1];
}

function train_routeToMap(route) {
    let drawStations = [];
    for (let station of route.stationDetails) {
        let transferInfo = [];
        if (station.interchangeInfo) {
            for (interchange of station.interchangeInfo) {
                if (interchange.isConnectingStation) continue;
                if (getNonExtraParts(interchange.name) == getNonExtraParts(route.routeName)) continue;
                transferInfo.push({ routeName: interchange.name, routeColor: interchange.color });
            }
            drawStations.push({ stationName: station.stationName, transInfo: transferInfo });
        } else if (station.interchangeRoutes) {
            for (interchange of station.interchangeRoutes) {
                if (interchange.isConnectingStation) continue;
                if (getNonExtraParts(interchange.name) == getNonExtraParts(route.routeName)) {
                    // setDebugInfo(`${getNonExtraParts(interchange.name)} == ${getNonExtraParts(route.routeName)}`);
                    continue;
                }
                transferInfo.push({ routeName: interchange.name, routeColor: intToColor(interchange.color) });
            }
            drawStations.push({ stationName: station.stationName, transInfo: transferInfo });
        } else drawStations.push({ stationName: station.stationName, transInfo: [] });
    }
    return {
        routeName: route.routeName,
        routeColor: route.routeColor,
        destination: route.destination,
        circularState: route.circularState,
        depotName: route.depotName,
        stationDetails: route.stationDetails,
        drawStations
    };
}

function findStation(station, stationList) {
    for (let i = 0; i < stationList.length; i++) {
        let currentStation = stationList[i];
        if (currentStation.stationName == station.stationName) return i;
    }
    return -1;
}

function getPlatformById(id) {
    for (let route of MTRClientData.PLATFORMS) {
        if (String(new java.lang.Long(route.id)) === id) {
            return route;
        }
    }
    return null;
}

function getRouteByPlatform(plat) {
    return MTRClientData.DATA_CACHE.requestPlatformIdToRoutes(new java.lang.Long(plat.id));
}

function getRouteByPlatId(platId) {
    return MTRClientData.DATA_CACHE.requestPlatformIdToRoutes(new java.lang.Long(platId));
}

function getRouteWithCondition(con) {
    let routes = [];
    let routeList = MTRClientData.ROUTES;
    for (let c of con) {
        if (c.type == "platform" || c.type == "platformId") {
            let platform = c.val;
            for (let route of routeList) {
                // print(route.platformIds)
                for (let routePlatform of route.platformIds) {
                    // print(String(new java.lang.Long(routePlatform.platformId)))
                    if (new java.lang.Long(routePlatform.platformId) == new java.lang.Long(c.type == "platformId" ? c.val : platform.id)) {
                        routes.push(route);
                    }
                }
            }
        } else if (c.type == "name") {
            let targetName = c.name;
            for (let route of routeList) {
                // print(route.name)
                if (route.name == targetName) {
                    routes.push(route);
                }
            }
        }
        routeList = routes;
    }
    return routes;
}

function getRouteById(id) {
    for (let route of MTRClientData.ROUTES) {
        if (String(new java.lang.Long(route.id)) === String(new java.lang.Long(id))) {
            return route;
        }
    }
    return null;
}

/**
 * 获取某个站台所在的车站
 * @param {Platform} plat 站台
 * @returns Station
 */
function getStationByPlatform(plat) {
    var posCentral = new Vector3f(plat.getMidPos());
    return MinecraftClient.getStationAt(posCentral);
}

function getPlatformByStation(station) {
    let platforms = MTRClientData.DATA_CACHE.requestStationIdToPlatforms(new java.lang.Long(station.id));
    return Array.from(platforms.values());
}

function getDestinationByRouteId(id) {
    let route = getRouteById(String(id));
    // print(String(id), "  ", (route))
    if (route == null) return "?";
    let destinationRoutePlatform = route.platformIds[route.platformIds.size() - 1];
    let destinationPlatform = getPlatformById(String(new java.lang.Long(destinationRoutePlatform.platformId)));
    let station = getStationByPlatform(destinationPlatform);
    // print(destinationPlatform);
    // print(destinationPlatform.getMidPos());
    // print(station);
    return station.name;
}

function getDestinationByPlatform(plat) {
    if (!plat) return [];
    var destSet = new Set();
    getRouteWithCondition([{ type: "platform", val: plat }]).forEach((route) => {
        var platforms = route.platformIds;
        if (platforms.size() > 0) {
            var lastPlat = platforms.get(platforms.size() - 1);
            var station = getStationByPlatform(getPlatformById(String(new java.lang.Long(lastPlat.platformId))));
            station.name && destSet.add("" + station.name); // 显式转为JS字符串
        }
    });

    return Array.from(destSet);
}

function getDestinationByPlatId(id) {
    var plat = getPlatformById(String(id));
    return getDestinationByPlatform(plat);
}

function findStation(station, stationList) {
    // print(String(station.name))
    for (let i = 0; i < stationList.length; i++) {
        let currentStation = stationList[i];
        // print(String(currentStation.stationName));
        if (station.name === currentStation.stationName) return i;
    }
    return -1;
}

function findStationName(station, stationList) {
    // print(String(station.name))
    for (let i = 0; i < stationList.length; i++) {
        let currentStation = stationList[i];
        // print(String(currentStation.stationName));
        if (station === currentStation) return i;
    }
    return -1;
}

function getRoutePlatform(route) {
    // let stationDetails = [];
    let platformIds = Array.from(route.platformIds);
    let platformNames = [];
    for (let p of route.platformIds.toArray()) {
        platformNames.push(getStationByPlatform(getPlatformById(String(new java.lang.Long(p.platformId)))).name);
    }
    // setDebugInfo(`getting routeplat: ${platformIds}`);
    let firstPlat = new java.lang.Long(platformIds[0].platformId);
    let routeList = getRouteByPlatId(firstPlat);

    let findRoute = {};

    for (let route of routeList) {
        let objRoute = routeToObj(route);
        if (TextUtil.getNonExtraParts(objRoute.routeName) != TextUtil.getNonExtraParts(route.name)) continue;
        for (let plat of objRoute.drawStations) {
            let haveSame = false;
            for (let p of platformNames) {
                if (p != plat.stationName) {
                    continue;
                }
                haveSame = true;
                break;
            }
            if (!haveSame) break;
        }
        findRoute = objRoute;
    }
    // setDebugInfo(`obj route found ${JSON.stringify(findRoute)}`);
    return findRoute;
}

function mtrRouteToObj(route) {
    let routePlatform = getRoutePlatform(route);
    if (routePlatform) return routeToObj(routePlatform);
    else return {};
}

function routeToObj(route) {
    let drawStations = [];
    if (route.stationDetails == null) drawStations = [];
    else
        for (let station of route.stationDetails) {
            let transInfo = [];
            if (station.interchangeInfo) {
                for (interchange of station.interchangeInfo) {
                    if (interchange.isConnectingStation) continue;
                    if (TextUtil.getNonExtraParts(interchange.name) == TextUtil.getNonExtraParts(route.routeName)) continue;
                    transInfo.push({ routeName: interchange.name, routeColor: interchange.color });
                }
                drawStations.push({ stationName: station.stationName, transInfo: transInfo });
            } else if (station.interchangeRoutes) {
                let interchangeNames = [];
                for (interchange of station.interchangeRoutes) {
                    // if (interchange.isConnectingStation) continue;
                    if (getNonExtraParts(interchange.name) == getNonExtraParts(route.routeName)) {
                        setDebugInfo(`${getNonExtraParts(interchange.name)}  ${getNonExtraParts(route.routeName)}`);
                        continue;
                    }
                    if (interchangeNames.includes(interchange.name)) continue;
                    transInfo.push({ routeName: interchange.name, routeColor: intToColor(interchange.color) });
                    interchangeNames.push(interchange.name);
                }
                drawStations.push({ stationName: station.stationName, transInfo: transInfo });
            } else drawStations.push({ stationName: station.stationName, transInfo: [] });
        }
    return {
        routeName: route.routeName,
        routeColor: route.routeColor,
        destination: route.destination,
        circularState: route.circularState,
        depotName: route.depotName,
        stationDetails: route.stationDetails,
        drawStations
    };
}
