"""补采查询布局元数据：MySQL 分区定义和业务 ES 索引 settings，不执行数据查询。"""
import argparse
import base64
import json
import pathlib
import re
import subprocess
import sys
import urllib.parse

sys.dont_write_bytecode = True
from collect_metadata import read_yaml, request_json, save, stamp, safe_error


def main():
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("--workspace", type=pathlib.Path, required=True)
    parser.add_argument("--snapshot", type=pathlib.Path, required=True)
    parser.add_argument("--output", type=pathlib.Path, required=True)
    parser.add_argument("--java", required=True)
    parser.add_argument("--mysql-jar", required=True)
    args = parser.parse_args()
    root, output = args.workspace.resolve(), args.output.resolve()
    if output == root or root in output.parents:
        parser.error("输出必须是工作区外临时目录")
    output.mkdir(parents=True, exist_ok=True)
    config_root = root / "doc/数据库设计管理/nacos"
    sources = read_yaml(config_root / "datasource.yaml")["datasource"]
    manifest = json.loads((args.snapshot / "manifest.json").read_text(encoding="utf-8"))
    done = set()
    for key, entry in manifest["sources"].items():
        if entry["kind"] != "mysql" or entry["database"] in done:
            continue
        database = entry["database"]
        done.add(database)
        target = output / ("mysql-layout-" + database + ".json")
        if target.exists():
            result = json.loads(target.read_text(encoding="utf-8"))
        else:
            config = sources[key]
            parsed = urllib.parse.urlsplit(config["url"].replace("jdbc:mysql:", "http:", 1))
            jdbc = f"jdbc:mysql://{parsed.netloc}/{database}?useSSL=false&allowPublicKeyRetrieval=true&connectTimeout=5000&socketTimeout=25000&characterEncoding=UTF-8"
            payload = "\n".join(base64.b64encode(str(x).encode()).decode() for x in (jdbc, config["username"], config["password"], database)) + "\npartitions\n"
            try:
                proc = subprocess.run([args.java, "-cp", args.mysql_jar, str(pathlib.Path(__file__).with_name("MysqlMetadata.java"))],
                                      input=payload.encode(), stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=120)
                result = json.loads(proc.stdout.decode("utf-8")) if proc.returncode == 0 else {"status": "error", "error": "Java_process_failed"}
            except Exception as exc:
                result = {"status": "error", "error": safe_error(exc)}
            result.update(database=database, captured_at=stamp())
            save(target, result)
        print(f"mysql-layout {database}: {result['status']}, {len(result.get('partitions', []))} partition entries", flush=True)
    target = output / "es-query-settings.json"
    if target.exists():
        result = json.loads(target.read_text(encoding="utf-8"))
    else:
        original = json.loads((args.snapshot / "elasticsearch.json").read_text(encoding="utf-8"))
        indexes = sorted(name for name in original["mappings"] if name in ("base_device", "apk_push_history") or name.startswith("app_install_device"))
        config = read_yaml(config_root / "application-common.yaml")["easy-es"]
        base = f"{config.get('schema', 'http')}://{str(config['address']).split(',')[0]}"
        try:
            raw = request_json(base + "/" + urllib.parse.quote(",".join(indexes), safe=",_-") + "/_settings?flat_settings=true", config["username"], config["password"])
            # 不发布无关实例配置，仅保留对字段查询、排序及路由有意义的选项。
            data = {name: {k: v for k, v in item.get("settings", {}).items()
                           if re.match(r"index\.(number_of_shards|number_of_replicas|routing\.|sort\.|analysis\.)", k)}
                    for name, item in raw.items()}
            result = {"status": "ok", "settings": data, "requested_indexes": indexes, "captured_at": stamp()}
        except Exception as exc:
            result = {"status": "error", "error": safe_error(exc), "captured_at": stamp()}
        save(target, result)
    print(f"es-query-settings: {result['status']}", flush=True)


if __name__ == "__main__":
    main()
