import React, { useState } from 'react';
import { useMutation, useQuery } from '@apollo/client';
import {
  Button,
  Card,
  Col,
  CreditCard,
  ErrorMessage,
  FormWrapper,
  GridDeprecated,
  NumberTextBox,
  PaymentSection,
  Row,
} from '@nova-hf/ui';
import EditMenu from 'components/edit-menu/EditMenu';
import { ADD_CARD } from 'graphql/mutations/cards';
import { CARDS } from 'graphql/queries/cards';
import { inject } from 'mobx-react';
import { useSnackbar } from 'notistack';
import { IUserData } from 'typings';
import formElementToObject from 'utils/formElementToObject';
import { useTranslation } from 'utils/i18n';

import { useRemoveCardMutation, useUpdateCardMutation } from '../../../../typings/graphql';

interface IPaymentProps {
  color: string;
  authentication?: any;
}

interface IAddCardProps {
  color: string;
  authentication?: any;
  onComplete: () => void;
}

export const AddCard = ({
  color = 'pink',
  authentication: { accountInput },
  onComplete,
}: IAddCardProps) => {
  const { t } = useTranslation('common');

  const [addCard, { loading }] = useMutation(ADD_CARD);
  const [submitted, setSubmitted] = useState(false);
  const [message, setMessage] = useState('');

  const onSubmit = async (e: any) => {
    // TODO(GUNNAR): type form stuff
    e.preventDefault();

    setSubmitted(false);
    setMessage('');

    const target: HTMLFormElement = e.target;

    if (!target.checkValidity()) {
      const firstInvalid: any = Object.values(e.target.elements).find(
        (el: any) => !el.validity.valid,
      );
      setSubmitted(true);
      if (firstInvalid) {
        firstInvalid.focus();
      }
      return;
    }

    const input: any = formElementToObject(e.target.elements);
    const { cardNumber, ...rest } = input;

    try {
      const res = await addCard({
        variables: {
          input: {
            isDefault: true,
            ssn: accountInput?.ssn,
            cardNumber: cardNumber.replace(/\s/g, ''),
            ...rest,
          },
        },
        refetchQueries: ['cards'],
      });

      if (res.data.addCard.error) {
        setMessage(res.data.addCard.error.message);
      } else {
        setMessage('');
        onComplete();
      }
    } catch (e) {
      setMessage(`${t('errors.general')}: ${e.message}`);
    }
  };

  return (
    <form onSubmit={onSubmit} noValidate id="card-form">
      {message && <ErrorMessage>{message}</ErrorMessage>}
      <FormWrapper color={color} submitted={submitted}>
        <NumberTextBox
          data-key="cardNumber"
          label={t('forms.cc.cardnumber')}
          name="cc-number"
          autoComplete="cc-number"
          errorType="cc"
          cc
          required
        />
        <CreditCard>
          <NumberTextBox
            data-key="expiryMonth"
            label={t('forms.cc.month')}
            name="cc-exp-month"
            autoComplete="cc-exp-month"
            maxLength="2"
            errorType="mm"
            required
          />
          <NumberTextBox
            data-key="expiryYear"
            label={t('forms.cc.year')}
            name="cc-exp-year"
            autoComplete="cc-exp-year"
            length="2"
            errorType="yy"
            required
          />
          <NumberTextBox
            data-key="cvc"
            label={t('forms.cc.cvc')}
            name="cc-exp-csc"
            autoComplete="cc-exp-csc"
            length="3"
            errorType="cvc"
            required
          />
        </CreditCard>
        <Button background={color} type="submit" loading={loading} arrowRight>
          Vista
        </Button>
      </FormWrapper>
    </form>
  );
};

const Payment = ({ color = 'pink', authentication }: IPaymentProps) => {
  const { t } = useTranslation('settings');
  const { accountInput } = authentication;
  const { loading, error, data } = useQuery<IUserData>(CARDS, { variables: { accountInput } });
  const { enqueueSnackbar } = useSnackbar();
  const [removeCard] = useRemoveCardMutation({
    onCompleted() {
      enqueueSnackbar(t('common:notification.success'), {
        variant: 'success',
      });
    },
    onError() {
      enqueueSnackbar(
        t('common:notification.error') + ': ' + t('common:notification.removeCardError'),
        {
          variant: 'error',
        },
      );
    },
  });
  const [updateCard] = useUpdateCardMutation({
    onCompleted() {
      enqueueSnackbar(t('common:notification.success'), {
        variant: 'success',
      });
    },
    onError(error) {
      enqueueSnackbar(t('common:notification.error') + ': ' + error.message, {
        variant: 'error',
      });
    },
  });
  const [showAdd, setShowAdd] = useState(false);

  const handleRemoveClick = (id: string) => {
    removeCard({
      variables: { input: { cardId: id } },
      refetchQueries: ['cards'],
    });
  };

  const handleUpdateClick = (id: string) => {
    updateCard({
      variables: { input: { cardId: id, isDefault: true } },
      refetchQueries: ['cards'],
    });
  };

  if (loading || error || !data) {
    return <div>Loading...</div>;
  }

  const {
    me: { cards },
  } = data;

  return (
    <>
      <PaymentSection
        title={t('payment.title')}
        subtitle={t('payment.subtitle')}
        smallerTitle
        fullWidth
        noSpacingTop
      >
        <GridDeprecated base={9} marginTop={2}>
          {cards.map(({ id, maskedNumber, issuer, expiryMonth, expiryYear }, i) => (
            <Col col={4} colWide={3} colTablet={6} colMobile={12} key={id} marginBottom={0}>
              <Row>
                <Card
                  color={color}
                  ccnumber={maskedNumber.substring(maskedNumber.length - 8, maskedNumber.length)}
                  expiry={`${expiryMonth}/${expiryYear}`}
                  type={issuer}
                  buttonText={i === 0 ? t('payment.selected') : t('payment.select')}
                  selected={i === 0}
                  onClick={() => handleUpdateClick(id)}
                  menu={
                    <EditMenu
                      title={t('payment.menuTitle')}
                      color={color}
                      iconColor="grey400"
                      menuList={[
                        {
                          title: t('payment.remove'),
                          onClick: () => {
                            handleRemoveClick(id);
                          },
                        },
                      ]}
                    />
                  }
                />
              </Row>
            </Col>
          ))}
        </GridDeprecated>
        {!showAdd && (
          <Button onClick={() => setShowAdd(true)} background={color} arrowRight>
            {t('payment.addButton')}
          </Button>
        )}
      </PaymentSection>
      {showAdd && (
        <PaymentSection
          title={t('payment.addTitle')}
          smallerTitle
          fullWidth
          noSpacingTop
          color={color}
        >
          <AddCard onComplete={() => setShowAdd(false)} authentication={authentication} />
        </PaymentSection>
      )}
    </>
  );
};

Payment.getInitalProps = () => {
  return {
    namespacesRequired: ['common'],
  };
};

export default inject('authentication')(Payment);
