#!/bin/bash

# DID Creation and Registration Flow
# @author Matthew Raymer
#
# This script implements the creation and registration of Decentralized Identifiers (DIDs)
# with the endorser.ch service. It matches the Python and TypeScript implementations.
#
# Flow:
# 1. Generate or load mnemonic seed phrase
# 2. Derive Ethereum keys and address
# 3. Create DID identifier
# 4. Initialize account
# 5. Create signed JWT
# 6. Register DID with endorser service

# Constants
API_SERVER=${ENDORSER_API_URL:-"https://test-api.endorser.ch"}
ENDORSER_DID="did:ethr:0x0000694B58C2cC69658993A90D3840C560f2F51F"
ENDORSER_PRIVATE_KEY="2b6472c026ec2aa2c4235c994a63868fc9212d18b58f6cbfe861b52e71330f5b"

# Create temporary directory for operations
TMPDIR=$(mktemp -d)
trap 'rm -rf "$TMPDIR"' EXIT

initialize_account() {
    # Generate or load mnemonic
    if [ ! -f "mnemonic.txt" ]; then
        # Generate entropy and convert to hex
        openssl rand -hex 32 > mnemonic.txt
    fi
    
    # Read entropy
    ENTROPY=$(cat mnemonic.txt)
    
    # Create temporary directory for key operations
    TMPDIR=$(mktemp -d)
    trap 'rm -rf "$TMPDIR"' EXIT
    
    # Generate secp256k1 private key
    openssl ecparam -name secp256k1 -genkey -noout -out "$TMPDIR/private.pem"
    
    # Extract private key in hex format
    PRIVATE_KEY=$(openssl ec -in "$TMPDIR/private.pem" -text -noout 2>/dev/null | 
        grep priv -A 3 | tail -n +2 | tr -d '\n[:space:]:' | cut -c3-)
    
    # Generate public key and address
    PUBLIC_KEY=$(openssl ec -in "$TMPDIR/private.pem" -pubout -outform DER 2>/dev/null | 
        tail -c 65 | xxd -p -c 65)
    
    # Generate Ethereum address (last 20 bytes of keccak256 of public key)
    ADDRESS=$(echo -n "$PUBLIC_KEY" | xxd -r -p | 
        openssl dgst -sha3-256 -binary | 
        tail -c 20 | xxd -p)
    
    # Create identity JSON
    IDENTITY=$(cat <<EOF
{
    "did": "did:ethr:0x${ADDRESS}",
    "keys": [{
        "id": "did:ethr:0x${ADDRESS}#keys-1",
        "type": "Secp256k1VerificationKey2018",
        "controller": "did:ethr:0x${ADDRESS}",
        "ethereumAddress": "0x${ADDRESS}",
        "publicKeyHex": "${PUBLIC_KEY}",
        "privateKeyHex": "${PRIVATE_KEY}"
    }],
    "services": []
}
EOF
)

    echo "Account initialized:"
    echo "$IDENTITY" | jq .
    echo
    
    # Export for other functions
    export IDENTITY
}

create_endorser_jwt() {
    local did="$1"
    local private_key="$2"
    local payload="$3"
    local sub_did="$4"
    
    # Create JWT header and payload
    local now=$(date +%s)
    local exp=$((now + 3600))
    
    local header='{"typ":"JWT","alg":"ES256K"}'
    local jwt_payload=$(echo "$payload" | jq --arg iss "$did" \
        --arg iat "$now" \
        --arg exp "$exp" \
        '. + {iss: $iss, iat: ($iat|tonumber), exp: ($exp|tonumber)}')
    
    # Base64URL encode header and payload
    local header_b64=$(echo -n "$header" | base64 -w 0 | tr '/+' '_-' | tr -d '=')
    local payload_b64=$(echo -n "$jwt_payload" | base64 -w 0 | tr '/+' '_-' | tr -d '=')
    local message="$header_b64.$payload_b64"
    
    # Create temporary directory
    local TMPDIR=$(mktemp -d)
    trap 'rm -rf "$TMPDIR"' EXIT
    
    # Create private key in SEC1 format
    (
        echo -n "$private_key"  # Private key bytes
    ) | xxd -r -p > "$TMPDIR/private.key"
    
    # Hash the message
    echo -n "$message" | openssl dgst -sha256 -binary -out "$TMPDIR/message.hash"
    
    # Sign using bitcoin-cli (or similar tool that handles secp256k1 correctly)
    if command -v bitcoin-cli &> /dev/null; then
        # Use bitcoin-cli if available
        signature=$(bitcoin-cli signmessagewithprivkey \
            "$(cat "$TMPDIR/private.key" | xxd -p -c 64)" \
            "$(cat "$TMPDIR/message.hash" | xxd -p -c 32)")
    else
        # Fallback to custom secp256k1 signing
        signature=$(secp256k1-sign "$TMPDIR/private.key" "$TMPDIR/message.hash")
    fi
    
    echo "$message.$signature"
}

register() {
    local active_did="$1"
    
    echo "Endorser DID: $ENDORSER_DID"
    echo "Active DID: $active_did"
    
    # Create registration claim
    local vc_payload=$(cat <<EOF
{
    "vc": {
        "@context": ["https://www.w3.org/2018/credentials/v1"],
        "type": ["VerifiableCredential"],
        "credentialSubject": {
            "@context": "https://schema.org",
            "@type": "RegisterAction",
            "agent": {
                "identifier": "$ENDORSER_DID"
            },
            "participant": {
                "identifier": "$active_did"
            },
            "object": "endorser.ch",
            "endTime": $(( $(date +%s) + 7*24*60*60 ))
        }
    }
}
EOF
)

    echo "Registration Claim:"
    echo "$vc_payload" | jq .
    echo

    # Create and sign JWT
    local jwt_token=$(create_endorser_jwt "$ENDORSER_DID" "$ENDORSER_PRIVATE_KEY" "$vc_payload" "$active_did")
    
    echo "Generated JWT:"
    echo "$jwt_token"
    echo
    
    # Submit registration
    local response=$(curl -s -X POST "$API_SERVER/api/v2/claim" \
        -H "Content-Type: application/json" \
        -d "{\"jwtEncoded\": \"$jwt_token\"}")
    
    echo "Registration response:"
    echo "$response" | jq .
}

main() {
    initialize_account
    
    # Extract DID and private key from identity
    local active_did=$(echo "$IDENTITY" | jq -r .did)
    local private_key=$(echo "$IDENTITY" | jq -r .keys[0].privateKeyHex)
    
    # Register DID
    register "$active_did"
}

main "$@"