import {
  Button,
  createStyles,
  Dialog,
  DialogActions,
  DialogContent,
  DialogTitle,
  FormControl,
  FormControlLabel,
  FormLabel,
  makeStyles,
  Paper,
  Radio,
  Theme,
  Toolbar,
  Typography,
} from '@material-ui/core'
import { Edit } from '@material-ui/icons'
import { Field, Formik } from 'formik'
import { RadioGroup as FormikMuiRadioGroup, TextField } from 'formik-material-ui'
import { useSnackbar } from 'notistack'
import React, { useState } from 'react'
import * as yup from 'yup'

import ExperimentsApi from 'src/api/ExperimentsApi'
import { serverErrorMessage } from 'src/api/HttpResponseError'
import LabelValueTable from 'src/components/general/LabelValueTable'
import LoadingButtonContainer from 'src/components/general/LoadingButtonContainer'
import * as Experiments from 'src/lib/experiments'
import { ExperimentFull, experimentFullSchema, yupPick } from 'src/lib/schemas'

const useStyles = makeStyles((theme: Theme) =>
  createStyles({
    title: {
      flexGrow: 1,
    },
    row: {
      margin: theme.spacing(5, 0),
      display: 'flex',
      alignItems: 'center',
      '&:first-of-type': {
        marginTop: theme.spacing(3),
      },
    },
  }),
)

/**
 * Renders the conclusion information of an experiment in a panel component.
 *
 * @param experiment - The experiment with the conclusion information.
 * @param experimentReloadRef - A ref for reloading the experiment.
 */
function ConclusionsPanel({
  className,
  experiment,
  experimentReloadRef,
}: {
  className?: string
  experiment: ExperimentFull
  experimentReloadRef: React.MutableRefObject<() => void>
}): JSX.Element {
  const classes = useStyles()

  const deployedVariation = Experiments.getDeployedVariation(experiment)
  const data = [
    { label: 'Reason the experiment ended', value: experiment.endReason },
    {
      label: 'Conclusion URL',
      value: !!experiment.conclusionUrl && (
        <a href={experiment.conclusionUrl} rel='noopener noreferrer' target='_blank'>
          {experiment.conclusionUrl}
        </a>
      ),
    },
    { label: 'Deployed variation', value: deployedVariation?.name },
  ]

  // Edit Modal
  const { enqueueSnackbar } = useSnackbar()
  const [isEditing, setIsEditing] = useState<boolean>(false)
  const editInitialValues = {
    endReason: experiment.endReason ?? '',
    conclusionUrl: experiment.conclusionUrl ?? '',
    deployedVariationId: String(experiment.deployedVariationId ?? ''),
  }
  const onEdit = () => setIsEditing(true)
  const onCancelEdit = () => setIsEditing(false)
  const onSubmitEdit = async ({ experiment: formValues }: { experiment: typeof editInitialValues }) => {
    try {
      await ExperimentsApi.patch(experiment.experimentId, {
        endReason: formValues.endReason,
        conclusionUrl: formValues.conclusionUrl === '' ? undefined : formValues.conclusionUrl,
        deployedVariationId: formValues.deployedVariationId ? Number(formValues.deployedVariationId) : undefined,
      })
      enqueueSnackbar('Experiment Updated!', { variant: 'success' })
      experimentReloadRef.current()
      setIsEditing(false)
    } catch (e) {
      // istanbul ignore next; shouldn't happen
      enqueueSnackbar(`Oops! Something went wrong while trying to update your experiment. ${serverErrorMessage(e)}`, {
        variant: 'error',
      })
    }
  }

  return (
    <Paper className={className}>
      <Toolbar>
        <Typography className={classes.title} color='textPrimary' variant='h3'>
          Conclusions
        </Typography>
        <Button onClick={onEdit} variant='outlined' aria-label='Edit Conclusion'>
          <Edit />
          Edit
        </Button>
      </Toolbar>

      <LabelValueTable data={data} />

      <Dialog open={isEditing} fullWidth aria-labelledby='edit-experiment-conclusions-dialog-title'>
        <DialogTitle id='edit-experiment-conclusions-dialog-title'>Edit Experiment: Conclusions</DialogTitle>
        <Formik
          initialValues={{ experiment: editInitialValues }}
          validationSchema={yup.object({ experiment: yupPick(experimentFullSchema, Object.keys(editInitialValues)) })}
          onSubmit={onSubmitEdit}
        >
          {(formikProps) => (
            <form onSubmit={formikProps.handleSubmit}>
              <DialogContent>
                <div className={classes.row}>
                  <Field
                    component={TextField}
                    name='experiment.endReason'
                    id='experiment.endReason'
                    label='Reason the experiment ended'
                    placeholder='Completed successfully'
                    variant='outlined'
                    fullWidth
                    required
                    multiline
                    rows={2}
                    InputLabelProps={{
                      shrink: true,
                    }}
                  />
                </div>

                <div className={classes.row}>
                  <Field
                    component={TextField}
                    id='experiment.conclusionUrl'
                    name='experiment.conclusionUrl'
                    placeholder='https://your-p2-post-here/#conclusion-comment'
                    label='Conclusion URL'
                    variant='outlined'
                    fullWidth
                    InputLabelProps={{
                      shrink: true,
                    }}
                  />
                </div>

                <div className={classes.row}>
                  <FormControl component='fieldset'>
                    <FormLabel component='legend'>Deployed variation</FormLabel>
                    <Field component={FormikMuiRadioGroup} name='experiment.deployedVariationId'>
                      {experiment.variations.map((variation) => (
                        <FormControlLabel
                          key={variation.variationId}
                          value={String(variation.variationId)}
                          control={<Radio />}
                          label={variation.name}
                        />
                      ))}
                    </Field>
                  </FormControl>
                </div>
              </DialogContent>
              <DialogActions>
                <Button onClick={onCancelEdit} color='primary'>
                  Cancel
                </Button>
                <LoadingButtonContainer isLoading={formikProps.isSubmitting}>
                  <Button
                    type='submit'
                    variant='contained'
                    color='secondary'
                    disabled={formikProps.isSubmitting || !formikProps.isValid}
                  >
                    Save
                  </Button>
                </LoadingButtonContainer>
              </DialogActions>
            </form>
          )}
        </Formik>
      </Dialog>
    </Paper>
  )
}

export default ConclusionsPanel