import type { TLineItemExpanded } from '../../store/models';
import type { CallbackArgs } from '../../libs/auth';
import { getTxMetadata } from '../../libs/util';
import {
  ensureSubscriptionDelegation,
  executeOcapTransactions,
  getAuthPrincipalClaim,
  getDelegationTxClaim,
} from './shared';

export default {
  action: 'delegation',
  authPrincipal: false,
  claims: {
    authPrincipal: async ({ extraParams }: CallbackArgs) => {
      const { paymentMethod } = await ensureSubscriptionDelegation(extraParams.subscriptionId);
      return getAuthPrincipalClaim(paymentMethod, 'continue');
    },
  },
  onConnect: async (args: CallbackArgs) => {
    const { userDid, userPk, extraParams } = args;
    const { paymentMethod, paymentCurrency, subscription, payerAddress } = await ensureSubscriptionDelegation(
      extraParams.subscriptionId
    );
    const billingThreshold = Number(subscription.billing_thresholds?.amount_gte || 0);
    if (userDid !== payerAddress) {
      throw new Error(
        `You are not the payer for this subscription. Expected payer: ${payerAddress}, but found: ${userDid}.`
      );
    }
    const claims: { [type: string]: [string, object] } = {
      delegation: [
        'signature',
        await getDelegationTxClaim({
          mode: 'delegation',
          userDid,
          userPk,
          nonce: subscription.id,
          data: getTxMetadata({ subscriptionId: subscription.id }),
          paymentCurrency,
          paymentMethod,
          trialing: true,
          billingThreshold,
          items: subscription!.items as TLineItemExpanded[],
          requiredStake: false,
          slippageConfig: subscription?.slippage_config || undefined,
        }),
      ],
    };
    return claims;
  },
  onAuth: async (args: CallbackArgs) => {
    const { request, userDid, userPk, claims, extraParams } = args;
    const { subscriptionId } = extraParams;
    const { paymentMethod, paymentCurrency } = await ensureSubscriptionDelegation(subscriptionId);

    if (paymentMethod.type === 'arcblock') {
      const { stakingAmount, ...paymentDetails } = await executeOcapTransactions(
        userDid,
        userPk,
        claims,
        paymentMethod,
        request,
        subscriptionId,
        paymentCurrency?.contract
      );
      return { hash: paymentDetails.tx_hash };
    }

    throw new Error(`Payment method ${paymentMethod.type} not supported`);
  },
};
