import React from 'react';
import Box from './Box';
import uuid from 'uuid/v4';
import {
  SortableContainer,
  SortableElement,
  arrayMove,
} from 'react-sortable-hoc';
import DragHandle from './DragHandle';
import { FieldArray, Formik, Form as FormikForm, Field } from 'formik';
import PropTypes from 'proptypes';
import Select from 'react-select';
import 'react-select/dist/react-select.css';
import {
  filter, find, findIndex, flatten, forEach, identity, map, prop, propEq, reject, uniq, update
} from 'rambda';
import { insert, remove } from 'ramda';
import theme from '../theme';

const allJobs = {
  whatever: 'Vševediaci',

  marketResearch: 'Prieskum trhu',

  designUi: 'Dizajnér – UI',
  designUx: 'Dizajnér – UX',

  architect: 'Softwarový architekt',

  devFrontend: 'Developer – frontend',
  devBackend: 'Developer – backend',
  devDb: 'Developer – databázy',

  admin: 'Serverový administrátor',

  tester: 'Tester',

  analyst: 'Analytik',

  qa: 'Quality assurance',

  deployManager: 'Deploy'
};

const nextWorkerName = (rows) =>
  `${rows.length + 1}. pracovník`;

class Form extends React.PureComponent {
  state = {
    rows: [
      // {
      //   id: uuid(),
      //   name: 'pracovnik 1',
      //   preempt: false,
      //   linkedTo: null,
      //   jobs: [
      //     { id: uuid(), name: 'frontend', t: '', d: '', w: '', succ: [], anc: [], succOrAnc: 0 },
      //     { id: uuid(), name: 'backend', t: '', d: '', w: '', succ: [], anc: [], succOrAnc: 0 }
      //   ]
      // },
      // {
      //   id: uuid(),
      //   name: 'pracovnik 2',
      //   preempt: false,
      //   linkedTo: null,
      //   jobs: [
      //     { id: uuid(), name: 'frontend', t: '', d: '', w: '', succ: [], anc: [], succOrAnc: 0 },
      //     { id: uuid(), name: 'backend', t: '', d: '', w: '', succ: [], anc: [], succOrAnc: 0 }
      //   ]
      // }
    ]
  };

  onSubmit = (values) => {
    console.log(values);
  };

  addWorker = (setFieldValue, rows) => {
    const jobs = [{
      id: uuid(), name: 'whatever', t: '', d: '', w: '', succ: [], anc: [], succOrAnc: 0
    }];

    const updatedRows = [...rows, { id: uuid(), name: nextWorkerName(rows), jobs } ];
    setFieldValue('rows', updatedRows);
  };

  render() {
    return (
      <Formik initialValues={this.state} onSubmit={this.onSubmit} render={({ setFieldValue, values: { rows } }) => (
        <FormikForm>
          <h1>Konfigurácia projektu</h1>

          {rows.length ?
          <Box flexDirection="row" marginBottom={10}>
            <Box flexBasis="15%" flexShrink={0}><strong>Pracovník</strong></Box>
            <Box flexBasis="63%" flexShrink={0}><strong>Úlohy</strong></Box>
            <Box flexBasis="12%" flexShrink={0} align="center"><strong>Prerušenie</strong></Box>
          </Box> : null
          }

          <FieldArray name="rows" render={arrayHelpers => (
            <React.Fragment>
              {rows.map((row, i) => <Row key={i} {...row} arrayHelpers={arrayHelpers} prefix={`rows.${i}`} index={i} />)}
            </React.Fragment>
          )} />

          <Box flexDirection="row" marginBottom={10}>
            <Box
              flexShrink={0}
              onClick={() => this.addWorker(setFieldValue, rows)}
              {...theme.buttons.primary}
            >
              + Nový pracovník
            </Box>
          </Box>

          <Box as="button" margin="auto" width="20rem" alignItems="center" padding={5}
               {...theme.buttons.primary} backgroundColor="#C89C93">
            <Box fontSize="1rem">Cieľ:</Box>
            <Box as="select" marginTop={5}>
              <option>Minimalizovať počet oneskorených úloh</option>
              <option>2...</option>
            </Box>
          </Box>
        </FormikForm>
      )}>
      </Formik>
    )
  }
}

const SortableJob = SortableElement(
  class extends React.PureComponent {
    static contextTypes = {
      formik: PropTypes.object
    };

    handleSelectChange = (type, selectedPairs) => {
      const { prefix } = this.props;
      const { formik: { setFieldValue } } = this.context;

      const selected = map(prop('value'), selectedPairs);

      setFieldValue(`${prefix}.${type}`, selected);
    };

    deleteJob = () => {
      const { rowIndex, myIndex } = this.props;
      const { formik: { setFieldValue, values: { rows } } } = this.context;

      const jobs = filter(identity, update(myIndex, null, rows[rowIndex].jobs));

      if (jobs.length) {
        setFieldValue(`rows.${rowIndex}.jobs`, jobs);
      } else {
        const updatedRows = filter(identity, update(rowIndex, null, rows));
        setFieldValue(`rows`, updatedRows);
      }
    };

    render() {
      const { myIndex, rowIndex, prefix, job, existingJobs: _existingJobs } = this.props;
      const { formik: { values: { rows } } } = this.context;

      const existingJobs = map(
        value => {
          const [idRow, idJob] = value.split(':');
          const row = find(propEq('id', idRow), rows);
          const jobName = find(propEq('id', idJob), row.jobs).name;

          return ({ value, label: `${row.name} – ${allJobs[jobName]}` });
        },
        reject(
          value => {
            const [, idJob] = value.split(':');
            return idJob === job.id;
          },
          _existingJobs
        )
      );

      return (
        <Box
          flexDirection="row"
          marginBottom={10}
          paddingBottom={10}
          className="sortable-inactive"
        >
          <Box marginRight={10} fontSize="1.5rem" width={20}>
            {!rows[rowIndex].linkedTo &&
            <DragHandle/>
            }
          </Box>

          <Box flex={1} padding={1}>
            <Box width={200} marginBottom={10} flexDirection="row">
              <Field component="select" name={`${prefix}.name`} disabled={rows[rowIndex].linkedTo}>
               {Object.keys(allJobs).map(key => (
                  <option value={key} key={key}>{allJobs[key]}</option>
                ))}
              </Field>
              {!rows[rowIndex].linkedTo &&
              <Box cursor="pointer" onClick={this.deleteJob} marginLeft={5} color="red">✕</Box>
              }
            </Box>

            <Box flexDirection="row" justifyContent="space-between" marginBottom={10}>
              <Box flexBasis="30%">
                <label>
                  Trvanie: <br />
                  <Field type="number" step={1} name={`${prefix}.t`} style={{ width: '100%' }} />
                </label>
              </Box>
              <Box flexBasis="30%">
                <label>
                  Deadline: <br />
                  <Field type="number" step={1} name={`${prefix}.d`} style={{ width: '100%' }} />
                </label>
              </Box>
              <Box flexBasis="30%">
                <label>
                  Váha: <br />
                  <Field type="number" min={0} max={1} step={0.1} name={`${prefix}.w`} style={{ width: '100%' }} />
                </label>
              </Box>
            </Box>

            <Box>
              <Box as="label" flexDirection="row" marginBottom={5}>
                <Field type="radio" name={`${prefix}.succOrAnc`} value={0} checked={job.succOrAnc == '0'} disabled={rows[rowIndex].linkedTo}/> Bez nadväznosti
              </Box>
              <Box marginBottom={5}>
                <Box as="label" flexDirection="row">
                  <Field type="radio" name={`${prefix}.succOrAnc`} value={1} checked={job.succOrAnc == '1'} disabled={rows[rowIndex].linkedTo} /> Predchodcovia
                </Box>
                <Box flex={1} marginLeft={10} marginTop={5}>
                  <Select
                    disabled={job.succOrAnc != '1' || rows[rowIndex].linkedTo}
                    multi
                    onChange={e => this.handleSelectChange('anc', e)}
                    options={existingJobs}
                    removeSelected
                    value={job.anc}
                  />
                </Box>
              </Box>
              <Box>
                <Box as="label" flexDirection="row">
                  <Field type="radio" name={`${prefix}.succOrAnc`} value={2} checked={job.succOrAnc == '2'} disabled={rows[rowIndex].linkedTo} /> Nasledovníci
                </Box>
                <Box flex={1} marginLeft={10} marginTop={5}>
                  <Select
                    disabled={job.succOrAnc != '2' || rows[rowIndex].linkedTo}
                    multi
                    onChange={e => this.handleSelectChange('succ', e)}
                    options={existingJobs}
                    removeSelected
                    value={job.succ}
                  />
                </Box>
              </Box>
            </Box>
          </Box>
        </Box>
      );
    }
  });

const SortableList = SortableContainer(({ jobs, existingJobs, prefix, rowIndex, draggingIndex }) => (
  <div>
    {jobs.map((job, i) => (
      <SortableJob
        key={job.id}
        index={i}
        myIndex={i}
        rowIndex={rowIndex}
        job={job}
        prefix={`${prefix}.${i}`}
        existingJobs={existingJobs}
        isDragging={draggingIndex === i}
      />
    ))}
  </div>
));

class Row extends React.PureComponent {
  static contextTypes = {
    formik: PropTypes.object
  };

  state = {
    draggingIndex: -1
  };

  onSortStart = ({ index }) => {
    this.setState({ draggingIndex: index });
  };

  onSortEnd = ({ oldIndex, newIndex }) => {
    const { prefix, index } = this.props;
    const { formik: { setFieldValue, values: { rows }} } = this.context;

    const updatedJobs = arrayMove(rows[index].jobs, oldIndex, newIndex);

    setFieldValue(`${prefix}.jobs`, updatedJobs);
    this.setState({ draggingIndex: -1 });
  };

  findExistingJobs = () => {
    const { formik: { values: { rows } } } = this.context;

    const existingJobs = uniq(
      flatten(
        map(({ id: idRow, jobs }) =>
          map(({ id: idJob }) => `${idRow}:${idJob}`, jobs),
        rows)
      )
    );

    return existingJobs;
  };

  addJob = () => {
    const { index } = this.props;
    const { formik: { setFieldValue, values: { rows } } } = this.context;
    const newJob = {
      id: uuid(), name: 'whatever', t: '', d: '', w: '', succ: [], anc: [], succOrAnc: 0
    };

    const jobs = [...rows[index].jobs, newJob];

    setFieldValue(`rows.${index}.jobs`, jobs);
  };

  deleteRow = () => {
    const { index, id } = this.props;
    const { formik: { setFieldValue, values: { rows } } } = this.context;

    let newRows = remove(index, 1, rows);

    const alsoDelete = filter(propEq('linkedTo', id), rows);

    forEach(row => {
      const index = findIndex(propEq('id', row.id), newRows);
      newRows = remove(index, 1, newRows);
    }, alsoDelete);

    setFieldValue('rows', newRows);
  };

  duplicate = () => {
    const { id, index, name, preempt, jobs } = this.props;
    const { formik: { setFieldValue, values: { rows } } } = this.context;

    const jobsCopy = map(job => ({ ...job }), jobs);
    const newRow = { id: uuid(), name: `${name} – kópia`, preempt, linkedTo: id, jobs: jobsCopy };

    const updatedRows = insert(index + 1, newRow, rows);

    setFieldValue('rows', updatedRows);
  };

  render() {
    const { index, prefix, name, preempt, linkedTo, jobs } = this.props;
    const { draggingIndex } = this.state;

    const existingJobs = this.findExistingJobs();

    return (
      <Box flexDirection="row" marginBottom={30} padding={10} className="row">
        <Box flexBasis="15%" flexShrink={0} paddingRight={10}>
          <strong>{name}</strong>
          <Box cursor="pointer" onClick={this.deleteRow} color="red">✕</Box>
        </Box>
        <Box flexBasis="63%" flexShrink={0}>
          <FieldArray render={() => (
            <SortableList
              helperClass="sorting"
              onSortStart={this.onSortStart}
              onSortEnd={this.onSortEnd}
              jobs={jobs}
              useDragHandle={true}
              existingJobs={existingJobs}
              prefix={`${prefix}.jobs`}
              rowIndex={index}
              draggingIndex={draggingIndex}
            />
          )} />
          {!linkedTo &&
          <Box onClick={this.addJob} {...theme.buttons.secondary} alignSelf="flex-start">
            + Nová úloha
          </Box>
          }
        </Box>
        <Box flexBasis="12%" flexShrink={0}>
          <Box as="label" alignItems="center" paddingTop={10}>
            <Field type="checkbox" name={`${prefix}.preempt`} disabled={linkedTo} />
            <Box as="em" color="gray" textAlign="center" padding={10} fontSize="0.9em">
              Úlohy pracovníka možno prerušiť
            </Box>
          </Box>
        </Box>
        <Box alignItems="flex-end">
          {!linkedTo &&
          <Box
            onClick={this.duplicate}
            {...theme.buttons.tertiary}
            flexDirection="row"
            alignItems="center"
            flexWrap="wrap"
            justifyContent="center"
            paddingVertical={1}
          >
            <span style={{ fontSize: '1.8em', paddingRight: '0.2em' }}>⩇</span> Duplikovať
          </Box>
          }
        </Box>
      </Box>
    )
  }
}

export default Form;