# Cross-Platform Identity Authentication and End-to-End Encrypted Communication Technology Based on DID
# Author: GaoWei Chang
# Email: chgaowei@gmail.com
# Website: http://pi-unlimited.com
#
# This project is open-sourced under the MIT License. For details, please see the LICENSE file.

import os
import hashlib
import base58
import base64
import json
import datetime
from typing import Dict, Any, Tuple
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric.utils import encode_dss_signature
from didall.utils.crypto_tool import generate_secp256r1_private_key, \
                              generate_secp256r1_public_key, \
                              generate_bitcoin_address, generate_signature_for_json

def generate_did(bitcoin_address: str) -> str:
    """Generate DID based on Bitcoin address"""
    return f"did:all:{bitcoin_address}"

def create_did_document(did: str, public_key: ec.EllipticCurvePublicKey, 
                        service_endpoint: str, router: str) -> Dict[str, Any]:
    """Generate DID document"""
    public_key_bytes = public_key.public_bytes(
        encoding=serialization.Encoding.X962,
        format=serialization.PublicFormat.UncompressedPoint
    )
    public_key_hex = '04' + public_key_bytes.hex()
    return {
        "@context": "https://www.w3.org/ns/did/v1",
        "id": did,
        "controller": did,
        "verificationMethod": [
            {
                "id": f"{did}#keys-1",
                "type": "EcdsaSecp256r1VerificationKey2019",
                "controller": did,
                "publicKeyHex": public_key_hex
            }
        ],
        "authentication": [
            {
                "id": f"{did}#keys-1",
                "type": "EcdsaSecp256r1VerificationKey2019",
                "controller": did,
                "publicKeyHex": public_key_hex
            }
        ],
        "service": [
            {
                "id": f"{did}#communication",
                "type": "messageService",
                "router": router,
                "serviceEndpoint": service_endpoint
            }
        ]
    }

def sign_did_document_secp256r1(private_key: ec.EllipticCurvePrivateKey, did_document: Dict[str, Any]) -> Dict[str, Any]:
    """Sign the DID document"""

    # Add timestamp
    created = datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ')
    proof = {
        "type": "EcdsaSecp256r1Signature2019",
        "created": created,
        "proofPurpose": "assertionMethod",
        "verificationMethod": f"{did_document['id']}#keys-1",
    }

    # Add proof to DID document for signing
    did_document['proof'] = proof

    proof_value = generate_signature_for_json(private_key, did_document)

    # Add signature to proof
    proof['proofValue'] = proof_value
    did_document['proof'] = proof

    return did_document

def did_generate(communication_service_endpoint: str, router: str="") -> \
                Tuple[ec.EllipticCurvePrivateKey, ec.EllipticCurvePublicKey, str, str]:
    private_key = generate_secp256r1_private_key()
    public_key = generate_secp256r1_public_key(private_key)
    bitcoin_address = generate_bitcoin_address(public_key)

    did = generate_did(bitcoin_address)
    if not router:
        router = did

    did_document = create_did_document(did, public_key, communication_service_endpoint, router)
    signed_did_document = sign_did_document_secp256r1(private_key, did_document)
    did_document_json = json.dumps(signed_did_document, indent=2)
    return private_key, public_key, did, did_document_json
