#!/usr/bin/env python3
"""Patch Store config to load Baidu credentials from a root-managed PHP file."""

import argparse
import os
import re
import shutil
import tempfile
from pathlib import Path


def load_env(path: Path) -> dict[str, str]:
    result: dict[str, str] = {}
    for raw in path.read_text(encoding="utf-8").splitlines():
        if not raw or raw.startswith("#"):
            continue
        key, sep, value = raw.partition("=")
        if not sep or not re.fullmatch(r"[A-Z][A-Z0-9_]*", key):
            raise ValueError(f"invalid env line in {path}")
        result[key] = value
    return result


def php_quote(value: str) -> str:
    return "'" + value.replace("\\", "\\\\").replace("'", "\\'") + "'"


def replace_once(text: str, pattern: str, replacement: str, label: str) -> str:
    updated, count = re.subn(pattern, replacement, text, flags=re.MULTILINE)
    if count != 1:
        raise ValueError(f"expected exactly one {label}, found {count}")
    return updated


def atomic_write(path: Path, content: str, mode: int) -> None:
    fd, temp_name = tempfile.mkstemp(dir=path.parent, prefix=path.name + ".")
    try:
        with os.fdopen(fd, "w", encoding="utf-8") as handle:
            handle.write(content)
        os.chmod(temp_name, mode)
        os.replace(temp_name, path)
    finally:
        if os.path.exists(temp_name):
            os.unlink(temp_name)


def main() -> int:
    parser = argparse.ArgumentParser()
    parser.add_argument("--project-root", type=Path, required=True)
    parser.add_argument("--secrets-env", type=Path, required=True)
    parser.add_argument("--secret-file", type=Path, required=True)
    parser.add_argument("--backup-dir", type=Path, required=True)
    args = parser.parse_args()

    values = load_env(args.secrets_env)
    api_key = values.get("BAIDU_FACE_API_KEY", "")
    secret_key = values.get("BAIDU_FACE_SECRET_KEY", "")
    if not api_key or api_key == "CHANGE_ME" or not secret_key or secret_key == "CHANGE_ME":
        raise ValueError("Baidu credentials are missing")

    config_path = args.project_root / "application" / "config.php"
    if not config_path.is_file():
        raise ValueError(f"Store config not found: {config_path}")
    original = config_path.read_text(encoding="utf-8")
    args.backup_dir.mkdir(parents=True, exist_ok=True)
    backup = args.backup_dir / "config.php.before-baidu-online"
    shutil.copy2(config_path, backup)

    loader = (
        "$zhctCloudSecretsPath = '/etc/zhct/online-single/cloud-secrets.php';\n"
        "$zhctCloudSecrets = is_readable($zhctCloudSecretsPath) "
        "? require $zhctCloudSecretsPath : [];\n\n"
    )
    if "$zhctCloudSecretsPath" not in original:
        original = replace_once(
            original,
            r"^<\?php\s*\n",
            "<?php\n" + loader,
            "PHP opening tag",
        )
    updated = replace_once(
        original,
        r"^\s*'baidu_apikey'\s*=>.*,$",
        "    'baidu_apikey' => $zhctCloudSecrets['baidu_face_api_key'] ?? '',",
        "baidu_apikey setting",
    )
    updated = replace_once(
        updated,
        r"^\s*'baidu_secretkey'\s*=>.*,$",
        "    'baidu_secretkey' => $zhctCloudSecrets['baidu_face_secret_key'] ?? '',",
        "baidu_secretkey setting",
    )

    secret_php = (
        "<?php\nreturn [\n"
        f"    'baidu_face_api_key' => {php_quote(api_key)},\n"
        f"    'baidu_face_secret_key' => {php_quote(secret_key)},\n"
        "];\n"
    )
    args.secret_file.parent.mkdir(parents=True, exist_ok=True)
    atomic_write(args.secret_file, secret_php, 0o640)
    atomic_write(config_path, updated, 0o640)
    print(str(backup))
    return 0


if __name__ == "__main__":
    raise SystemExit(main())

