import { useState } from 'react';
import { useMutation, useQuery } from '@apollo/client';
import { inject } from 'mobx-react';
import { useSnackbar } from 'notistack';
import { useTranslation } from 'utils/i18n';
import { stripTypenames } from 'utils/helpers';
import { isEmpty } from 'lodash';

import { Payment, PaymentSection, NumberTextBox, Button, Col, Row, TextBox, FormDropdown, InfoText } from '@nova-hf/ui';
import Switch from 'components/switch/Switch';

import { FORWARDING_SETTINGS } from 'graphql/queries/forwardingSettings';
import { CHANGE_FORWARDING_SETTINGS } from 'graphql/mutations/forwardingSettings';
import { IForwardingSettings, IOpeningHours, IRecording, IUserData, IDay, IForwardingNumber } from 'typings';

import Settings from '../../containers/settings/Settings';
import { ServiceOpeningHours } from '../components/service-opening-hours/ServiceOpeningHours';

const COLOR = 'purple';

interface IDoormanProps {
  subscriptionId: string;
  pathname: string;
  authentication?: any;
}

interface IOpeningHoursProps {
  color: string;
  openingHours: IOpeningHours;
  setOpeningHours(openingHours: IOpeningHours): any;
}

interface IRecordingProps {
  color: string;
  recording: IRecording;
  setRecording(recording: IRecording): any;
  forwardFrom: string;
  forwardTo: string;
}

interface IForwardingProps {
  color: string;
  subscriptionId: string;
  forwardingSettings: IForwardingSettings;
}

const Forwarding = ({ forwardingSettings, color, subscriptionId }: IForwardingProps) => {
  const { t } = useTranslation('stillingar');
  const { enqueueSnackbar } = useSnackbar();
  const [changeForwardingSettings, { loading }] = useMutation(CHANGE_FORWARDING_SETTINGS);

  const [forwardingData, setForwarding] = useState(forwardingSettings);
  const { forwardingNumbers, voicemailActive, voicemailEmail, recording, openingHours } = forwardingData;

  const numberRe = /^[0-9\b]+$/;

  const changeSettings = async () => {
    try {
      const stripData = stripTypenames(forwardingData);
      const { data } = await changeForwardingSettings({ variables: { input: { ...stripData, subscriptionId } } });

      if (data.changeForwardingSettings.error) {
        const { error: { message } } = data.changeForwardingSettings;

        enqueueSnackbar(`${t('doorman.forwarding.error')}: ${message}`, {
          variant: 'error',
        });
      } else {
        setForwarding(data.changeForwardingSettings.forwardingSettings);
        enqueueSnackbar(t('doorman.forwarding.success'), {
          variant: 'success',
        });
      }
    } catch (e) {
      console.error(e);
      enqueueSnackbar(`${t('doorman.forwarding.error')}: ${e.message}`, {
        variant: 'error',
      });
    }
  };

  const cancel = () => {
    setForwarding(forwardingSettings);
  };

  const setNewData = (
    key: 'voicemailActive' | 'voicemailEmail' | 'forwardingNumbers' | 'openingHours' | 'recording',
    value: boolean | string | IForwardingNumber[] | IOpeningHours | IRecording,
  ) => {
    setForwarding({
      ...forwardingData,
      [key]: value,
    });
  };

  return (
    <Payment color={color}>
      <PaymentSection
        smallerTitle
        fullWidth
        noSpacingTop
        title={t('doorman.forwarding.title')}
        subtitle={t('doorman.forwarding.subtitle')}
      >
        <NumberTextBox
          name="phonenumber"
          label={t('doorman.forwarding.forwardFrom')}
          length={7}
          value={forwardingNumbers[0]?.doormanNumber}
          disabled
        />
        <NumberTextBox
          name="phonenumber"
          label={t('doorman.forwarding.forwardTo')}
          length={7}
          value={forwardingNumbers[0]?.forwardTo[0]}
          onChange={(e: any) => setNewData(
            'forwardingNumbers',
            [{
              ...forwardingNumbers[0],
              forwardTo: numberRe.test(e.target.value) ? [e.target.value] : [forwardingNumbers?.[0]?.forwardTo[0]],
            }],
          )}
        />
        <Row>
          <Col col={4}>
            {t('doorman.forwarding.voicemail')}
          </Col>
          <Col col={2}>
            <Switch
              isOn={voicemailActive}
              onToggle={() => setNewData('voicemailActive', !voicemailActive)}
              color={color}
            />
          </Col>
          <Col col={6}>
            <InfoText>{t('doorman.forwarding.voicemailDescription')}</InfoText>
          </Col>
          <Col col={12}>
            <TextBox
              value={voicemailEmail}
              label={t('doorman.forwarding.voicemailEmail')}
              onChange={(e: any) => setNewData('voicemailEmail', e.target.value)}
              disabled={!voicemailActive}
            />
          </Col>
        </Row>
      </PaymentSection>

      <Recording
        color={color}
        recording={recording}
        setRecording={(rec: IRecording) => { setNewData('recording', rec); }}
        forwardFrom={forwardingNumbers[0]?.doormanNumber}
        forwardTo={forwardingNumbers[0]?.forwardTo[0]}
      />

      <OpeningHours
        color={color}
        openingHours={openingHours}
        setOpeningHours={(hours: IOpeningHours) => { setNewData('openingHours', hours); }}
      />

      <PaymentSection
        fullWidth
        noSpacingTop
      >
        <Row>
          <Col col={5} orderTablet={2}>
            <Button
              onClick={() => cancel()}
              background="white"
              disabled={loading}
              text="dark"
              big
            >
              {t('doorman.buttons.cancel')}
            </Button>
          </Col>
          <Col col={6} push={1} orderTablet={1}>
            <Button
              background={color}
              big
              fill
              loading={loading}
              disabled={loading}
              onClick={changeSettings}
            >
              {t('doorman.buttons.confirm')}
            </Button>
          </Col>
        </Row>
      </PaymentSection>
    </Payment>
  );
};

const Recording = ({ recording, setRecording, color, forwardFrom, forwardTo }: IRecordingProps) => {
  const { t } = useTranslation('stillingar');

  return (
    <PaymentSection
      title={t('doorman.recording.title')}
      subtitle={t('doorman.recording.subtitle')}
      fullWidth
      noSpacingTop
      smallerTitle
    >
      <FormDropdown
        noEmpty
        label={t('doorman.recording.title')}
        defaultValue={recording.type}
        onSelect={(value: 'generated' | 'recording') => setRecording({ ...recording, type: value })}
      >
        {['generated', 'recording'].map(value => (
          <option key={value} value={value}>{t(`doorman.recording.${value}`)}</option>
        ))}
      </FormDropdown>

      {recording.type === 'recording' && (
        <PaymentSection fullWidth noSpacingTop>
          <InfoText>
            {t('doorman.recording.description', { forwardTo, forwardFrom })}
          </InfoText>
        </PaymentSection>
      )}

      {recording.type === 'generated' && (
        <FormDropdown
          noEmpty
          label={t('doorman.recording.chooseGeneratedPerson')}
          defaultValue={recording.gender}
          onSelect={(value: 'female' | 'male') => setRecording({ ...recording, gender: value })}
        >
          {['female', 'male'].map(value => (
            <option key={value} value={value}>{t(`doorman.recording.${value}`)}</option>
          ))}
        </FormDropdown>
      )}

      {recording.type === 'generated' && (
        <TextBox
          label={t('doorman.recording.generatedText')}
          isTextarea
          value={recording.generatedValue}
          placeholder={t('doorman.recording.generatedTextPlaceholder')}
          onChange={(e: any) => setRecording({ ...recording, generatedValue: e.target.value })}
        />
      )}

      <Row>
        <Col col={4}>
          {t('doorman.recording.readOpeninghours')}
        </Col>
        <Col col={2}>
          <Switch
            isOn={recording.readOpeningHours}
            onToggle={() => setRecording({ ...recording, readOpeningHours: !recording.readOpeningHours })}
            color={color}
          />
        </Col>
        <Col col={6}>
          <InfoText>{t('doorman.recording.readOpeninghoursDescription')}</InfoText>
        </Col>
      </Row>
    </PaymentSection>
  );
};

const OpeningHours = ({ color, openingHours, setOpeningHours }: IOpeningHoursProps) => {
  const { t } = useTranslation('stillingar');
  const { override } = openingHours;
  const [days] = useState(openingHours.days.map(({ day, openingInfo }) =>
    ({ day, openingInfo: openingInfo.map(({ opens, closes }) => ({ opens, closes })) })));

  const toggle = ({ day, openingInfo }: IDay) => {
    const newArr = [...days];

    newArr[day].openingInfo = openingInfo?.length > 0
      ? []
      : [{ opens: '00:00', closes: '00:00' }];

    setOpeningHours({ override, days: newArr });
  };

  const changeHours = (key: 'opens' | 'closes', { day }: IDay, periodIndex: number, value: string) => {
    const newArr = [...days];

    newArr[day].openingInfo[periodIndex][key] = value;

    setOpeningHours({ override, days: newArr });
  };

  const addPeriod = ({ day }: IDay) => {
    const newArr = [...days];

    newArr[day].openingInfo.push({ opens: '', closes: '' });

    setOpeningHours({ override, days: newArr });
  };

  const removePeriod = (openingIndex: number, periodIndex: number) => {
    const newArr = [...days];

    newArr[openingIndex].openingInfo.splice(periodIndex, 1);

    setOpeningHours({ override, days: newArr });
  };

  return (
    <PaymentSection
      smallerTitle
      fullWidth
      title={t('doorman.openingHours.title')}
      subtitle={t('doorman.openingHours.subtitle')}
      color={color}
    >
      <FormDropdown
        onSelect={(value: 'no' | 'open' | 'closed') => setOpeningHours({ override: value, days })}
        label={t('doorman.openingHours.override')}
        defaultValue={override}
        noEmpty
      >
        {['no', 'open', 'closed'].map(value => (
          <option key={value} value={value}>{t(`doorman.openingHours.${value}`)}</option>
        ))}
      </FormDropdown>

      {override === 'no' && (
        <ServiceOpeningHours
          days={days}
          color={color}
          changeHours={changeHours}
          removePeriod={removePeriod}
          addPeriod={addPeriod}
          toggle={toggle}
        />
      )}
    </PaymentSection>
  );
};

const Doorman = ({ subscriptionId, authentication }: IDoormanProps) => {
  const { t } = useTranslation('stillingar');
  const { accountInput } = authentication;
  const { loading, error, data } = useQuery<IUserData>(FORWARDING_SETTINGS, { variables: { accountInput, subscriptionId } });

  if (loading) {
    return (
      <Settings subscriptionId={subscriptionId}>
        <div>{t('loading')}</div>
      </Settings>
    );
  }

  if (error || !data?.me?.subscriptions?.subscriptions[0]?.forwardingSettings ||
    isEmpty(data?.me?.subscriptions?.subscriptions[0]?.forwardingSettings.forwardingNumbers)) {
    return (
      <Settings subscriptionId={subscriptionId}>
        <div>{t('error')}</div>
      </Settings>
    );
  }

  const { me: { subscriptions: { subscriptions } } } = data;
  const { forwardingSettings } = subscriptions[0];

  return (
    <Settings subscriptionId={subscriptionId}>
      <Forwarding
        color={COLOR}
        subscriptionId={subscriptionId}
        forwardingSettings={forwardingSettings}
      />
    </Settings>
  );
};

Doorman.getInitialProps = async ({ pathname, query }: any) => {
  return {
    pathname,
    subscriptionId: query.subscriptionId,
    namespacesRequired: ['stillingar'],
  };
};

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