// motr.mjs

import Dexie from "dexie";

export class Motr {
  constructor(config) {
    this.config = config;
    this.vault = null;
    this.initializeVault();
  }

  initializeVault() {
    const { schema } = this.config;
    this.vault = new Dexie("Vault");
    this.vault.version(schema.version).stores(schema);
  }

  // Account methods
  async insertAccount(accountData) {
    return this.vault.account.add(accountData);
  }

  async getAccount(id) {
    return this.vault.account.get(id);
  }

  async updateAccount(id, accountData) {
    return this.vault.account.update(id, accountData);
  }

  async deleteAccount(id) {
    return this.vault.account.delete(id);
  }

  // Asset methods
  async insertAsset(assetData) {
    return this.vault.asset.add(assetData);
  }

  async getAsset(id) {
    return this.vault.asset.get(id);
  }

  async updateAsset(id, assetData) {
    return this.vault.asset.update(id, assetData);
  }

  async deleteAsset(id) {
    return this.vault.asset.delete(id);
  }

  // Chain methods
  async insertChain(chainData) {
    return this.vault.chain.add(chainData);
  }

  async getChain(id) {
    return this.vault.chain.get(id);
  }

  async updateChain(id, chainData) {
    return this.vault.chain.update(id, chainData);
  }

  async deleteChain(id) {
    return this.vault.chain.delete(id);
  }

  // Credential methods
  async insertCredential(credentialData) {
    const publicKey = await this.createPublicKeyCredential(credentialData);
    credentialData.credentialId = publicKey.id;
    credentialData.publicKey = publicKey.publicKey;
    return this.vault.credential.add(credentialData);
  }

  async getCredential(id) {
    return this.vault.credential.get(id);
  }

  async updateCredential(id, credentialData) {
    return this.vault.credential.update(id, credentialData);
  }

  async deleteCredential(id) {
    return this.vault.credential.delete(id);
  }

  // JWK methods
  async insertJwk(jwkData) {
    return this.vault.jwk.add(jwkData);
  }

  async getJwk(id) {
    return this.vault.jwk.get(id);
  }

  async updateJwk(id, jwkData) {
    return this.vault.jwk.update(id, jwkData);
  }

  async deleteJwk(id) {
    return this.vault.jwk.delete(id);
  }

  // Grant methods
  async insertGrant(grantData) {
    return this.vault.grant.add(grantData);
  }

  async getGrant(id) {
    return this.vault.grant.get(id);
  }

  async updateGrant(id, grantData) {
    return this.vault.grant.update(id, grantData);
  }

  async deleteGrant(id) {
    return this.vault.grant.delete(id);
  }

  // Keyshare methods
  async insertKeyshare(keyshareData) {
    return this.vault.keyshare.add(keyshareData);
  }

  async getKeyshare(id) {
    return this.vault.keyshare.get(id);
  }

  async updateKeyshare(id, keyshareData) {
    return this.vault.keyshare.update(id, keyshareData);
  }

  async deleteKeyshare(id) {
    return this.vault.keyshare.delete(id);
  }

  // PublicKey methods
  async insertPublicKey(publicKeyData) {
    return this.vault.publicKey.add(publicKeyData);
  }

  async getPublicKey(id) {
    return this.vault.publicKey.get(id);
  }

  async updatePublicKey(id, publicKeyData) {
    return this.vault.publicKey.update(id, publicKeyData);
  }

  async deletePublicKey(id) {
    return this.vault.publicKey.delete(id);
  }

  // Profile methods
  async insertProfile(profileData) {
    return this.vault.profile.add(profileData);
  }

  async getProfile(id) {
    return this.vault.profile.get(id);
  }

  async updateProfile(id, profileData) {
    return this.vault.profile.update(id, profileData);
  }

  async deleteProfile(id) {
    return this.vault.profile.delete(id);
  }

  // WebAuthn methods
  async createPublicKeyCredential(options) {
    const publicKeyCredentialCreationOptions = {
      challenge: new Uint8Array(32),
      rp: {
        name: this.config.motr.origin,
        id: new URL(this.config.motr.origin).hostname,
      },
      user: {
        id: new TextEncoder().encode(options.subject),
        name: options.subject,
        displayName: options.label,
      },
      pubKeyCredParams: [
        { alg: -7, type: "public-key" },
        { alg: -257, type: "public-key" },
      ],
      authenticatorSelection: {
        authenticatorAttachment: "platform",
        userVerification: "required",
      },
      timeout: 60000,
      attestation: "direct",
    };

    try {
      const credential = await navigator.credentials.create({
        publicKey: publicKeyCredentialCreationOptions,
      });

      const publicKeyJwk = await crypto.subtle.exportKey(
        "jwk",
        credential.response.getPublicKey(),
      );

      return {
        id: credential.id,
        publicKey: publicKeyJwk,
        type: credential.type,
        transports: credential.response.getTransports(),
      };
    } catch (error) {
      console.error("Error creating credential:", error);
      throw error;
    }
  }

  async getPublicKeyCredential(options) {
    const publicKeyCredentialRequestOptions = {
      challenge: new Uint8Array(32),
      rpId: new URL(this.config.motr.origin).hostname,
      allowCredentials: options.allowCredentials || [],
      userVerification: "required",
      timeout: 60000,
    };

    try {
      const assertion = await navigator.credentials.get({
        publicKey: publicKeyCredentialRequestOptions,
      });

      return {
        id: assertion.id,
        type: assertion.type,
        rawId: new Uint8Array(assertion.rawId),
        response: {
          authenticatorData: new Uint8Array(
            assertion.response.authenticatorData,
          ),
          clientDataJSON: new Uint8Array(assertion.response.clientDataJSON),
          signature: new Uint8Array(assertion.response.signature),
          userHandle: new Uint8Array(assertion.response.userHandle),
        },
      };
    } catch (error) {
      console.error("Error getting credential:", error);
      throw error;
    }
  }
}
