import { Buffer } from "buffer/";
import { decode as cborDecode } from "cbor-x";
import { bytesToMultibase, multibaseToBytes } from "did-jwt";

import { getWebCrypto } from "../../../libs/crypto/vc/passkeyHelpers";

export const PEER_DID_PREFIX = "did:peer:";
const PEER_DID_MULTIBASE_PREFIX = PEER_DID_PREFIX + "0";

/**
 *
 *
 * similar code is in crowd-funder-for-time-pwa libs/crypto/vc/passkeyDidPeer.ts verifyJwtWebCrypto
 *
 * @returns {Promise<boolean>}
 */
export async function verifyPeerSignature(
  payloadBytes: Buffer,
  issuerDid: string,
  signatureBytes: Uint8Array,
): Promise<boolean> {
  const publicKeyBytes = peerDidToPublicKeyBytes(issuerDid);

  const WebCrypto = await getWebCrypto();
  const verifyAlgorithm = {
    name: "ECDSA",
    hash: { name: "SHA-256" },
  };
  const publicKeyJwk = cborToKeys(publicKeyBytes).publicKeyJwk;
  const keyAlgorithm = {
    name: "ECDSA",
    namedCurve: publicKeyJwk.crv,
  };
  const publicKeyCryptoKey = await WebCrypto.subtle.importKey(
    "jwk",
    publicKeyJwk,
    keyAlgorithm,
    false,
    ["verify"],
  );
  const verified = await WebCrypto.subtle.verify(
    verifyAlgorithm,
    publicKeyCryptoKey,
    signatureBytes,
    payloadBytes,
  );
  return verified;
}

export function cborToKeys(publicKeyBytes: Uint8Array) {
  const jwkObj = cborDecode(publicKeyBytes);
  if (
    jwkObj[1] != 2 || // kty "EC"
    jwkObj[3] != -7 || // alg "ES256"
    jwkObj[-1] != 1 || // crv "P-256"
    jwkObj[-2].length != 32 || // x
    jwkObj[-3].length != 32 // y
  ) {
    throw new Error("Unable to extract key.");
  }
  const publicKeyJwk = {
    alg: "ES256",
    crv: "P-256",
    kty: "EC",
    x: arrayToBase64Url(jwkObj[-2]),
    y: arrayToBase64Url(jwkObj[-3]),
  };
  const publicKeyBuffer = Buffer.concat([
    Buffer.from(jwkObj[-2]),
    Buffer.from(jwkObj[-3]),
  ]);
  return { publicKeyJwk, publicKeyBuffer };
}

export function toBase64Url(anythingB64: string) {
  return anythingB64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
}

export function arrayToBase64Url(anything: Uint8Array) {
  return toBase64Url(Buffer.from(anything).toString("base64"));
}

export function peerDidToPublicKeyBytes(did: string) {
  return multibaseToBytes(did.substring(PEER_DID_MULTIBASE_PREFIX.length));
}

export function createPeerDid(publicKeyBytes: Uint8Array) {
  // https://github.com/decentralized-identity/veramo/blob/next/packages/did-provider-peer/src/peer-did-provider.ts#L67
  //const provider = new PeerDIDProvider({ defaultKms: LOCAL_KMS_NAME });
  const methodSpecificId = bytesToMultibase(
    publicKeyBytes,
    "base58btc",
    "p256-pub",
  );
  return PEER_DID_MULTIBASE_PREFIX + methodSpecificId;
}
