import * as React from "react";
import { merge } from "lodash";

import { FormBuilderProps, FormFieldTypes } from "./types";
import { EditorMode } from "../../Editor/types";
import LiveFormField from "./LiveFormField";
import { EditFormField } from "./EditFormField";

import { LiveFormFieldProps } from "./LiveFormField/types";

import {
  SortableList,
  DefaultItemComponent,
} from "@sc/modules/v2/CRUD/SortableList";

import { Grid } from "@material-ui/core";
import { Icon } from "@sc/plugins/webcomponents/v2";
import { FieldNamePresets, FieldNameIcons } from "./EditFormField/types";
import { IconTypes } from "@sc/plugins/webcomponents/v2/Icon";
import theme from "@sc/components/ui/theme";
import { ItemComponentTypes } from "../SortableList/types";

interface ItemProps extends LiveFormFieldProps {
  onMouseEnter?: (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => void;
  onMouseLeave?: (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => void;
  isHovering?: boolean;
}

const newFormItem: LiveFormFieldProps = {
  id: Math.random()
    .toString(36)
    .slice(2),
  type: FormFieldTypes.TEXT,
  name: "MyTextBox",
  placeholder: "Placeholder Test",
  label: "Text Label",
  description: "Text Description",
  defaultValue: "Testing Default Value",
  // styles: styleData,
  // icon: IconTypes.Email,
  columns: 12,
  preset: FieldNamePresets.CUSTOM,
};

/**
 * A module for displaying, validating, and handling groups of form fields
 *
 * - Displays in either live view or edit view
 * - In "edit view", a drag-and-drop ux is provided to help users build forms
 * - Shows a list sortable object with a custom item container (&lt;EditFormField /&gt;)
 * - In "live view", the form is generated based on the incoming data it receives
 */
const FormBuilder: React.FC<FormBuilderProps> = ({
  mode = EditorMode.LIVE,
  data = [],
  globalFieldStyle,
  onChange = () => null,
  onBlur = () => null,
}) => {
  const [isExpandedList, setIsExpandedList] = React.useState<string[]>([]);

  const handleTypeChange = (id: string, type: FormFieldTypes): void => {
    const key = data.findIndex((itm) => itm.id === id);
    onChange([
      ...data.slice(0, key),
      { ...data[key], type },
      ...data.slice(key + 1),
    ]);

    // make sure it is expanded
    if (isExpandedList.indexOf(id) === -1)
      setIsExpandedList([...isExpandedList, id]);
  };

  const handleChange = (mutatedPayload: LiveFormFieldProps[]): void => {
    console.log({ mutatedPayload });
    onChange(mutatedPayload);
  };

  const handleEdit = (data: LiveFormFieldProps): void => {
    // toggle expansion
    if (isExpandedList.indexOf(data.id) > -1) {
      // remove if it exists
      setIsExpandedList(isExpandedList.filter((id) => id !== data.id));
    } else {
      // add if it doesn't exist
      setIsExpandedList([...isExpandedList, data.id]);
    }
  };

  const ItemComponent: React.FC<ItemProps> = (itm) => {
    const { id, type, preset, styles } = itm;

    const [fieldData, setFieldData] = React.useState<ItemProps>(itm);
    const isExpanded = Boolean(isExpandedList.indexOf(id) > -1);

    const handleSingleFieldChange = (
      attrItem: LiveFormFieldProps,
      dbUpdate = true
    ): void => {
      const key = data.findIndex((itm) => itm.id === attrItem.id);
      const newData = [...data.slice(0, key), attrItem, ...data.slice(key + 1)];
      setFieldData(attrItem);
      if (dbUpdate) onChange(newData);
    };

    const handleSingleFieldBlur = (
      attrItem: LiveFormFieldProps,
      dbUpdate = true
    ): void => {
      const key = data.findIndex((itm) => itm.id === attrItem.id);
      const newData = [...data.slice(0, key), attrItem, ...data.slice(key + 1)];
      setFieldData(attrItem);
      if (dbUpdate) onBlur(newData);
    };

    return (
      <DefaultItemComponent
        isHovering={itm.isHovering}
        onMouseEnter={itm.onMouseEnter}
        onMouseLeave={itm.onMouseLeave}
        type={ItemComponentTypes.TEXT}
        icon={FieldNameIcons[preset === "custom" ? type : preset]}
        caption={preset === FieldNamePresets.CUSTOM ? type : preset}
        isExpanded={isExpanded}
      >
        <EditFormField
          id={id}
          type={type}
          fieldData={fieldData}
          onBlur={(newData) => handleSingleFieldBlur(newData)}
          onChange={(newData) => handleSingleFieldChange(newData, false)}
          onTypeChange={(type: FormFieldTypes) => handleTypeChange(id, type)}
          globalFieldStyle={merge(globalFieldStyle, styles)}
          isExpanded
        />
      </DefaultItemComponent>
    );
  };

  return (
    <div data-testid="FormBuilder">
      {mode === EditorMode.LIVE && (
        <Grid container>
          {data.map((itm, key) => (
            <LiveFormField
              key={key}
              {...itm}
              styles={merge(globalFieldStyle, itm.styles)}
            />
          ))}
        </Grid>
      )}
      {mode === EditorMode.EDITOR && (
        <SortableList
          data={data}
          itemStyle={{
            border: "1px solid #DDD",
            borderRadius: 3,
            margin: "10px 0",
            height: 45,
          }}
          itemHoverStyle={{
            border: "1px solid #AAA",
            boxShadow: "0 2px 1px 0 rgb(0,0,0,0.1)",
          }}
          ItemComponent={ItemComponent}
          onAdd={() => handleChange([...data, newFormItem])}
          onEdit={handleEdit}
          onChange={handleChange}
          onDelete={(payload, updatedData) => handleChange(updatedData)}
          canDragAndDrop
          showItemInline={false}
        />
      )}
    </div>
  );
};

export default FormBuilder;
