#!/usr/bin/env python3
"""Ollaya 0.7.2 の公式Mac用ファイルを指定した新規フォルダーへ取得する。

Python 3.10+ と macOS 標準の curl を使う。モデル取得・起動・常駐登録はしない。
約57 MBをGitHubからダウンロードする。公開時点のSHA-256を固定して検査する。
"""
import argparse
import hashlib
import platform
import subprocess
import tarfile
from pathlib import Path

VERSION = "0.7.2"
BASE = f"https://github.com/ollaya-dev/ollaya/releases/download/v{VERSION}/"
FILES = {
    "ollaya-darwin-arm64.tgz":
        "5515087bf1a97f0b7d839957c63496be8a023b37f759c3fe0f6a6137a1ca677e",
    "ollaya-darwin-arm64-mlx.tgz":
        "dbd2831442d65c064e695068dc010773d514b8edf92ee6beeea470cc294a1abb",
}


def extract_checked(path, destination):
    root = destination.resolve()
    with tarfile.open(path) as archive:
        for member in archive.getmembers():
            resolved = (root / member.name).resolve()
            if not resolved.is_relative_to(root):
                raise ValueError("展開先の外を指すファイルです")
            if not (member.isfile() or member.isdir() or member.issym() or member.islnk()):
                raise ValueError("想定外のファイル形式です")
            if member.issym() or member.islnk():
                base = resolved.parent if member.issym() else root
                if not (base / member.linkname).resolve().is_relative_to(root):
                    raise ValueError("展開先の外を指すリンクです")
        # ハッシュ値で固定した公式配布物だけを、上で検査した新規ディレクトリへ展開。
        if hasattr(tarfile, "data_filter"):
            archive.extractall(root, filter="data")
        else:
            archive.extractall(root)


def main():
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("--directory", type=Path, default=Path("ollaya-trial"))
    args = parser.parse_args()
    if platform.system() != "Darwin" or platform.machine() != "arm64":
        raise SystemExit("この準備スクリプトはApple silicon Mac専用です")
    if int(platform.mac_ver()[0].split(".")[0]) < 14:
        raise SystemExit("macOS 14以上が必要です")
    root = args.directory.resolve()
    root.mkdir(parents=True, exist_ok=False)
    runtime = root / "runtime"
    runtime.mkdir()
    for name, expected in FILES.items():
        path = root / name
        subprocess.run(["curl", "-fLsS", "--max-time", "180", "--max-filesize", "60000000",
                        "-o", str(path), BASE + name], check=True)
        actual = hashlib.sha256(path.read_bytes()).hexdigest()
        if actual != expected:
            raise ValueError(f"チェックサムが一致しません: {name}")
        extract_checked(path, runtime)
        print(f"SHA-256 OK: {name}")
    print(f"準備先: {root}")
    print("モデル取得・起動はしていません。READMEの次の手順へ進んでください。")


if __name__ == "__main__":
    main()
