import { z } from 'zod';
import { objectKeys } from 'ts-extras';

export class VenmoClient {
  #accessToken: string;
  #defaultChargeeUserId: string;

  constructor(config: VenmoConfig) {
    this.#accessToken = config.accessToken;
    this.#defaultChargeeUserId = config.defaultChargeeId;
  }

  async requestPayment(details: PaymentDetails) {
    try {
      const chargeResponse = await fetch('https://api.venmo.com/v1/payments', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          Authorization: `Bearer ${this.#accessToken}`,
        },
        body: JSON.stringify({
          note: details.note,
          metadata: {
            quasi_cash_disclaimer_viewed: false,
          },
          amount: details.cents * -0.01,
          user_id: this.#defaultChargeeUserId,
          audience: 'private',
        }),
      });

      if (!chargeResponse.ok) {
        throw new Error(`Venmo charge failed with status ${chargeResponse.status}`);
      }
    } catch (e) {
      console.error('Venmo charge error: ', e);
      throw e;
    }
  }
}

const ChargeeIdSchema = z.string();

export const VenmoEnvVarsSchema = z.object({
  DEFAULT_VENMO_CHARGEE_ID: ChargeeIdSchema,
  VENMO_API_ACCESS_TOKEN: z.string(),
});

export const VENMO_ENV_VAR_NAMES = objectKeys(VenmoEnvVarsSchema.keyof().Values);

export const VenmoConfigSchema = z.object({
  accessToken: z.string(),
  defaultChargeeId: ChargeeIdSchema,
});

type VenmoConfig = z.infer<typeof VenmoConfigSchema>;

export const PaymentDetailsSchema = z.object({
  cents: z.number(),
  note: z.string(),
});

export type PaymentDetails = z.infer<typeof PaymentDetailsSchema>;
