import * as React from "react";
import { get, head } from "lodash";
// import ReactJson from "react-json-view";
import ListItemIcon from "@material-ui/core/ListItemIcon";
// import CheckIcon from "@material-ui/icons/Check";
import CancelIcon from "@material-ui/icons/Cancel";

import IconButton from "@material-ui/core/IconButton";
import Menu from "@material-ui/core/Menu";
import MenuItem from "@material-ui/core/MenuItem";
import MoreVertIcon from "@material-ui/icons/MoreVert";

// import { LiveFormFieldProps } from "@sc/modules/v2/CRUD/FormBuilder/LiveFormField/types";

import {
  AttributeContainerProps,
  AttributeNames,
  AttributeList,
} from "./types";

import IconSelector from "@sc/modules/v2/Properties/components/properties/IconSelector";
// import { fieldset } from "@sc/components/ui/theme";

import {
  Placeholder,
  Description,
  InitialValue,
  Label,
  FormItemName,
  Columns,
  Required,
  ValidationCriteria,
} from ".";
import { Grid, ListItemText } from "@material-ui/core";
import LinkSelector from "./LinkSelector";
import PresetSelector from "./PresetSelector";

/**
 * A component to use for displaying a consistent look and field for the collection of form fields
 *
 * - Pass in an array of attributes, and it will figure out where and how to display them
 * - It will collect and pass back the values as they are gathered
 */
const AttributeContainer: React.FC<AttributeContainerProps> = ({
  children,
  data = [],
  attributes = {},
  hideFooter = false,
  style = {},
  onChange = (data) => null,
  onBlur = (data) => null,
}) => {
  const [liveData, setLiveData] = React.useState<AttributeList[]>(data);
  const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null);
  const open = Boolean(anchorEl);

  /**
   * Converts the AttributeName enum into it's form field attribute counterpart
   * @param name AttributeNames
   */
  const getAttributeKeyFromAttributeName = (name: AttributeNames): string => {
    switch (name) {
      case AttributeNames.COLUMNS:
        return "columns";
      case AttributeNames.PLACEHOLDER:
        return "placeholder";
      case AttributeNames.DESCRIPTION:
        return "description";
      case AttributeNames.INITIALVALUE:
        return "defaultValue";
      case AttributeNames.LABEL:
        return "label";
      case AttributeNames.FORMITEMNAME:
        return "name";
      case AttributeNames.REQUIRED:
        return "isRequired";
      case AttributeNames.ICON:
        return "icon";
      case AttributeNames.LINK:
        return "href";
      case AttributeNames.PRESET:
        return "preset";
    }
  };

  /**
   * Combine any changes that come from the various attributes that I load and trigger the onChange prop
   * @params
   */
  const handleChange = (type: AttributeNames, value: any): void => {
    const t = getAttributeKeyFromAttributeName(type);
    onChange({ ...attributes, [t]: value });
  };

  /**
   * Combine any changes that come from the various attributes that I load and trigger the onBlur prop
   * @params
   */
  const handleBlur = (type: AttributeNames, value: any): void => {
    const t = getAttributeKeyFromAttributeName(type);
    onBlur({ ...attributes, [t]: value });
  };

  const handleShowHide = (option: AttributeList) => {
    const key = liveData.findIndex((itm) => itm.id === option.id);

    const newOption = {
      ...liveData[key],
      settings: {
        ...liveData[key].settings,
        hide: !liveData[key].settings.hide,
      },
    };

    // console.log({ option, liveData, newOption, key });

    setLiveData([
      ...liveData.slice(0, key),
      newOption,
      ...liveData.slice(key + 1),
    ]);

    setAnchorEl(null);
  };

  const canIShow = (
    attribute: AttributeNames,
    showIfHasAttributeValue = true
  ) => {
    const key = liveData.findIndex((itm) => itm.attribute === attribute);
    const attrValue =
      attributes[getAttributeKeyFromAttributeName(attribute)] || false;

    if (key > -1) {
      return (
        !get(liveData[key], "settings.hide", false) ||
        (attrValue.length && showIfHasAttributeValue)
      );
    }
  };

  const handleClick = (event: React.MouseEvent<HTMLElement>) => {
    setAnchorEl(event.currentTarget);
  };

  const handleClose = () => {
    setAnchorEl(null);
  };

  const getLabel = (name: AttributeNames) => {
    const item = data.filter((itm) => itm.attribute === name);
    return get(head(item), "settings.label", false);
  };

  const getSetting = (name: AttributeNames, key: string) => {
    const item = data.filter((itm) => itm.attribute === name);
    return get(head(item), `settings.${key}`, false);
  };

  React.useEffect(() => {
    setLiveData(data);
  }, [data]);

  return (
    <div
      data-testid="FormBuilder-AttributeContainer"
      // style={{ padding: "0 10px", overflowY: "scroll", ...style }}
      onClick={(e) => e.stopPropagation()}
    >
      {canIShow(AttributeNames.LABEL) && (
        <div data-testid="FormBuilder-AttributeContainer-Item">
          <Label
            onChange={(e) => handleChange(AttributeNames.LABEL, e)}
            onBlur={(e) => handleBlur(AttributeNames.LABEL, e)}
            label={getLabel(AttributeNames.LABEL)}
            value={get(
              attributes,
              getAttributeKeyFromAttributeName(AttributeNames.LABEL)
            )}
          />
        </div>
      )}

      {canIShow(AttributeNames.PLACEHOLDER) && (
        <div data-testid="FormBuilder-AttributeContainer-Item">
          <Placeholder
            onChange={(e) => handleChange(AttributeNames.PLACEHOLDER, e)}
            onBlur={(e) => handleBlur(AttributeNames.PLACEHOLDER, e)}
            label={getLabel(AttributeNames.PLACEHOLDER)}
            value={get(
              attributes,
              getAttributeKeyFromAttributeName(AttributeNames.PLACEHOLDER)
            )}
          />
        </div>
      )}

      {canIShow(AttributeNames.DESCRIPTION) && (
        <div data-testid="FormBuilder-AttributeContainer-Item">
          <Description
            onChange={(e) => handleChange(AttributeNames.DESCRIPTION, e)}
            onBlur={(e) => handleBlur(AttributeNames.DESCRIPTION, e)}
            label={getLabel(AttributeNames.DESCRIPTION)}
            value={get(
              attributes,
              getAttributeKeyFromAttributeName(AttributeNames.DESCRIPTION)
            )}
          />
        </div>
      )}

      {canIShow(AttributeNames.INITIALVALUE) && (
        <div data-testid="FormBuilder-AttributeContainer-Item">
          <InitialValue
            onChange={(e) => handleChange(AttributeNames.INITIALVALUE, e)}
            onBlur={(e) => handleBlur(AttributeNames.INITIALVALUE, e)}
            label={getLabel(AttributeNames.INITIALVALUE)}
            value={get(
              attributes,
              getAttributeKeyFromAttributeName(AttributeNames.INITIALVALUE)
            )}
          />
        </div>
      )}

      {canIShow(AttributeNames.FORMITEMNAME, false) && (
        <div data-testid="FormBuilder-AttributeContainer-Item">
          <FormItemName
            onChange={(e) => handleChange(AttributeNames.FORMITEMNAME, e)}
            onBlur={(e) => handleBlur(AttributeNames.FORMITEMNAME, e)}
            label={getLabel(AttributeNames.FORMITEMNAME)}
            value={get(
              attributes,
              getAttributeKeyFromAttributeName(AttributeNames.FORMITEMNAME)
            )}
          />
        </div>
      )}

      {canIShow(AttributeNames.LINK) && (
        <div data-testid="FormBuilder-AttributeContainer-Item">
          <div data-testid="FormBuilder-Attributes-IconSelector">
            <LinkSelector
              onChange={(e) => handleChange(AttributeNames.LINK, e)}
              onBlur={(e) => handleBlur(AttributeNames.LINK, e)}
              label={getLabel(AttributeNames.LINK)}
              data={getSetting(AttributeNames.LINK, "links")}
              value={get(
                attributes,
                getAttributeKeyFromAttributeName(AttributeNames.LINK)
              )}
            />
          </div>
        </div>
      )}

      {canIShow(AttributeNames.PRESET) && (
        <div data-testid="FormBuilder-AttributeContainer-Item">
          <div data-testid="FormBuilder-Attributes-PresetSelector">
            <PresetSelector
              onChange={(e) => handleChange(AttributeNames.PRESET, e)}
              onBlur={(e) => handleBlur(AttributeNames.PRESET, e)}
              label={getLabel(AttributeNames.PRESET)}
              data={getSetting(AttributeNames.PRESET, "presets")}
              value={get(
                attributes,
                getAttributeKeyFromAttributeName(AttributeNames.PRESET)
              )}
            />
          </div>
        </div>
      )}

      {canIShow(AttributeNames.COLUMNS) && (
        <div data-testid="FormBuilder-AttributeContainer-Item">
          <Columns
            onChange={(e) => handleChange(AttributeNames.COLUMNS, e)}
            onBlur={(e) => handleBlur(AttributeNames.COLUMNS, e)}
            label={getLabel(AttributeNames.COLUMNS)}
            value={get(
              attributes,
              getAttributeKeyFromAttributeName(AttributeNames.COLUMNS)
            )}
          />
        </div>
      )}

      {canIShow(AttributeNames.ICON) && (
        <div data-testid="FormBuilder-AttributeContainer-Item">
          <div
            data-testid="FormBuilder-Attributes-IconSelector"
            style={{ marginTop: 10 }}
          >
            <IconSelector
              containerStyle={{ zoom: 0.85 }}
              label={getLabel(AttributeNames.ICON)}
              onChange={(e) => {
                handleChange(AttributeNames.ICON, e);
                handleBlur(AttributeNames.ICON, e);
              }}
              isExpanded
            />
          </div>
        </div>
      )}

      {children}

      {canIShow(AttributeNames.VALIDATIONCRITERIA) && (
        <div data-testid="FormBuilder-AttributeContainer-Item">
          <ValidationCriteria
            onChange={(e) => {
              handleChange(AttributeNames.VALIDATIONCRITERIA, e);
              handleBlur(AttributeNames.VALIDATIONCRITERIA, e);
            }}
            onBlur={(e) => handleBlur(AttributeNames.VALIDATIONCRITERIA, e)}
            label={getLabel(AttributeNames.VALIDATIONCRITERIA)}
            value={get(
              attributes,
              getAttributeKeyFromAttributeName(
                AttributeNames.VALIDATIONCRITERIA
              )
            )}
          />
        </div>
      )}

      {!hideFooter && (
        <Grid
          container
          style={{ marginTop: 15 }}
          direction="row"
          justify="space-between"
          alignItems="center"
        >
          <Grid item>
            {canIShow(AttributeNames.REQUIRED) && (
              <div data-testid="FormBuilder-AttributeContainer-Item">
                <Required
                  onChange={(e) => {
                    handleChange(AttributeNames.REQUIRED, e);
                    handleBlur(AttributeNames.REQUIRED, e);
                  }}
                  value={get(
                    attributes,
                    getAttributeKeyFromAttributeName(AttributeNames.REQUIRED)
                  )}
                />
              </div>
            )}
          </Grid>
          <Grid item>
            <div data-testid="FormBuilder-AttributeContainer-ShowHide">
              <IconButton
                aria-label="more"
                aria-controls="show-hide-menu"
                aria-haspopup="true"
                onClick={handleClick}
              >
                <MoreVertIcon />
              </IconButton>
              <Menu
                id="show-hide-menu"
                anchorEl={anchorEl}
                keepMounted
                open={open}
                onClose={handleClose}
              >
                {data
                  .filter((itm) => get(itm, "settings.hide", false))
                  .map((option, key) => {
                    const item = head(
                      liveData.filter(
                        (itm) => itm.attribute === option.attribute
                      )
                    );
                    // const isShowing = get(item, "settings.hide", false);
                    const isShowing = !canIShow(item.attribute);
                    return (
                      <MenuItem
                        key={key}
                        data-testid="FormBuilder-AttributeContainer-ShowHideItems"
                        onClick={() => handleShowHide(option)}
                      >
                        <ListItemIcon>
                          {isShowing ? (
                            <div />
                          ) : (
                            <CancelIcon fontSize="small" />
                          )}
                        </ListItemIcon>
                        <ListItemText
                          primary={
                            isShowing
                              ? `Set the ${option.attribute}`
                              : `Hide the ${option.attribute}`
                          }
                        />
                      </MenuItem>
                    );
                  })}
              </Menu>
            </div>
          </Grid>
        </Grid>
      )}
    </div>
  );
};

export default AttributeContainer;
