import { useState } from 'react';
import { ApolloCache, FetchResult, useMutation } from '@apollo/client';
import { UPDATE_PAYMENT_METHOD } from 'components/billing/schema/mutations';
import { paymentMethod } from 'components/billing/schema/fragments';
import {
  UpdatePaymentMethodMutation,
  UpdatePaymentMethodMutationVariables,
} from 'types/graphql';

import { useModal } from 'components/layers';

import { Box, Button, Spinner } from 'components/common';
import {
  AddCardModal,
  NewPaymentMethod,
} from 'components/billing/modals/AddCardModal';
import { PaymentMethod } from 'components/billing/PaymentMethod';

const updatePaymentMethodCache = (
  cache: ApolloCache<object>,
  { data }: FetchResult<UpdatePaymentMethodMutation>
) => {
  if (!data?.paymentMethod) return;
  cache.modify({
    fields: {
      paymentMethod() {
        const newPaymentMethodRef = cache.writeFragment({
          data: data.paymentMethod,
          fragment: paymentMethod,
        });
        return newPaymentMethodRef;
      },
    },
  });
};

type PM = {
  id: string;
  brand: string;
  last4: string;
  expYear: string;
  expMonth: string;
};

export const PaymentMethods = ({ data: method }: { data: PM | null }) => {
  const [newPaymentMethod, setNewPaymentMethod] = useState<PM | null>(null);
  const paymentMethod = newPaymentMethod || method;

  const [updatePyamentMethod, update] = useMutation<
    UpdatePaymentMethodMutation,
    UpdatePaymentMethodMutationVariables
  >(UPDATE_PAYMENT_METHOD, {
    update: updatePaymentMethodCache,
  });

  const handleNewPaymentMethod = async (paymentMethod: NewPaymentMethod) => {
    try {
      const { data } = await updatePyamentMethod({
        variables: {
          stripePaymentId: paymentMethod.id,
        },
      });
      setNewPaymentMethod(data!.paymentMethod);
    } catch (error) {
      console.log(error);
    }
  };

  const addCardModal = useModal(AddCardModal, {
    defaultProps: {
      title: paymentMethod ? 'New payment method' : 'Add a card',
      message: paymentMethod
        ? 'New payment method will be applied to your next billing cycle.'
        : undefined,
      withSetupIntent: true,
      onSuccess: handleNewPaymentMethod,
    },
  });

  const loading = update.loading;

  return (
    <Box spacingY={5} className="fz14">
      <div className="flex alignCenter justifyBetween">
        <div className="fz16 bold">Payment methods</div>
        <div>
          <Button
            onClick={() => addCardModal.show()}
            color={!paymentMethod ? 'blue' : 'gray'}
            disabled={loading}
          >
            {!paymentMethod ? 'Add payment method' : 'Change payment method'}
          </Button>
        </div>
      </div>

      {paymentMethod ? (
        <PaymentMethod
          brand={paymentMethod.brand}
          last4={paymentMethod.last4}
          expYear={paymentMethod.expYear}
          expMonth={paymentMethod.expMonth}
          key={paymentMethod.id}
        />
      ) : (
        <div>No credit card found</div>
      )}

      <Spinner show={loading} />
    </Box>
  );
};
