import React, { useEffect, useState } from 'react';
import { Controller, useForm } from 'react-hook-form';
import { ApolloError, useMutation, useQuery } from '@apollo/client';
import { ErrorMessage } from '@hookform/error-message';
import {
  Box,
  Button,
  Card,
  Checkbox,
  Col,
  Datepicker,
  FormStatusMessage,
  Grid,
  GridDeprecated,
  GridItem,
  Input,
  MainButton,
  PaymentSection,
  Radio,
  Row,
  Select,
  Text,
} from '@nova-hf/ui';
import { MainColorType } from '@nova-hf/ui/umd/ts/src/styles/vars.css';
import { REMOVE_CARD } from 'graphql/mutations/cards';
import { CHANGE_DEPARTMENT } from 'graphql/mutations/departments';
import { CARDS } from 'graphql/queries/cards';
import { SUBSCRIPTIONACCOUNT } from 'graphql/queries/subscriptionAccount';
import { inject, observer } from 'mobx-react';
import { useSnackbar } from 'notistack';
import Authentication from 'store/authentication';
import Profiles from 'store/profiles';
import { IDepartment, IUserData } from 'typings';
import {
  PaymentTypeV2,
  useDepartmentsQuery,
  useGetSplitBillQuery,
  useInvoiceExplanationMutation,
  useMeLazyQuery,
  usePayerAlterationMutation,
  useSetPostpaidPaymentMethodMutation,
  useSplitBillMutation,
  WsPaymentMethod,
} from 'typings/graphql';
import { isCompany } from 'utils/helpers';
import { useTranslation } from 'utils/i18n';

import EditMenu from '../../../../../../components/edit-menu/EditMenu';
import { AddCard } from '../../../../../stillingar/containers/settings/Payment';

interface IPayerSettingsProps {
  subscriptionId: string;
  color: MainColorType;
  profiles?: Profiles;
  authentication: Authentication;
}

type PayerAlterationForm = {
  newPayerPaysCurrentMonth: boolean;
  payerSsn: string;
  runDate: Date;
  salesNumber: string;
};

type PayerInfo = {
  email?: string;
  address?: string;
  city?: string;
  zip?: string;
  ssn?: string;
  name?: string;
};

export const PayerSettings = ({
  color,
  profiles,
  authentication,
  subscriptionId,
}: IPayerSettingsProps) => {
  const { t } = useTranslation(['stillingar', 'settings', 'multi']);
  const { accountInput } = authentication;
  const { enqueueSnackbar } = useSnackbar();
  const [payerAlteration, { loading: alterationLoading }] = usePayerAlterationMutation();

  const { control, watch, handleSubmit, setValue } = useForm<PayerAlterationForm>({
    defaultValues: {
      newPayerPaysCurrentMonth: false,
      payerSsn: '',
      runDate: undefined,
      salesNumber: '',
    },
    delayError: 500,
    mode: 'onChange',
  });

  const { payerSsn, newPayerPaysCurrentMonth, runDate, salesNumber } = watch();

  const [getPayerInfo] = useMeLazyQuery({
    onCompleted(data) {
      if (data.me?.userProfile && data?.me?.email && data?.me?.ssn) {
        const ssn = data.me.ssn;
        setPayerInfos({
          email: data?.me?.email || '',
          address: data?.me?.userProfile?.streetAddress || '',
          city: data?.me?.userProfile?.city || '',
          zip: data?.me?.userProfile?.postalCode || '',
          ssn: ssn,
          name: data?.me?.name || '',
        });
      }
    },
  });

  const setPayerInfo = (payerSsn: string) => {
    getPayerInfo({ variables: { accountInput: { ssn: payerSsn } } });
  };

  const adjustRunDate = (runDateChosen: Date) => {
    const now = new Date();
    const runDate = new Date(runDateChosen);

    if (
      runDate.getFullYear() === now.getFullYear() &&
      runDate.getMonth() === now.getMonth() &&
      runDate.getDate() === now.getDate()
    ) {
      const bufferMinutes = Math.floor(Math.random() * 11) + 20;
      runDate.setHours(now.getHours());
      runDate.setMinutes(now.getMinutes() + bufferMinutes);
    }

    return runDate;
  };

  useEffect(() => {
    if (payerSsn?.length === 10) {
      setPayerInfo(payerSsn);
    }
  }, [payerSsn]);

  const onSubmit = async () => {
    if (subscriptionId && payerInfos) {
      const adjustRunDateIfNeeded = adjustRunDate(runDate);
      try {
        await payerAlteration({
          variables: {
            input: {
              msisdn: subscriptionId,
              newPayerPaysCurrentMonth: newPayerPaysCurrentMonth,
              payer: {
                method: WsPaymentMethod.BankClaim,
                name: payerInfos.name,
                ssn: payerInfos.ssn,
                email: payerInfos.email,
                address: {
                  address: payerInfos.address,
                  city: payerInfos.city,
                  postcode: payerInfos.zip,
                },
              },
              runDate: adjustRunDateIfNeeded,
              salesPerson: {
                salesPersonNumber: Number(salesNumber),
              },
            },
          },
        });
        enqueueSnackbar('Beiðni verður framkvæmd innan skamms', {
          variant: 'success',
        });
      } catch (e) {
        enqueueSnackbar('Upp kom villa við að senda beiðni', {
          variant: 'error',
        });
      }
    }
  };
  const { data: ceilingData, refetch: ceilingRefetch } = useGetSplitBillQuery({
    variables: {
      input: {
        subscriptionId: subscriptionId,
      },
    },
    skip: !subscriptionId || subscriptionId?.length !== 7,
  });
  const currentCeiling = ceilingData?.getSplitBill?.primaryPayerLimit ?? 0;

  const {
    loading,
    error,
    data,
    refetch: subRefetch,
  } = useQuery<IUserData>(SUBSCRIPTIONACCOUNT, {
    variables: { subscriptionId, accountInput, servicesRequired: false },
  });

  const currentExplanation = data?.me?.profiles?.[0]?.invoiceExplanation;
  const { data: cardData, refetch } = useQuery<IUserData>(CARDS, { variables: { accountInput } });
  const cards = cardData?.me?.cards;

  const [changeDepartment] = useMutation(CHANGE_DEPARTMENT);
  const [splitBill, { loading: splitBillLoading }] = useSplitBillMutation({
    onCompleted() {
      ceilingRefetch();
      enqueueSnackbar(t('multi:ceiling.singleSuccess'), {
        variant: 'success',
      });
    },
    onError(error: ApolloError) {
      enqueueSnackbar(t('multi:ceiling.singleFail') + error.message, {
        variant: 'error',
      });
    },
  });
  const [setExplanation, { loading: setExplanationLoading }] = useInvoiceExplanationMutation({
    onCompleted() {
      subRefetch();
      enqueueSnackbar('Tókst að breyta skýringu á reikning', {
        variant: 'success',
      });
    },
    onError(error: ApolloError) {
      enqueueSnackbar('Ekki tókst að breyta skýringu á reikning' + error.message, {
        variant: 'error',
      });
    },
  });
  const [removeCard] = useMutation(REMOVE_CARD);
  const [updateCard] = useSetPostpaidPaymentMethodMutation({
    onCompleted() {
      refetch();
      subRefetch();
      enqueueSnackbar(t('general.message.success'), {
        variant: 'success',
      });
    },
    onError() {
      enqueueSnackbar(t('general.message.error'), {
        variant: 'error',
      });
    },
  });

  const isSplit = ceilingData?.getSplitBill?.isSplit;
  const [newDepartment, setNewDepartment] = useState('');
  const [newCeiling, setNewCeiling] = useState(0);
  const [newExplanation, setNewExplanation] = useState(currentExplanation);
  const [submitting, setSubmitting] = useState(false);
  const [showAdd, setShowAdd] = useState(false);
  const [isChecked, setIsChecked] = useState(isSplit);
  const [payerInfos, setPayerInfos] = useState<PayerInfo>({});

  const { data: companyDepartmentsData } = useDepartmentsQuery({
    variables: {
      accountInput: {
        ssn: data?.me?.profiles[0]?.accountSsn,
      },
      servicesRequired: false,
    },
    skip: !isCompany(data?.me?.profiles[0]?.accountSsn ?? ''),
  });
  const departmentId = data?.me?.profiles[0]?.departmentId;
  useEffect(() => {
    setNewDepartment(departmentId);
  }, [departmentId]);
  useEffect(() => {
    setIsChecked(isSplit);
  }, [isSplit]);

  if (loading || error || !data?.me?.profiles[0]) {
    return <div>Loading...</div>;
  }

  const { accountName, accountSsn, postpaidPaymentMethod, rateplan } = data.me.profiles[0];

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

  const usedDepartments = companyDepartmentsData?.me?.departments as [IDepartment];

  const bankIsCurrent = postpaidPaymentMethod?.type === PaymentTypeV2.BankClaim;
  const isPayer = ssn === accountSsn;
  const isStaff = authentication?.isStaff;

  const chooseClick = async (type: PaymentTypeV2, virtualNumber?: string) => {
    await updateCard({
      variables: {
        input: {
          subscriptionId: subscriptionId ?? '',
          payerSsn: accountSsn,
          type: type,
          ...(virtualNumber && { virtualNumber }),
        },
      },
    });
  };

  const onCeilingSubmit = () => {
    splitBill({
      variables: {
        input: {
          splitBillLimit: newCeiling,
          splitBill: isChecked,
          subscriptionId: subscriptionId,
        },
      },
    });
  };

  const onExplanationSubmit = () => {
    setExplanation({
      variables: {
        input: {
          invoiceExplanation: newExplanation,
          subscriptionId: subscriptionId,
        },
      },
    });
  };

  function modifyString(inputString: string): string {
    return inputString.replace(/-/g, '').replace(/x/g, '*');
  }

  const submitChanges = async (newDepartmentId: string) => {
    setSubmitting(true);
    try {
      await changeDepartment({
        variables: {
          input: {
            newDepartmentId,
            ssn: accountSsn,
            msisdnList: [subscriptionId],
          },
        },
      });
      setSubmitting(false);
      enqueueSnackbar(t('payer.changeSuccess'), {
        variant: 'success',
      });
    } catch (error) {
      enqueueSnackbar(t('payer.changeError'), {
        variant: 'error',
      });
      setSubmitting(false);
    }
  };

  const payerIsCompanyAndViewerisStaff = isCompany(accountSsn) && isStaff;

  return (
    <Box padding={4} marginX={{ sm: 0, md: 5 }} marginBottom={4}>
      {isStaff && (
        <>
          <Box marginBottom={3}>
            <Text variant="subHeading">Greiðandi</Text>
          </Box>
          <Box marginBottom={3}>
            <Text variant="pMediumBold">Núverandi greiðandi</Text>
          </Box>
          <Box renderAs="form" onSubmit={handleSubmit(onSubmit)}>
            <Grid gridTemplate={{ sm: 4, md: 8 }}>
              <GridItem gridColumn={{ sm: 'span4', md: 'span8' }}>
                <Input
                  id={t('payer.ssn')}
                  name={t('payer.ssn')}
                  type="number"
                  value={accountSsn}
                  label={t('payer.ssn')}
                  color={color}
                  disabled
                />
              </GridItem>
              <GridItem gridColumn={{ sm: 'span4', md: 'span8' }}>
                <Input
                  id={t('payer.name')}
                  name={t('payer.name')}
                  type="text"
                  value={accountName}
                  label={t('payer.name')}
                  color={color}
                  autoComplete="name"
                  disabled
                />
              </GridItem>
              <GridItem gridColumn={{ sm: 'span4', md: 'span8' }}>
                <Text variant="pMediumBold">Nýr greiðandi</Text>
              </GridItem>
              <GridItem gridColumn={{ sm: 'span4', md: 'span8' }}>
                <Controller
                  name="payerSsn"
                  control={control}
                  rules={{
                    required: true,
                    maxLength: {
                      value: 10,
                      message: 'Kennitala getur ekki verið lengri en 10 stafir',
                    },
                    minLength: {
                      value: 10,
                      message: 'Kennitala getur ekki verið styttri en 10 stafir',
                    },
                  }}
                  render={({ field, formState: { errors } }) => {
                    const { value, name, ref } = field;
                    return (
                      <Box>
                        <Input
                          id="payerSsn"
                          name="payerSsnInput"
                          label="Kennitala"
                          isBold={false}
                          value={value}
                          ref={ref}
                          onChange={(e) => setValue('payerSsn', e?.target?.value)}
                        />
                        <ErrorMessage
                          errors={errors}
                          name={name}
                          render={() => <FormStatusMessage message="Villa" status="error" />}
                        />
                      </Box>
                    );
                  }}
                />
              </GridItem>
              <GridItem gridColumn={{ sm: 'span2', md: 'span4' }}>
                <Controller
                  name="runDate"
                  control={control}
                  rules={{ required: true }}
                  render={() => {
                    return (
                      <>
                        <Datepicker
                          inputId="datepicker"
                          inputName="datepicker"
                          color="black100"
                          selected={runDate}
                          minDate={new Date()}
                          onSelect={(date: Date) => setValue('runDate', date)}
                        />
                      </>
                    );
                  }}
                />
              </GridItem>
              <GridItem gridColumn={{ sm: 'span2', md: 'span4' }}>
                <Controller
                  name="salesNumber"
                  control={control}
                  rules={{
                    required: true,
                  }}
                  render={({ field, formState: { errors } }) => {
                    const { value, name, ref } = field;
                    return (
                      <Box>
                        <Input
                          id="salesNumber"
                          name="salesNumberInput"
                          label="Sölunúmer"
                          isBold={false}
                          value={value}
                          ref={ref}
                          onChange={(e) => setValue('salesNumber', e.target.value)}
                        />
                        <ErrorMessage
                          errors={errors}
                          name={name}
                          render={() => <FormStatusMessage message="Villa" status="error" />}
                        />
                      </Box>
                    );
                  }}
                />
              </GridItem>
              <GridItem gridColumn={{ sm: 'span2', md: 'span4' }}>
                <Controller
                  name="newPayerPaysCurrentMonth"
                  control={control}
                  render={() => {
                    return (
                      <Box display="flex" flexDirection="row" alignItems="center">
                        <Radio
                          isChecked={newPayerPaysCurrentMonth}
                          value="Nýr greiðandi borgar núverandi tímabil"
                          color={color}
                          onChange={() => setValue('newPayerPaysCurrentMonth', true)}
                        />
                        <Radio
                          isChecked={!newPayerPaysCurrentMonth}
                          value="Nýr greiðandi tekur við á næsta tímabili"
                          color={color}
                          onChange={() => setValue('newPayerPaysCurrentMonth', false)}
                        />
                      </Box>
                    );
                  }}
                />
              </GridItem>
              <GridItem gridColumn={{ sm: 'span4', md: 'span8' }}>
                <Box
                  display="flex"
                  marginTop={6}
                  justifyContent="flex-start"
                  flexDirection={{ sm: 'column', md: 'row' }}
                >
                  <Box marginBottom={6} display="flex" width={{ sm: '100%', md: '4/12' }}>
                    <MainButton
                      text={'Breyta'}
                      colorScheme={color}
                      isDisabled={!payerSsn || !runDate || !salesNumber}
                      isSubmitButton
                      isLoading={alterationLoading}
                    />
                  </Box>
                </Box>
              </GridItem>
            </Grid>
          </Box>
        </>
      )}
      <Grid rowGap={4} columnGap={4}>
        {(profiles?.isCompany || payerIsCompanyAndViewerisStaff) && usedDepartments && (
          <>
            <Box marginBottom={3}>
              <Text variant="subHeading">Deild</Text>
            </Box>
            <GridItem gridColumn={{ sm: '1/12' }}>
              <Select
                id="departments"
                label={t('payer.department')}
                name="departments"
                onChange={(e) => setNewDepartment(e.target.value)}
                color={color}
                value={newDepartment ?? ''}
              >
                <React.Fragment>
                  <option selected={newDepartment === ''} hidden>
                    {'Engin deild valin'}
                  </option>
                  {usedDepartments?.map(({ name, id }) => {
                    return (
                      <option
                        key={id}
                        value={id}
                        selected={newDepartment?.toLowerCase() === id?.toLowerCase()}
                      >
                        {name}
                      </option>
                    );
                  })}
                </React.Fragment>
              </Select>
            </GridItem>
            <GridItem gridColumn={{ sm: '1/12', md: '1/6' }}>
              <MainButton
                text={t('multi:multi.change')}
                colorScheme={color}
                icon="longArrowRight"
                onClick={() => submitChanges(newDepartment)}
                isLoading={loading || submitting}
                isDisabled={newDepartment === ''}
              />
            </GridItem>
          </>
        )}
        <GridItem />
      </Grid>
      {(profiles?.isCompany || payerIsCompanyAndViewerisStaff) && (
        <Box display="flex" flexDirection="column" gap={3} marginY={7}>
          <Box marginBottom={3}>
            <Text variant="subHeading">Þak</Text>
          </Box>
          <Text variant="pMediumRegular">{t('multi:multi.ceilingDescription')}</Text>
          <Checkbox
            label={isChecked ? 'Þak er á númeri' : 'Ekkert þak er á númeri'}
            isChecked={isChecked}
            type="checked"
            color={color}
            onChange={() => {
              setIsChecked(!isChecked);
            }}
          />
          {isChecked && (
            <>
              <Input
                id={'oldThak'}
                name={t('multi:ceiling.currentCeiling')}
                type="number"
                value={currentCeiling?.toString()}
                label={t('multi:ceiling.currentCeiling')}
                color={color}
                disabled
              />
              <Input
                id={'newThak'}
                name={t('multi:ceiling.newCeiling')}
                type="number"
                value={newCeiling?.toString()}
                label={t('multi:ceiling.newCeiling')}
                color={color}
                onWheel={(e) => {
                  (e.target as HTMLInputElement).blur();
                }}
                onChange={(e) => {
                  const value = e.target.value;
                  setNewCeiling(value ? parseFloat(value) : 0);
                }}
                required
              />
              {(newCeiling === 0 || !newCeiling) && (
                <Text>* Ef þak er 0 kr. þá greiðir notandi allt mánaðargjald. </Text>
              )}
            </>
          )}
          <Box width="6/12">
            <MainButton
              text={t('multi:ceiling.changeButton')}
              colorScheme={color}
              icon="longArrowRight"
              onClick={() => onCeilingSubmit()}
              isLoading={splitBillLoading}
              isDisabled={newCeiling === 1 || (newCeiling === currentCeiling && isChecked)}
            />
          </Box>
        </Box>
      )}
      {(profiles?.isCompany || payerIsCompanyAndViewerisStaff) && (
        <Box display="flex" flexDirection="column" gap={3} marginY={7}>
          <Box marginBottom={3}>
            <Text variant="subHeading">Skýring á reikning</Text>
          </Box>
          <Input
            id={'oldSkyring'}
            name={'Núverandi skýring á reikning'}
            type="text"
            value={currentExplanation?.toString() ?? 'Engin skýring'}
            label={'Núverandi skýring á reikning'}
            color={color}
            isBold={false}
            disabled
          />
          <Input
            id={'newSkyring'}
            name={'Ný skýring á reikning'}
            type="text"
            value={newExplanation?.toString()}
            label={'Ný skýring á reikning'}
            color={color}
            onChange={(e) => {
              const value = e.target.value;
              setNewExplanation(value ? value : '');
            }}
            required
          />
          <Box width="6/12">
            <MainButton
              text={'Breyta skýringu'}
              colorScheme={color}
              icon="longArrowRight"
              onClick={() => onExplanationSubmit()}
              isLoading={setExplanationLoading}
              isDisabled={!newExplanation}
            />
          </Box>
        </Box>
      )}
      {!rateplan.isPrepaid && (isPayer || isStaff) && (
        <>
          <Box marginBottom={3}>
            <Text variant="subHeading">Greiðslumáti</Text>
          </Box>
          <GridDeprecated base={9}>
            {cards?.map(({ id, maskedNumber, issuer, expiryMonth, expiryYear, virtualNumber }) => (
              <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={
                      maskedNumber === modifyString(postpaidPaymentMethod?.maskedNumber ?? '')
                        ? t('settings:payment.selected')
                        : t('settings:payment.select')
                    }
                    selected={
                      maskedNumber === modifyString(postpaidPaymentMethod?.maskedNumber ?? '')
                    }
                    onClick={() => chooseClick(PaymentTypeV2.CreditCard, virtualNumber)}
                    menu={
                      <EditMenu
                        title={t('settings:payment.menuTitle')}
                        color={color}
                        iconColor="grey400"
                        menuList={[
                          {
                            title: t('settings:payment.remove'),
                            onClick: () => {
                              removeCard({
                                variables: { input: { cardId: id } },
                                refetchQueries: ['cards'],
                              });
                            },
                          },
                        ]}
                      />
                    }
                  />
                </Row>
              </Col>
            ))}
            <Col colWide={3} marginBottom={0}>
              <Row>
                <Card
                  color={color}
                  ccnumber={t('multi:multi.bank')}
                  buttonText={
                    bankIsCurrent ? t('settings:payment.selected') : t('settings:payment.select')
                  }
                  selected={bankIsCurrent}
                  onClick={() => chooseClick(PaymentTypeV2.BankClaim)}
                />
              </Row>
            </Col>
          </GridDeprecated>
        </>
      )}
      {!showAdd && !rateplan.isPrepaid && (isPayer || isStaff) && (
        <Button onClick={() => setShowAdd(true)} background={color} arrowRight>
          {t('settings:payment.addButton')}
        </Button>
      )}
      {showAdd && (
        <PaymentSection
          title={t('settings:payment.addTitle')}
          smallerTitle
          fullWidth
          noSpacingTop
          color={color}
        >
          <AddCard
            onComplete={() => setShowAdd(false)}
            authentication={authentication}
            color={color}
          />
        </PaymentSection>
      )}
    </Box>
  );
};

PayerSettings.getInitialProps = ({ query }: any) => {
  return {
    subscriptionId: query.subscriptionId,
    namespacesRequired: ['stillingar', 'settings', 'multi'],
  };
};
export default inject('authentication', 'profiles')(observer(PayerSettings));
