"""
Witness Signing Infrastructure

Creates cryptographically signed attestations of trustmark state for external verification.
Uses Ed25519 signatures for compact, fast signing suitable for CI environments.
"""
from __future__ import annotations

import hashlib
import json
from datetime import datetime, timezone
from pathlib import Path
from typing import Dict, Any, Optional, Union

try:
    from nacl.signing import SigningKey, VerifyKey
    from nacl.encoding import HexEncoder
    HAS_NACL = True
except ImportError:
    HAS_NACL = False


class WitnessSigner:
    """
    Ed25519 witness signer for trustmark attestations.

    Usage:
        # Generate new key
        signer = WitnessSigner.generate()
        signer.save_key("var/witness/key.secret")

        # Load existing key
        signer = WitnessSigner.load("var/witness/key.secret")

        # Sign trustmark
        witness = signer.sign_trustmark(trustmark, witness_id="witness_001")
    """

    def __init__(self, signing_key: Optional[bytes] = None):
        """
        Initialize witness signer.

        Args:
            signing_key: 32-byte Ed25519 signing key (None to generate new)
        """
        if not HAS_NACL:
            raise ImportError("PyNaCl required for witness signing: pip install pynacl")

        if signing_key is None:
            self.signing_key = SigningKey.generate()
        else:
            self.signing_key = SigningKey(signing_key)

    @classmethod
    def generate(cls) -> WitnessSigner:
        """Generate new witness signer with random key."""
        return cls(signing_key=None)

    @classmethod
    def load(cls, path: Union[str, Path]) -> WitnessSigner:
        """
        Load signing key from file.

        Args:
            path: Path to secret key file (32 bytes hex)

        Returns:
            WitnessSigner instance
        """
        key_hex = Path(path).read_text().strip()
        key_bytes = bytes.fromhex(key_hex)
        return cls(signing_key=key_bytes)

    def save_key(self, path: Union[str, Path]) -> None:
        """
        Save signing key to file (KEEP SECRET).

        Args:
            path: Path to write secret key (32 bytes hex)
        """
        p = Path(path)
        p.parent.mkdir(parents=True, exist_ok=True)
        p.write_text(self.signing_key.encode(encoder=HexEncoder).decode("utf-8"))
        p.chmod(0o600)  # Make file readable only by owner

    def public_key_hex(self) -> str:
        """Get public key as hex string (for verification)."""
        return self.signing_key.verify_key.encode(encoder=HexEncoder).decode("utf-8")

    def sign_trustmark(
        self,
        trustmark: Dict[str, Any],
        witness_id: str = "witness_001",
        who: str = "@guardian_ci"
    ) -> Dict[str, Any]:
        """
        Sign trustmark and create witness receipt.

        Args:
            trustmark: Trustmark payload to attest
            witness_id: Unique witness identifier
            who: Identity of witness

        Returns:
            Witness receipt with Ed25519 signature
        """
        # Compute hash of trustmark (canonical JSON)
        trustmark_canonical = json.dumps(trustmark, sort_keys=True, separators=(',', ':'))
        h = hashlib.sha256()
        h.update(trustmark_canonical.encode("utf-8"))
        trustmark_hash = "sha256:" + h.hexdigest()

        # Build witness receipt (unsigned)
        witness = {
            "schema": "receipt.witness.v1",
            "ts": datetime.now(timezone.utc).isoformat(),
            "who": who,
            "subject": f"Trustmark attestation: V={trustmark.get('verifiability_score', 0.0):.2f}",
            "trustmark_hash": trustmark_hash,
            "verifiability_score": trustmark.get("verifiability_score", 0.0),
            "metrics": {
                "evhd_pass": trustmark.get("integrity", {}).get("evhd_pass", False) if trustmark.get("integrity") else False,
                "dignity_p50": trustmark.get("dignity", {}).get("p50", 0.0) if trustmark.get("dignity") else 0.0,
                "atlas_coverage": trustmark.get("atlas", {}).get("coverage", 0.0) if trustmark.get("atlas") else 0.0,
                "floors_breached": trustmark.get("dignity", {}).get("floors_breached", 0) if trustmark.get("dignity") else 0,
            },
            "witness_id": witness_id,
            "public_key": self.public_key_hex(),
        }

        # Sign canonical representation
        witness_canonical = json.dumps(witness, sort_keys=True, separators=(',', ':'))
        signature_bytes = self.signing_key.sign(witness_canonical.encode("utf-8")).signature
        signature_hex = signature_bytes.hex()

        # Add signature
        witness["signature"] = f"ed25519:{signature_hex}"

        return witness


def verify_witness(witness: Dict[str, Any]) -> bool:
    """
    Verify witness receipt signature.

    Args:
        witness: Witness receipt with signature

    Returns:
        True if signature valid, False otherwise
    """
    if not HAS_NACL:
        raise ImportError("PyNaCl required for witness verification: pip install pynacl")

    try:
        # Extract public key and signature
        public_key_hex = witness["public_key"]
        signature_str = witness["signature"]

        if not signature_str.startswith("ed25519:"):
            return False

        signature_hex = signature_str.split(":", 1)[1]
        signature_bytes = bytes.fromhex(signature_hex)

        # Build canonical representation (without signature)
        witness_unsigned = {k: v for k, v in witness.items() if k != "signature"}
        witness_canonical = json.dumps(witness_unsigned, sort_keys=True, separators=(',', ':'))

        # Verify signature
        verify_key = VerifyKey(public_key_hex, encoder=HexEncoder)
        verify_key.verify(witness_canonical.encode("utf-8"), signature_bytes)

        return True

    except Exception:
        return False


def build_witness_receipt(
    trustmark_path: Union[str, Path] = "var/trustmark.json",
    witness_id: str = "witness_001",
    key_path: Union[str, Path] = "var/witness/key.secret",
    output_path: Optional[Union[str, Path]] = None
) -> Dict[str, Any]:
    """
    Build and optionally save witness receipt for trustmark.

    Args:
        trustmark_path: Path to trustmark JSON file
        witness_id: Unique witness identifier
        key_path: Path to Ed25519 secret key (creates if missing)
        output_path: Optional path to save witness receipt

    Returns:
        Witness receipt dict
    """
    # Load or generate signer
    key_p = Path(key_path)
    if key_p.exists():
        signer = WitnessSigner.load(key_p)
    else:
        print(f"Generating new witness key: {key_p}")
        signer = WitnessSigner.generate()
        signer.save_key(key_p)
        print(f"Public key: {signer.public_key_hex()}")

    # Load trustmark
    trustmark = json.loads(Path(trustmark_path).read_text(encoding="utf-8"))

    # Sign and create witness receipt
    witness = signer.sign_trustmark(trustmark, witness_id=witness_id)

    # Save if output path provided
    if output_path:
        out_p = Path(output_path)
        out_p.parent.mkdir(parents=True, exist_ok=True)
        out_p.write_text(json.dumps(witness, indent=2))

    return witness


if __name__ == "__main__":
    import argparse

    parser = argparse.ArgumentParser(description="Witness trustmark attestation")
    parser.add_argument(
        "--trustmark",
        default="var/trustmark.json",
        help="Path to trustmark JSON file"
    )
    parser.add_argument(
        "--key",
        default="var/witness/key.secret",
        help="Path to witness signing key"
    )
    parser.add_argument(
        "--output",
        default="var/witness/latest.json",
        help="Path to save witness receipt"
    )
    parser.add_argument(
        "--witness-id",
        default="witness_001",
        help="Unique witness identifier"
    )
    parser.add_argument(
        "--verify",
        help="Verify existing witness receipt"
    )

    args = parser.parse_args()

    if args.verify:
        # Verify mode
        witness = json.loads(Path(args.verify).read_text(encoding="utf-8"))
        if verify_witness(witness):
            print(f"✅ Witness signature valid")
            print(f"   Witness ID: {witness['witness_id']}")
            print(f"   Verifiability: {witness['verifiability_score']:.2f}")
            print(f"   Public key: {witness['public_key']}")
        else:
            print(f"❌ Witness signature INVALID")
            exit(1)
    else:
        # Sign mode
        witness = build_witness_receipt(
            trustmark_path=args.trustmark,
            witness_id=args.witness_id,
            key_path=args.key,
            output_path=args.output
        )
        print(json.dumps(witness, indent=2))
