import Foundation
import Mpc
import React

@objc(PortalMobileMpc)
class PortalMobileMpc: NSObject {

  @objc static func requiresMainQueueSetup() -> Bool { false }

  private static let mpcQueue = DispatchQueue(label: "io.portalhq.mpc", attributes: .concurrent)

  @objc var methodQueue: DispatchQueue {
    return PortalMobileMpc.mpcQueue
  }

  // MARK: - Generate Methods

  @objc func generate(
    _ clientApiKey: String,
    addr: String,
    apiHost: String,
    metadata: String,
    resolve: @escaping RCTPromiseResolveBlock,
    reject _: @escaping RCTPromiseRejectBlock
  ) {
    let result = MobileGenerate(clientApiKey, addr, apiHost, metadata)
    resolve(result)
  }

  @objc func generateEd25519(
    _ clientApiKey: String,
    addr: String,
    apiHost: String,
    metadata: String,
    resolve: @escaping RCTPromiseResolveBlock,
    reject _: @escaping RCTPromiseRejectBlock
  ) {
    let result = MobileGenerateEd25519(clientApiKey, addr, apiHost, metadata)
    resolve(result)
  }

  @objc func generateSecp256k1(
    _ clientApiKey: String,
    addr: String,
    apiHost: String,
    metadata: String,
    resolve: @escaping RCTPromiseResolveBlock,
    reject _: @escaping RCTPromiseRejectBlock
  ) {
    let result = MobileGenerateSecp256k1(clientApiKey, addr, apiHost, metadata)
    resolve(result)
  }

  // MARK: - Sign Method

  @objc func sign(
    _ clientApiKey: String,
    addr: String,
    dkgResult: String,
    method: String,
    params: String,
    rpcUrl: String,
    chainId: String,
    metadata: String,
    resolve: @escaping RCTPromiseResolveBlock,
    reject _: @escaping RCTPromiseRejectBlock
  ) {
    let result = MobileSign(clientApiKey, addr, dkgResult, method, params, rpcUrl, chainId, metadata)
    resolve(result)
  }

  // Internal SDK use only: do not expose to client API. Pre-signature flow is managed by portal.request() / MpcSigner.
  @objc func presign(
    _ clientApiKey: String,
    addr: String,
    share: String,
    metadata: String,
    resolve: @escaping RCTPromiseResolveBlock,
    reject _: @escaping RCTPromiseRejectBlock
  ) {
    let result = MobilePresign(clientApiKey, addr, share, metadata)
    resolve(result)
  }

  // Internal SDK use only: do not expose to client API. Used by MpcSigner when a presignature is available during portal.request() signing.
  @objc func signWithPresignature(
    _ clientApiKey: String,
    addr: String,
    share: String,
    presignature: String,
    method: String,
    params: String,
    rpcUrl: String,
    chainId: String,
    metadata: String,
    resolve: @escaping RCTPromiseResolveBlock,
    reject _: @escaping RCTPromiseRejectBlock
  ) {
    let result = MobileSignWithPresignature(clientApiKey, addr, share, presignature, method, params, rpcUrl, chainId, metadata)
    resolve(result)
  }

  // MARK: - Backup Methods

  @objc func backup(
    _ clientApiKey: String,
    addr: String,
    dkgResult: String,
    apiHost: String,
    metadata: String,
    resolve: @escaping RCTPromiseResolveBlock,
    reject _: @escaping RCTPromiseRejectBlock
  ) {
    let result = MobileBackup(clientApiKey, addr, dkgResult, apiHost, metadata)
    resolve(result)
  }

  @objc func backupEd25519(
    _ clientApiKey: String,
    addr: String,
    dkgResult: String,
    apiHost: String,
    metadata: String,
    resolve: @escaping RCTPromiseResolveBlock,
    reject _: @escaping RCTPromiseRejectBlock
  ) {
    let result = MobileBackupEd25519(clientApiKey, addr, dkgResult, apiHost, metadata)
    resolve(result)
  }

  @objc func backupSecp256k1(
    _ clientApiKey: String,
    addr: String,
    dkgResult: String,
    apiHost: String,
    metadata: String,
    resolve: @escaping RCTPromiseResolveBlock,
    reject _: @escaping RCTPromiseRejectBlock
  ) {
    let result = MobileBackupSecp256k1(clientApiKey, addr, dkgResult, apiHost, metadata)
    resolve(result)
  }

  // MARK: - Recover Methods

  @objc func recoverSigning(
    _ clientApiKey: String,
    addr: String,
    dkgResult: String,
    apiHost: String,
    metadata: String,
    resolve: @escaping RCTPromiseResolveBlock,
    reject _: @escaping RCTPromiseRejectBlock
  ) {
    let result = MobileRecoverSigning(clientApiKey, addr, dkgResult, apiHost, metadata)
    resolve(result)
  }

  @objc func recoverSigningSecp256k1(
    _ clientApiKey: String,
    addr: String,
    dkgResult: String,
    apiHost: String,
    metadata: String,
    resolve: @escaping RCTPromiseResolveBlock,
    reject _: @escaping RCTPromiseRejectBlock
  ) {
    let result = MobileRecoverSigningSecp256k1(clientApiKey, addr, dkgResult, apiHost, metadata)
    resolve(result)
  }

  @objc func recoverSigningEd25519(
    _ clientApiKey: String,
    addr: String,
    dkgResult: String,
    apiHost: String,
    metadata: String,
    resolve: @escaping RCTPromiseResolveBlock,
    reject _: @escaping RCTPromiseRejectBlock
  ) {
    let result = MobileRecoverSigningEd25519(clientApiKey, addr, dkgResult, apiHost, metadata)
    resolve(result)
  }

  @objc func recoverBackup(
    _ clientApiKey: String,
    addr: String,
    dkgResult: String,
    apiHost: String,
    metadata: String,
    resolve: @escaping RCTPromiseResolveBlock,
    reject _: @escaping RCTPromiseRejectBlock
  ) {
    let result = MobileRecoverBackup(clientApiKey, addr, dkgResult, apiHost, metadata)
    resolve(result)
  }

  // MARK: - Encryption Methods

  @objc func encrypt(
    _ data: String,
    resolve: @escaping RCTPromiseResolveBlock,
    reject _: @escaping RCTPromiseRejectBlock
  ) {
    let result = MobileEncrypt(data)
    resolve(result)
  }

  @objc func decrypt(
    _ key: String,
    cipherText: String,
    resolve: @escaping RCTPromiseResolveBlock,
    reject _: @escaping RCTPromiseRejectBlock
  ) {
    let result = MobileDecrypt(key, cipherText)
    resolve(result)
  }

  @objc func encryptWithPassword(
    _ data: String,
    password: String,
    resolve: @escaping RCTPromiseResolveBlock,
    reject _: @escaping RCTPromiseRejectBlock
  ) {
    let result = MobileEncryptWithPassword(data, password)
    resolve(result)
  }

  @objc func decryptWithPassword(
    _ key: String,
    cipherText: String,
    resolve: @escaping RCTPromiseResolveBlock,
    reject _: @escaping RCTPromiseRejectBlock
  ) {
    let result = MobileDecryptWithPassword(key, cipherText)
    resolve(result)
  }

  // MARK: - Eject Methods

  @objc func ejectSecp256k1(
    _ dkgResultOne: String,
    dkgResultTwo: String,
    resolve: @escaping RCTPromiseResolveBlock,
    reject _: @escaping RCTPromiseRejectBlock
  ) {
    let result = MobileEjectWalletAndDiscontinueMPC(dkgResultOne, dkgResultTwo)
    resolve(result)
  }

  @objc func ejectEd25519(
    _ dkgResultOne: String,
    dkgResultTwo: String,
    resolve: @escaping RCTPromiseResolveBlock,
    reject _: @escaping RCTPromiseRejectBlock
  ) {
    let result = MobileEjectWalletAndDiscontinueMPCEd25519(dkgResultOne, dkgResultTwo)
    resolve(result)
  }

  // MARK: - Utility Methods

  @objc func formatShares(
    _ shares: String,
    resolve: @escaping RCTPromiseResolveBlock,
    reject _: @escaping RCTPromiseRejectBlock
  ) {
    let result = MobileFormatShares(shares)
    resolve(result)
  }

  @objc func getCustodianIdClientIdHashes(
    _ custodianIdClientIdJson: String,
    resolve: @escaping RCTPromiseResolveBlock,
    reject _: @escaping RCTPromiseRejectBlock
  ) {
    let result = MobileGetCustodianIdClientIdHashes(custodianIdClientIdJson)
    resolve(result)
  }
}
