/* eslint-disable */
import * as React from 'react';
import { fetchByPath, validateField } from './utils';
import { School, Student } from '../models';
import { getOverrideProps, useDataStoreBinding } from '@aws-amplify/ui-react/internal';
import {
  Autocomplete,
  Badge,
  Button,
  Divider,
  Flex,
  Grid,
  Icon,
  ScrollView,
  Text,
  TextField,
  useTheme,
} from '@aws-amplify/ui-react';
import { DataStore } from 'aws-amplify';
function ArrayField({
  items = [],
  onChange,
  label,
  inputFieldRef,
  children,
  hasError,
  setFieldValue,
  currentFieldValue,
  defaultFieldValue,
  lengthLimit,
  getBadgeText,
}) {
  const { tokens } = useTheme();
  const [selectedBadgeIndex, setSelectedBadgeIndex] = React.useState();
  const [isEditing, setIsEditing] = React.useState();
  React.useEffect(() => {
    if (isEditing) {
      inputFieldRef?.current?.focus();
    }
  }, [isEditing]);
  const removeItem = async (removeIndex) => {
    const newItems = items.filter((value, index) => index !== removeIndex);
    await onChange(newItems);
    setSelectedBadgeIndex(undefined);
  };
  const addItem = async () => {
    if ((currentFieldValue !== undefined || currentFieldValue !== null || currentFieldValue !== '') && !hasError) {
      const newItems = [...items];
      if (selectedBadgeIndex !== undefined) {
        newItems[selectedBadgeIndex] = currentFieldValue;
        setSelectedBadgeIndex(undefined);
      } else {
        newItems.push(currentFieldValue);
      }
      await onChange(newItems);
      setIsEditing(false);
    }
  };
  const arraySection = (
    <React.Fragment>
      {!!items?.length && (
        <ScrollView height="inherit" width="inherit" maxHeight={'7rem'}>
          {items.map((value, index) => {
            return (
              <Badge
                key={index}
                style={{
                  cursor: 'pointer',
                  alignItems: 'center',
                  marginRight: 3,
                  marginTop: 3,
                  backgroundColor: index === selectedBadgeIndex ? '#B8CEF9' : '',
                }}
                onClick={() => {
                  setSelectedBadgeIndex(index);
                  setFieldValue(items[index]);
                  setIsEditing(true);
                }}
              >
                {getBadgeText ? getBadgeText(value) : value.toString()}
                <Icon
                  style={{
                    cursor: 'pointer',
                    paddingLeft: 3,
                    width: 20,
                    height: 20,
                  }}
                  viewBox={{ width: 20, height: 20 }}
                  paths={[
                    {
                      d: 'M10 10l5.09-5.09L10 10l5.09 5.09L10 10zm0 0L4.91 4.91 10 10l-5.09 5.09L10 10z',
                      stroke: 'black',
                    },
                  ]}
                  ariaLabel="button"
                  onClick={(event) => {
                    event.stopPropagation();
                    removeItem(index);
                  }}
                />
              </Badge>
            );
          })}
        </ScrollView>
      )}
      <Divider orientation="horizontal" marginTop={5} />
    </React.Fragment>
  );
  if (lengthLimit !== undefined && items.length >= lengthLimit && !isEditing) {
    return arraySection;
  }
  return (
    <React.Fragment>
      <Text>{label}</Text>
      {isEditing && children}
      {!isEditing ? (
        <>
          <Button
            onClick={() => {
              setIsEditing(true);
            }}
          >
            Add item
          </Button>
        </>
      ) : (
        <Flex justifyContent="flex-end">
          {(currentFieldValue || isEditing) && (
            <Button
              children="Cancel"
              type="button"
              size="small"
              onClick={() => {
                setFieldValue(defaultFieldValue);
                setIsEditing(false);
                setSelectedBadgeIndex(undefined);
              }}
            ></Button>
          )}
          <Button
            size="small"
            variation="link"
            color={tokens.colors.brand.primary[80]}
            isDisabled={hasError}
            onClick={addItem}
          >
            {selectedBadgeIndex !== undefined ? 'Save' : 'Add'}
          </Button>
        </Flex>
      )}
      {arraySection}
    </React.Fragment>
  );
}
export default function SchoolUpdateForm(props) {
  const { id, school, onSuccess, onError, onSubmit, onCancel, onValidate, onChange, overrides, ...rest } = props;
  const initialValues = {
    name: undefined,
    Students: [],
  };
  const [name, setName] = React.useState(initialValues.name);
  const [Students, setStudents] = React.useState(initialValues.Students);
  const [errors, setErrors] = React.useState({});

  const [schoolRecord, setSchoolRecord] = React.useState(school);
  const [linkedStudents, setLinkedStudents] = React.useState([]);
  const canUnlinkStudents = false;

  React.useEffect(() => {
    const queryData = async () => {
      const record = id ? await DataStore.query(School, id) : school;
      const linkedStudents = record ? await record.Students.toArray() : [];
      setLinkedStudents(linkedStudents);
      setSchoolRecord(record);
    };
    queryData();
  }, [id, school]);

  const [currentStudentsDisplayValue, setCurrentStudentsDisplayValue] = React.useState('');
  const [currentStudentsValue, setCurrentStudentsValue] = React.useState(undefined);

  const StudentsRef = React.createRef();

  const studentRecords = useDataStoreBinding({
    type: 'collection',
    model: Student,
  }).items;

  const resetStateValues = () => {
    const cleanValues = schoolRecord ? { ...initialValues, ...schoolRecord, Students: linkedStudents } : initialValues;
    setName(cleanValues.name);
    setStudents(cleanValues.Students ?? []);
    setCurrentStudentsValue(undefined);
    setCurrentStudentsDisplayValue('');
    setErrors({});
  };

  React.useEffect(resetStateValues, [schoolRecord, linkedStudents]);

  const getDisplayValue = {
    Students: (record) => record?.name,
  };

  const validations = {
    name: [],
    Students: [],
  };

  const runValidationTasks = async (fieldName, currentValue, getDisplayValue) => {
    const value = getDisplayValue ? getDisplayValue(currentValue) : currentValue;
    let validationResponse = validateField(value, validations[fieldName]);
    const customValidator = fetchByPath(onValidate, fieldName);
    if (customValidator) {
      validationResponse = await customValidator(value, validationResponse);
    }
    setErrors((errors) => ({ ...errors, [fieldName]: validationResponse }));
    return validationResponse;
  };
  return (
    <Grid
      as="form"
      rowGap="15px"
      columnGap="15px"
      padding="20px"
      onSubmit={async (event) => {
        event.preventDefault();
        let modelFields = {
          name,
          Students,
        };
        const validationResponses = await Promise.all(
          Object.keys(validations).reduce((promises, fieldName) => {
            if (Array.isArray(modelFields[fieldName])) {
              promises.push(
                ...modelFields[fieldName].map((item) =>
                  runValidationTasks(fieldName, item, getDisplayValue[fieldName]),
                ),
              );
              return promises;
            }
            promises.push(runValidationTasks(fieldName, modelFields[fieldName], getDisplayValue[fieldName]));
            return promises;
          }, []),
        );
        if (validationResponses.some((r) => r.hasError)) {
          return;
        }
        if (onSubmit) {
          modelFields = onSubmit(modelFields);
        }
        try {
          const studentsToLink = [];
          const studentsToUnLink = [];
          const studentsSet = new Set();
          const linkedStudentsSet = new Set();
          if (!canUnlinkStudents && studentsToUnLink.length > 0) {
            throw Error(`${original.id} cannot be unlinked from School because schoolID is a required field.`);
          }
          Students.forEach((r) => studentsSet.add(r.id));
          linkedStudents.forEach((r) => linkedStudentsSet.add(r.id));

          linkedStudents.forEach((r) => {
            if (!studentsSet.has(r.id)) {
              studentsToUnLink.push(r);
            }
          });

          Students.forEach((r) => {
            if (!linkedStudentsSet.has(r.id)) {
              studentsToLink.push(r);
            }
          });

          const promises = [];
          studentsToUnLink.forEach((original) => {
            if (!canUnlinkStudents) {
              throw Error(
                `Student ${original.id} cannot be unlinked from School because schoolID is a required field.`,
              );
            }
            promises.push(
              DataStore.save(
                Student.copyOf(original, (updated) => {
                  updated.schoolID = null;
                }),
              ),
            );
          });

          studentsToLink.forEach((original) => {
            promises.push(
              DataStore.save(
                Student.copyOf(original, (updated) => {
                  updated.schoolID = schoolRecord.id;
                }),
              ),
            );
          });

          promises.push(
            DataStore.save(
              School.copyOf(schoolRecord, (updated) => {
                Object.assign(updated, modelFields);
              }),
            ),
          );

          await Promise.all(promises);

          if (onSuccess) {
            onSuccess(modelFields);
          }
        } catch (err) {
          if (onError) {
            onError(modelFields, err.message);
          }
        }
      }}
      {...rest}
      {...getOverrideProps(overrides, 'SchoolUpdateForm')}
    >
      <TextField
        label="Name"
        isRequired={false}
        isReadOnly={false}
        defaultValue={name}
        onChange={(e) => {
          let { value } = e.target;
          if (onChange) {
            const modelFields = {
              name: value,
              Students,
            };
            const result = onChange(modelFields);
            value = result?.name ?? value;
          }
          if (errors.name?.hasError) {
            runValidationTasks('name', value);
          }
          setName(value);
        }}
        onBlur={() => runValidationTasks('name', name)}
        errorMessage={errors.name?.errorMessage}
        hasError={errors.name?.hasError}
        {...getOverrideProps(overrides, 'name')}
      ></TextField>
      <ArrayField
        onChange={async (items) => {
          let values = items;
          if (onChange) {
            const modelFields = {
              name,
              Students: values,
            };
            const result = onChange(modelFields);
            values = result?.Students ?? values;
          }
          setStudents(values);
          setCurrentStudentsValue(undefined);
          setCurrentStudentsDisplayValue('');
        }}
        currentFieldValue={currentStudentsValue}
        label="Students"
        items={Students}
        hasError={errors.Students?.hasError}
        getBadgeText={getDisplayValue.Students}
        setFieldValue={(model) => setCurrentStudentsDisplayValue(getDisplayValue.Students(model))}
        inputFieldRef={StudentsRef}
        defaultFieldValue=""
      >
        <Autocomplete
          label="Students"
          isRequired={false}
          isReadOnly={false}
          value={currentStudentsDisplayValue}
          options={studentRecords.map((r) => ({
            id: r.id,
            label: getDisplayValue.Students?.(r) ?? r.id,
          }))}
          onSelect={({ id, label }) => {
            setCurrentStudentsValue(studentRecords.find((r) => r.id === id));
            setCurrentStudentsDisplayValue(label);
          }}
          onClear={() => {
            setCurrentStudentsDisplayValue('');
          }}
          onChange={(e) => {
            let { value } = e.target;
            if (errors.Students?.hasError) {
              runValidationTasks('Students', value);
            }
            setCurrentStudentsDisplayValue(value);
            setCurrentStudentsValue(undefined);
          }}
          onBlur={() => runValidationTasks('Students', currentStudentsValue)}
          errorMessage={errors.Students?.errorMessage}
          hasError={errors.Students?.hasError}
          ref={StudentsRef}
          labelHidden={true}
          {...getOverrideProps(overrides, 'Students')}
        ></Autocomplete>
      </ArrayField>
      <Flex justifyContent="space-between" {...getOverrideProps(overrides, 'CTAFlex')}>
        <Button
          children="Reset"
          type="reset"
          onClick={resetStateValues}
          {...getOverrideProps(overrides, 'ResetButton')}
        ></Button>
        <Flex {...getOverrideProps(overrides, 'RightAlignCTASubFlex')}>
          <Button
            children="Cancel"
            type="button"
            onClick={() => {
              onCancel && onCancel();
            }}
            {...getOverrideProps(overrides, 'CancelButton')}
          ></Button>
          <Button
            children="Submit"
            type="submit"
            variation="primary"
            isDisabled={Object.values(errors).some((e) => e?.hasError)}
            {...getOverrideProps(overrides, 'SubmitButton')}
          ></Button>
        </Flex>
      </Flex>
    </Grid>
  );
}
