import { useMutation, useQuery, gql } from "@apollo/client";
import { Dialog, DialogContent, SvgIcon, IconButton } from '@mui/material'
import { makeStyles } from '@mui/material/styles'
import classnames from 'classnames'
import { Form, Formik, FastField } from 'formik'
import {QRCodeSVG as QRCode} from 'qrcode.react'
import * as R from 'ramda'
import React, { memo, useState, useEffect, useRef } from 'react'
import Title from 'src/components/Title'
import Sidebar from 'src/components/layout/Sidebar'
import { Info2, P } from 'src/components/typography'
import CameraIcon from 'src/styling/icons/ID/photo/zodiac.svg?react'
import CloseIcon from 'src/styling/icons/action/close/zodiac.svg?react'
import CompleteStageIconSpring from 'src/styling/icons/stage/spring/complete.svg?react'
import CompleteStageIconZodiac from 'src/styling/icons/stage/zodiac/complete.svg?react'
import CurrentStageIconZodiac from 'src/styling/icons/stage/zodiac/current.svg?react'
import EmptyStageIconZodiac from 'src/styling/icons/stage/zodiac/empty.svg?react'
import WarningIcon from 'src/styling/icons/warning-icon/comet.svg?react'
import * as Yup from 'yup'

import { Button } from 'src/components/buttons'
import { TextInput } from 'src/components/inputs/formik'
import { primaryColor } from 'src/styling/variables'

import styles from './styles'

const SAVE_CONFIG = gql`
  mutation createPairingTotem($name: String!) {
    createPairingTotem(name: $name)
  }
`
const GET_MACHINES = gql`
  {
    machines {
      name
      deviceId
    }
  }
`

const useStyles = makeStyles(styles)

const getSize = R.compose(R.length, R.pathOr([], ['machines']))

const QrCodeComponent = ({ classes, qrCode, name, count, onPaired }) => {
  const timeout = useRef(null)
  const CLOSE_SCREEN_TIMEOUT = 2000
  const { data } = useQuery(GET_MACHINES, { pollInterval: 10000 })

  useEffect(() => {
    return () => {
      if (timeout.current) {
        clearTimeout(timeout.current)
      }
    }
  }, [])

  const addedMachine = data?.machines?.find(m => m.name === name)
  const hasNewMachine = getSize(data) > count && addedMachine
  if (hasNewMachine) {
    timeout.current = setTimeout(
      () => onPaired(addedMachine),
      CLOSE_SCREEN_TIMEOUT
    )
  }

  return (
    <>
      <Info2 className={classes.qrTitle}>
        Scan QR code with your new cryptomat
      </Info2>
      <div className={classes.qrCodeWrapper}>
        <div className={classes.qrCodeImageWrapper} data-cy={qrCode}>
          <QRCode
            size={280}
            fgColor={primaryColor}
            marginSize={4}
            value={qrCode}
            className={classes.qrCodeBorder}
          />
          <div className={classes.qrCodeScanMessage}>
            <CameraIcon />
            <P noMargin>Snap a picture and scan</P>
          </div>
        </div>
        <div className={classes.qrTextWrapper}>
          <div className={classes.qrTextInfoWrapper}>
            <div className={classes.qrTextIcon}>
              <WarningIcon />
            </div>
            <div className={classes.textWrapper}>
              <P className={classes.qrText}>
                To pair the machine you need scan the QR code with your machine.
                To do this either snap a picture of this QR code or download it
                through the button above and scan it with the scanning bay on
                your machine.
              </P>
            </div>
          </div>
          {hasNewMachine && (
            <div className={classes.successMessageWrapper}>
              <div className={classes.successMessageIcon}>
                <CompleteStageIconSpring />
              </div>
              <Info2 className={classes.successMessage}>
                Machine has been successfully paired!
              </Info2>
            </div>
          )}
        </div>
      </div>
    </>
  )
}

const initialValues = {
  name: ''
}

const validationSchema = Yup.object().shape({
  name: Yup.string()
    .required('Machine name is required.')
    .max(50)
    .test(
      'unique-name',
      'Machine name is already in use.',
      (value, context) =>
        !R.includes(
          R.toLower(value),
          R.map(R.toLower, context.options.context.machineNames)
        )
    )
})

const MachineNameComponent = ({ nextStep, classes, setQrCode, setName }) => {
  const [register] = useMutation(SAVE_CONFIG, {
    onCompleted: ({ createPairingTotem }) => {
      if (process.env.NODE_ENV === 'development') {
        console.log(`totem: "${createPairingTotem}" `)
      }
      setQrCode(createPairingTotem)
      nextStep()
    },
    onError: e => console.log(e)
  })

  const { data } = useQuery(GET_MACHINES)
  const machineNames = R.map(R.prop('name'), data?.machines || {})

  const uniqueNameValidator = value => {
    try {
      validationSchema.validateSync(value, {
        context: { machineNames: machineNames }
      })
    } catch (error) {
      return error
    }
  }

  return (
    <>
      <Info2 className={classes.nameTitle}>
        Machine Name (ex: Coffee shop 01)
      </Info2>
      <Formik
        validateOnBlur={false}
        validateOnChange={false}
        initialValues={initialValues}
        validate={uniqueNameValidator}
        onSubmit={({ name }) => {
          setName(name)
          register({ variables: { name } })
        }}>
        {({ errors }) => (
          <Form className={classes.form}>
            <div>
              <FastField
                name="name"
                label="Enter machine name"
                component={TextInput}
              />
            </div>
            {errors && <P className={classes.errorMessage}>{errors.message}</P>}
            <div className={classes.button}>
              <Button type="submit">Submit</Button>
            </div>
          </Form>
        )}
      </Formik>
    </>
  )
}

const steps = [
  {
    label: 'Machine name',
    component: MachineNameComponent
  },
  {
    label: 'Scan QR code',
    component: QrCodeComponent
  }
]

const renderStepper = (step, it, idx, classes) => {
  const active = step === idx
  const past = idx < step
  const future = idx > step

  return (
    <div className={classes.item}>
      <span
        className={classnames({
          [classes.itemText]: true,
          [classes.itemTextActive]: active,
          [classes.itemTextPast]: past
        })}>
        {it.label}
      </span>
      {active && <CurrentStageIconZodiac />}
      {past && <CompleteStageIconZodiac />}
      {future && <EmptyStageIconZodiac />}
      {idx < steps.length - 1 && (
        <div
          className={classnames({
            [classes.stepperPath]: true,
            [classes.stepperPast]: past
          })}></div>
      )}
    </div>
  )
}

const AddMachine = memo(({ close, onPaired }) => {
  const classes = useStyles()
  const { data } = useQuery(GET_MACHINES)
  const [qrCode, setQrCode] = useState('')
  const [name, setName] = useState('')
  const [step, setStep] = useState(0)
  const count = getSize(data)

  const Component = steps[step].component

  return (
    <div>
      <Dialog
        fullScreen
        className={classes.dialog}
        open={true}
        aria-labelledby="form-dialog-title">
        <DialogContent className={classes.dialog}>
          <div className={classes.wrapper}>
            <div className={classes.headerDiv}>
              <Title>Add Machine</Title>
              <IconButton disableRipple={true} onClick={close}>
                <SvgIcon color="error">
                  <CloseIcon />
                </SvgIcon>
              </IconButton>
            </div>
            <div className={classes.contentDiv}>
              <Sidebar>
                {steps.map((it, idx) => renderStepper(step, it, idx, classes))}
              </Sidebar>
              <div className={classes.contentWrapper}>
                <Component
                  classes={classes}
                  nextStep={() => setStep(1)}
                  count={count}
                  onPaired={onPaired}
                  qrCode={qrCode}
                  setQrCode={setQrCode}
                  name={name}
                  setName={setName}
                />
              </div>
            </div>
          </div>
        </DialogContent>
      </Dialog>
    </div>
  )
})

export default AddMachine
