import React, { useState } from 'react';
import { Link } from 'react-router-dom';
import Alert from '@mui/material/Alert';
import Button from '@mui/material/Button';
import Checkbox from '@mui/material/Checkbox';
import Grid from '@mui/material/Grid';
import FormControl from '@mui/material/FormControl';
import FormControlLabel from '@mui/material/FormControlLabel';
import FormGroup from '@mui/material/FormGroup';
import FormHelperText from '@mui/material/FormHelperText';
import Radio from '@mui/material/Radio';
import RadioGroup from '@mui/material/RadioGroup';
import TextField from '@mui/material/TextField';
import Typography from '@mui/material/Typography';

const intl = {
  es: {
    'value-missing-validation-error': 'Campo requerido',
    'array-missmatch': 'Respuesta incorrecta',
    'value-missmatch': 'Respuesta incorrecta',
    'confim-send': [
      '¿Estás segura de que quieres enviar tus respuestas?',
      'Recuerda que solo podrás enviar tus respuestas una vez.',
    ].join(' '),
    'form-results': () => {
      const pathnameParts = window.location.pathname.split('/');

      return (
        <Alert severity="success">
          Respuestas salvadas correctamente.
          {' '}
          {pathnameParts[2] === 'applications' && (
            <>
              <Link to={pathnameParts.slice(0, -2).join('/')}>
                Regresa a enviar tu postulación
              </Link>
              {' '}
              para completar el proceso.
            </>
          )}
        </Alert>
      );
    },
    'send-result': 'Enviar respuestas',
    'question-title': 'Preguntas',
  },
  pt: {
    'value-missing-validation-error': 'Campo obrigatório',
    'array-missmatch': 'Resposta incorreta',
    'value-missmatch': 'Resposta incorreta',
    'confim-send': [
      'Tem certeza de que deseja enviar suas respostas?',
      'Lembre-se de que você só pode enviar suas respostas uma vez.',
    ].join(' '),
    'form-results': () => {
      const pathnameParts = window.location.pathname.split('/');

      return (
        <Alert severity="success">
          Respostas salvas corretamente.
          {' '}
          {pathnameParts[2] === 'applications' && (
            <>
              <Link to={pathnameParts.slice(0, -2).join('/')}>
                Volte a Enviar sua inscrição
              </Link>
              {' '}
              para completar o processo.
            </>
          )}
        </Alert>
      );
    },
    'send-result': 'Enviar respostas',
    'question-title': 'Perguntas',
  },
};

const FormInput = ({
  challenge,
  lang,
  editorValue,
  setEditorValue,
  runAndSave,
  testResults,
}) => {
  const [validationErrors, setValidationErrors] = useState({});
  const { questions } = challenge.intl[lang];

  const buildTextField = ({ solution }, idx, isError, color) => {
    return (
      <TextField
        multiline={!!solution?.multiline}
        minRows={5}
        error={isError}
        color={color}
        disabled={!!testResults}
        value={editorValue[idx] || ''}
        onChange={(ev) => {
          setValidationErrors({});
          setEditorValue(prev => ({ ...prev, [idx]: ev.target.value }));
        }}
      />
    );
  };

  const buildCheckboxes = (question, idx, _, color) => {
    return (
      <FormGroup>
        {question.options.map((option, optionIdx) => (
          <FormControlLabel
            key={option}
            value={optionIdx}
            disabled={!!testResults}
            control={
              <Checkbox
                color={color}
                checked={!!editorValue[idx]?.includes(optionIdx)}
                onChange={(ev) => {
                  const val = parseInt(ev.target.value, 10);
                  setValidationErrors({});
                  setEditorValue(prev => ({
                    ...prev,
                    [idx]: (
                      ev.target.checked
                        ? (prev[idx] || []).concat(val)
                        : (prev[idx] || []).filter((item) => item !== val)
                    ),
                  }))
                }}
              />
            }
            label={
              <span dangerouslySetInnerHTML={{ __html: option }} />
            }
          />
        ))}
      </FormGroup>
    );
  };

  const buildRadioButtons = (question, idx, _, color) => {
    return (
      <RadioGroup
        name="radio-buttons-group"
        value={typeof editorValue[idx] === 'number' ? editorValue[idx] : ''}
        onChange={(ev) => {
          setValidationErrors({});
          setEditorValue(prev => ({
            ...prev,
            [idx]: parseInt(ev.target.value, 10),
          }));
        }}
      >
        {question.options.map((option, optionIdx) => (
          <FormControlLabel
            key={option}
            value={optionIdx}
            disabled={!!testResults}
            control={<Radio color={color} />}
            label={
              <span dangerouslySetInnerHTML={{ __html: option }} />
            }
          />
        ))}
      </RadioGroup>
    );
  };

  const validate = () => {
    const answers = editorValue || {};
    const validationErrors = questions.reduce(
      (memo, question, idx) => {
        const solution = question.solution || { required: true };
        const isNullVal = [null, undefined, ''].includes(answers[idx]);

        if (solution?.required && isNullVal) {
          return { ...memo, [idx]: 'value-missing-validation-error' };
        }

        if (solution?.validate) {
          const fn = new Function('v', `const fn = ${solution.validate}; return fn(v);`);
          const validateError = fn(answers[idx]);
          if (validateError) {
            return { ...memo, [idx]: validateError };
          }
        }

        return memo;
      },
      {},
    );

    setValidationErrors(validationErrors);

    if (Object.keys(validationErrors).length > 0) {
      return;
    }

    if (!confirm(intl[lang]['confim-send'])) {
      return;
    }

    runAndSave();
  };

  const onRef = (el) => {
    if (!el) {
      return;
    }

    const validationErrorsKeys = Object.keys(validationErrors);

    if (!validationErrorsKeys.length) {
      return;
    }

    const firstValidationError = validationErrorsKeys
      .map(idx => parseInt(idx, 10))
      .sort()
      .shift();

    el.querySelector(`#question-${firstValidationError} input`)?.focus();
  };

  return (
    <>
      <Typography variant="h2" sx={{ mt: 4, mb: 2 }}>
        {intl[lang]['question-title']}
      </Typography>
      <Grid container spacing={3} direction="column" ref={onRef} sx={{ mb: 3 }}>
        {questions.map((question, idx) => {
          const { title, options, solution } = question;
          const isMultipleChoice = Array.isArray(options) && options.length;
          const isMultiSolution = Array.isArray(solution) && solution.length > 1;
          const error = validationErrors[idx] || testResults?.errors[idx];
          const isError = !!error;
          const color = !!testResults && !isError ? 'success' : 'primary';

          const field = (
            !isMultipleChoice
              ? buildTextField(question, idx, isError, color)
              : isMultiSolution
                ? buildCheckboxes(question, idx, isError, color)
                : buildRadioButtons(question, idx, isError, color)
          );

          return (
            <Grid key={title} item id={`question-${idx}`}>
              <FormControl error={isError} focused color={color}>
                <Typography variant="h3">{question.title}</Typography>
                <Typography variant="body1">
                  <span dangerouslySetInnerHTML={{ __html: question.body }} />
                </Typography>
                {field}
                {isError && (
                  <FormHelperText>{intl[lang][error] || error}</FormHelperText>
                )}
              </FormControl>
            </Grid>);
        })}

        {!testResults && (
          <Grid item>
            <Button color="primary" onClick={validate}>
              {intl[lang]['send-result']}
            </Button>
          </Grid>
        )}

        {testResults && (
          <Grid item>
            {intl.es['form-results'](testResults)}
          </Grid>
        )}
      </Grid>
    </>
  );
};

export default FormInput;
