#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Skill keypair management (consumer side only)

The private key is generated by the backend during Skill registration;
the seller persists it to .keypair.json during initialization.
This module only reads and normalizes the format (raw Base64 -> PEM).

File location: <skill_dir>/.keypair.json
File format (example):
{
  "skill_code":  "<32-char skillCode>",
  "private_key": "-----BEGIN PRIVATE KEY-----\\n...\\n-----END PRIVATE KEY-----",
  "sign_method": "SHA256withRSA"
}

private_key can also be raw Base64 (PKCS#8 single-line); this module auto-wraps it into PEM.
"""

from __future__ import annotations

import json
import os
import textwrap
from typing import Dict

import config


class SkillKeypairError(RuntimeError):
    pass


def _to_pem(private_key_str: str) -> bytes:
    """Normalize a private key string into PEM bytes.

    Supports two input formats:
    - Already PEM text (with -----BEGIN/-----END headers);
    - Raw Base64 PKCS#8 single-line (no headers), auto-wrapped into PEM.
    """
    s = private_key_str.strip()
    if not s:
        raise SkillKeypairError("private_key is empty")
    if "BEGIN" in s and "END" in s:
        # Already PEM; normalize line endings
        return s.replace("\r\n", "\n").encode("utf-8")
    # Raw Base64 -> wrap as PEM; fold at 64 chars
    body = "\n".join(textwrap.wrap(s, 64))
    pem = f"-----BEGIN PRIVATE KEY-----\n{body}\n-----END PRIVATE KEY-----\n"
    return pem.encode("utf-8")


def load_keypair(path: str = None) -> Dict:
    """Read .keypair.json and return a dict.

    Returned fields:
    - skill_code: str
    - private_key_pem: bytes (PEM format, can be fed directly to cryptography.serialization.load_pem_private_key)
    - sign_method: str (default SHA256withRSA)
    """
    path = path or config.KEYPAIR_FILE
    if not os.path.exists(path):
        raise SkillKeypairError(
            f".keypair.json not found: {path}\n"
            f"Please persist the Skill-registered private key and skillCode to this file.\n"
            f"Template: {{\"skill_code\":\"...\",\"private_key\":\"-----BEGIN PRIVATE KEY-----...\",\"sign_method\":\"SHA256withRSA\"}}"
        )
    try:
        with open(path, "r", encoding="utf-8") as f:
            raw = json.load(f)
    except json.JSONDecodeError as e:
        raise SkillKeypairError(f".keypair.json parse failed: {e}") from e

    skill_code = (raw.get("skill_code") or "").strip()
    private_key = raw.get("private_key") or ""
    if not skill_code:
        raise SkillKeypairError(".keypair.json missing skill_code")
    if not private_key:
        raise SkillKeypairError(".keypair.json missing private_key")

    return {
        "skill_code": skill_code,
        "private_key_pem": _to_pem(private_key),
        "sign_method": (raw.get("sign_method") or "SHA256withRSA").strip(),
    }
