"""登录密码 RSA-OAEP 加密 — 公网/客户端须密文上传 · NAS 私钥解密。"""

from __future__ import annotations

import base64
from pathlib import Path
from typing import Any

from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding, rsa


def _keys_path(home: Path) -> Path:
    return home / "control" / "auth_login_rsa.pem"


def ensure_login_keypair(home: Path) -> tuple[bytes, str]:
    """返回 (private_pem, key_id)。key_id = 文件 mtime 或固定 login-v1。"""
    path = _keys_path(home)
    path.parent.mkdir(parents=True, exist_ok=True)
    if not path.is_file():
        private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
        pem = private_key.private_bytes(
            encoding=serialization.Encoding.PEM,
            format=serialization.PrivateFormat.PKCS8,
            encryption_algorithm=serialization.NoEncryption(),
        )
        path.write_bytes(pem)
    private_pem = path.read_bytes()
    key_id = "login-v1"
    return private_pem, key_id


def public_key_pem(home: Path) -> str:
    private_pem, _ = ensure_login_keypair(home)
    private_key = serialization.load_pem_private_key(private_pem, password=None)
    public_key = private_key.public_key()
    return public_key.public_bytes(
        encoding=serialization.Encoding.PEM,
        format=serialization.PublicFormat.SubjectPublicKeyInfo,
    ).decode("utf-8")


def login_key_id(home: Path) -> str:
    ensure_login_keypair(home)
    return "login-v1"


def encrypt_password(plaintext: str, public_pem: str) -> str:
    public_key = serialization.load_pem_public_key(public_pem.encode("utf-8"))
    cipher = public_key.encrypt(
        plaintext.encode("utf-8"),
        padding.OAEP(
            mgf=padding.MGF1(algorithm=hashes.SHA256()),
            algorithm=hashes.SHA256(),
            label=None,
        ),
    )
    return base64.b64encode(cipher).decode("ascii")


def decrypt_password(home: Path, password_encrypted: str) -> str:
    private_pem, _ = ensure_login_keypair(home)
    private_key = serialization.load_pem_private_key(private_pem, password=None)
    raw = base64.b64decode(password_encrypted.encode("ascii"))
    plain = private_key.decrypt(
        raw,
        padding.OAEP(
            mgf=padding.MGF1(algorithm=hashes.SHA256()),
            algorithm=hashes.SHA256(),
            label=None,
        ),
    )
    return plain.decode("utf-8")


def resolve_owner_password(
    home: Path,
    *,
    password: str | None,
    password_encrypted: str | None,
    allow_plaintext: bool,
) -> str | None:
    if password_encrypted:
        try:
            return decrypt_password(home, password_encrypted)
        except Exception as exc:
            raise ValueError("password_decrypt_failed") from exc
    if password and allow_plaintext:
        return str(password).strip()
    if password and not allow_plaintext:
        raise ValueError("password_plaintext_forbidden")
    return None


def login_crypto_config(config: dict[str, Any]) -> dict[str, Any]:
    tenant_auth = config.get("tenant_auth") or {}
    if not isinstance(tenant_auth, dict):
        return {}
    return tenant_auth
