import { useQuery, useMutation } from '@apollo/react-hooks'
import { makeStyles } from '@material-ui/core'
import classnames from 'classnames'
import { Form, Formik, Field as FormikField } from 'formik'
import gql from 'graphql-tag'
import * as R from 'ramda'
import React, { useState } from 'react'
import * as Yup from 'yup'

import ErrorMessage from 'src/components/ErrorMessage'
import PromptWhenDirty from 'src/components/PromptWhenDirty'
import { Link, IconButton } from 'src/components/buttons'
import { Switch } from 'src/components/inputs'
import { TextInput } from 'src/components/inputs/formik'
import { H4, Info2, Info3, Label2, Label3, P } from 'src/components/typography'
import { ReactComponent as EditIcon } from 'src/styling/icons/action/edit/enabled.svg'
import { fromNamespace, toNamespace, namespaces } from 'src/utils/config'

import { global, fieldStyles } from './OperatorInfo.styles'

const useFieldStyles = makeStyles(fieldStyles)

const Field = ({
  editing,
  name,
  width,
  placeholder,
  label,
  value,
  multiline = false,
  rows,
  onFocus,
  ...props
}) => {
  const classes = useFieldStyles()

  const classNames = {
    [classes.field]: true,
    [classes.notEditing]: !editing,
    [classes.notEditingSingleLine]: !editing && !multiline,
    [classes.notEditingMultiline]: !editing && multiline
  }

  return (
    <div className={classnames(classNames)}>
      {!editing && (
        <>
          <Label3>{label}</Label3>
          <Info3>{value}</Info3>
        </>
      )}
      {editing && (
        <FormikField
          id={name}
          name={name}
          component={TextInput}
          width={width}
          placeholder={placeholder}
          type="text"
          label={label}
          multiline={multiline}
          rows={rows}
          rowsMax="6"
          onFocus={onFocus}
          {...props}
        />
      )}
    </div>
  )
}

const GET_CONFIG = gql`
  query getData {
    config
  }
`

const SAVE_CONFIG = gql`
  mutation Save($config: JSONObject) {
    saveConfig(config: $config)
  }
`

const useTermsConditionsStyles = makeStyles(global)

const TermsConditions = () => {
  const [error, setError] = useState(null)
  const [editing, setEditing] = useState(false)
  const [saveConfig] = useMutation(SAVE_CONFIG, {
    onCompleted: () => {
      setError(null)
      setEditing(false)
    },
    refetchQueries: () => ['getData'],
    onError: e => setError(e)
  })

  const classes = useTermsConditionsStyles()

  const { data } = useQuery(GET_CONFIG)

  const termsAndConditions =
    data?.config && fromNamespace(namespaces.TERMS_CONDITIONS, data.config)
  const formData = termsAndConditions ?? {}
  const showOnScreen = termsAndConditions?.active ?? false
  const addDelayOnScreen = termsAndConditions?.delay ?? false
  const tcPhoto = termsAndConditions?.tcPhoto ?? false

  const save = it =>
    saveConfig({
      variables: { config: toNamespace(namespaces.TERMS_CONDITIONS, it) }
    })

  const fields = [
    {
      name: 'title',
      label: 'Screen title',
      value: formData.title ?? '',
      width: 282
    },
    {
      name: 'text',
      label: 'Text content',
      value: formData.text ?? '',
      width: 502,
      multiline: true,
      rows: 6
    },
    {
      name: 'acceptButtonText',
      label: 'Accept button text',
      value: formData.acceptButtonText ?? '',
      placeholder: 'I accept',
      width: 282
    },
    {
      name: 'cancelButtonText',
      label: 'Cancel button text',
      value: formData.cancelButtonText ?? '',
      placeholder: 'Cancel',
      width: 282
    }
  ]

  const findField = name => R.find(R.propEq('name', name))(fields)
  const findValue = name => findField(name).value

  const initialValues = {
    title: findValue('title'),
    text: findValue('text'),
    acceptButtonText: findValue('acceptButtonText'),
    cancelButtonText: findValue('cancelButtonText')
  }

  const validationSchema = Yup.object().shape({
    title: Yup.string('The screen title must be a string')
      .required('The screen title is required')
      .max(50, 'Too long'),
    text: Yup.string('The text content must be a string').required(
      'The text content is required'
    ),
    acceptButtonText: Yup.string('The accept button text must be a string')
      .required('The accept button text is required')
      .max(50, 'The accept button text is too long'),
    cancelButtonText: Yup.string('The cancel button text must be a string')
      .required('The cancel button text is required')
      .max(50, 'The cancel button text is too long')
  })

  return (
    <>
      <div className={classes.header}>
        <H4>Terms &amp; Conditions</H4>
      </div>
      <div className={classes.switchRow}>
        <P>Show on screen</P>
        <div className={classes.switch}>
          <Switch
            checked={showOnScreen}
            onChange={event =>
              save({
                active: event.target.checked
              })
            }
          />
          <Label2>{showOnScreen ? 'Yes' : 'No'}</Label2>
        </div>
      </div>
      <div className={classes.switchRow}>
        <P>
          Capture customer photo on acceptance <br /> of Terms & Conditions
          screen
        </P>
        <div className={classes.switch}>
          <Switch
            checked={tcPhoto}
            onChange={event =>
              save({
                tcPhoto: event.target.checked
              })
            }
          />
          <Label2>{tcPhoto ? 'Yes' : 'No'}</Label2>
        </div>
      </div>
      <div className={classes.switchRow}>
        <P>Add 7 seconds delay on screen</P>
        <div className={classes.switch}>
          <Switch
            checked={addDelayOnScreen}
            onChange={event =>
              save({
                delay: event.target.checked
              })
            }
          />
          <Label2>{addDelayOnScreen ? 'Yes' : 'No'}</Label2>
        </div>
      </div>
      <div className={classes.header}>
        <Info2>Info card</Info2>
        {!editing && (
          <IconButton
            className={classes.transparentButton}
            onClick={() => setEditing(true)}>
            <EditIcon />
          </IconButton>
        )}
      </div>
      <Formik
        validateOnBlur={false}
        validateOnChange={false}
        enableReinitialize
        initialValues={initialValues}
        validationSchema={validationSchema}
        onSubmit={values => save(values)}
        onReset={() => {
          setEditing(false)
          setError(null)
        }}>
        {({ errors }) => (
          <Form>
            <PromptWhenDirty />
            {fields.map((f, idx) => (
              <div className={classes.row} key={idx}>
                <Field
                  editing={editing}
                  name={f.name}
                  width={f.width}
                  placeholder={f.placeholder}
                  label={f.label}
                  value={f.value}
                  multiline={f.multiline}
                  rows={f.rows}
                  onFocus={() => setError(null)}
                />
              </div>
            ))}
            <div className={classnames(classes.row, classes.submit)}>
              {editing && (
                <>
                  <Link color="primary" type="submit">
                    Save
                  </Link>
                  <Link color="secondary" type="reset">
                    Cancel
                  </Link>
                  {!R.isEmpty(errors) && (
                    <ErrorMessage>{R.head(R.values(errors))}</ErrorMessage>
                  )}
                  {error && <ErrorMessage>Failed to save changes</ErrorMessage>}
                </>
              )}
            </div>
          </Form>
        )}
      </Formik>
    </>
  )
}

export default TermsConditions
