import shutil
import subprocess
import sys
import tempfile
from pathlib import Path

from scienith_openapi_contract_tooling.openapi.load import load_openapi_spec
from scienith_openapi_contract_tooling.openapi.plantuml import PlantUmlOptions, openapi_schemas_to_plantuml
from scienith_openapi_contract_tooling.openapi.redoc import openapi_to_redoc_html
from scienith_openapi_contract_tooling.openapi.resolve import normalize_schema_refs, resolve_components_schemas


def _resolve_java_executable() -> str:
    def is_working(java_path: str) -> bool:
        try:
            return (
                subprocess.run(
                    [java_path, "-version"],
                    stdout=subprocess.DEVNULL,
                    stderr=subprocess.DEVNULL,
                    check=False,
                ).returncode
                == 0
            )
        except OSError:
            return False

    found = shutil.which("java")
    if found and is_working(found):
        return found

    if sys.platform == "darwin":
        candidates = [
            "/opt/homebrew/opt/openjdk/bin/java",
            "/usr/local/opt/openjdk/bin/java",
        ]
        for p in candidates:
            if Path(p).exists() and is_working(p):
                return p

    raise RuntimeError(
        "未找到 Java Runtime（无法执行 `java`）。"
        "如已通过 Homebrew 安装 openjdk，请把其 bin 目录加入 PATH，"
        "或直接安装/配置可用的 JRE/JDK。"
    )


def _render_plantuml(*, puml_path: Path, out_path: Path, plantuml_jar: Path) -> None:
    out_suffix = out_path.suffix.lower()
    if out_suffix not in {".png", ".svg"}:
        raise ValueError("仅支持输出 .png 或 .svg（或直接输出 .puml）。")

    java_exe = _resolve_java_executable()
    fmt = out_suffix.lstrip(".")
    tflag = f"-t{fmt}"
    subprocess.run(
        [java_exe, "-Djava.awt.headless=true", "-jar", str(plantuml_jar), tflag, str(puml_path)],
        check=True,
    )

    produced = puml_path.with_suffix(out_suffix)
    if not produced.exists():
        raise RuntimeError(f"PlantUML 未生成预期文件：{produced}")

    out_path.parent.mkdir(parents=True, exist_ok=True)
    if produced.resolve() != out_path.resolve():
        produced.replace(out_path)


def openapi_to_uml(
    *,
    root_path: str,
    out_path: str,
    plantuml_jar: str | None,
    bundle: bool,
    direction: str,
    redoc_out_path: str | None,
) -> None:
    root = Path(root_path)
    out = Path(out_path)

    out_suffix = out.suffix.lower()
    if out_suffix not in {".puml", ".png", ".svg"}:
        raise ValueError("`--out` 必须以 .puml/.png/.svg 结尾。")

    if out_suffix in {".png", ".svg"} and not plantuml_jar:
        raise ValueError("输出 png/svg 时必须提供 `--plantuml-jar`。")

    with tempfile.TemporaryDirectory(prefix="scienith_openapi_contract_tooling_") as td:
        tmp_dir = Path(td)
        puml = tmp_dir / "openapi.puml"

        spec = load_openapi_spec(root)
        if bundle:
            resolved = resolve_components_schemas(root_path=root)
            normalized_schemas = normalize_schema_refs(resolved=resolved, root_dir=root.parent)
            spec.setdefault("components", {})
            spec["components"]["schemas"] = normalized_schemas
        puml_text = openapi_schemas_to_plantuml(
            spec=spec,
            options=PlantUmlOptions(direction=direction),
        )
        puml.write_text(puml_text, encoding="utf-8")

        if out_suffix == ".puml":
            out.parent.mkdir(parents=True, exist_ok=True)
            puml.replace(out)
            return

        if redoc_out_path:
            openapi_to_redoc_html(
                root_path=root_path,
                out_path=redoc_out_path,
                bundle=bundle,
            )

        jar_path = Path(plantuml_jar) if plantuml_jar else None
        if jar_path is None:
            raise ValueError("缺少 `--plantuml-jar`。")

        _render_plantuml(puml_path=puml, out_path=out, plantuml_jar=jar_path)
