/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
import { FunctionComponent, useState, useEffect, ChangeEvent } from 'react';

import { t } from '@apache-superset/core/translation';
import { styled } from '@apache-superset/core/theme';
import { useSingleViewResource } from 'src/views/CRUD/hooks';
import { ModalTitleWithIcon } from 'src/components/ModalTitleWithIcon';
import { Typography } from '@superset-ui/core/components/Typography';
import { Input, Modal } from '@superset-ui/core/components';
import withToasts from 'src/components/MessageToasts/withToasts';

import { OnlyKeyWithType } from 'src/utils/types';
import { AnnotationLayerObject } from './types';

type AnnotationLayerObjectStringKeys = keyof Pick<
  AnnotationLayerObject,
  OnlyKeyWithType<AnnotationLayerObject, string>
>;

interface AnnotationLayerModalProps {
  addDangerToast: (msg: string) => void;
  addSuccessToast: (msg: string) => void;
  layer?: AnnotationLayerObject | null;
  onLayerAdd?: (layer?: AnnotationLayerObject) => void;
  onHide: () => void;
  show: boolean;
}

const StyledAnnotationLayerTitle = styled.div`
  margin: ${({ theme }) => theme.sizeUnit * 2}px auto
    ${({ theme }) => theme.sizeUnit * 4}px auto;
`;

const LayerContainer = styled.div`
  margin-bottom: ${({ theme }) => theme.sizeUnit * 10}px;

  .control-label {
    margin-bottom: ${({ theme }) => theme.sizeUnit * 2}px;
  }

  .required {
    margin-left: ${({ theme }) => theme.sizeUnit / 2}px;
    color: ${({ theme }) => theme.colorError};
  }

  textarea,
  input[type='text'] {
    padding: ${({ theme }) => theme.sizeUnit * 1.5}px
      ${({ theme }) => theme.sizeUnit * 2}px;
    border: 1px solid ${({ theme }) => theme.colorBorder};
    border-radius: ${({ theme }) => theme.borderRadius}px;
    width: 50%;
  }

  input,
  textarea {
    flex: 1 1 auto;
  }

  textarea {
    width: 100%;
    height: 160px;
    resize: none;
  }

  input::placeholder,
  textarea::placeholder {
    color: ${({ theme }) => theme.colorTextPlaceholder};
  }
`;

const AnnotationLayerModal: FunctionComponent<AnnotationLayerModalProps> = ({
  addDangerToast,
  addSuccessToast,
  onLayerAdd,
  onHide,
  show,
  layer = null,
}) => {
  const [disableSave, setDisableSave] = useState<boolean>(true);
  const [currentLayer, setCurrentLayer] =
    useState<AnnotationLayerObject | null>();
  const [isHidden, setIsHidden] = useState<boolean>(true);
  const isEditMode = layer !== null;

  // annotation layer fetch logic
  const {
    state: { loading, resource },
    fetchResource,
    createResource,
    updateResource,
  } = useSingleViewResource<AnnotationLayerObject>(
    'annotation_layer',
    t('annotation_layer'),
    addDangerToast,
  );

  const resetLayer = () => {
    // Reset layer
    setCurrentLayer({
      name: '',
      descr: '',
    });
  };

  // Functions
  const hide = () => {
    setIsHidden(true);

    // Reset layer
    resetLayer();

    onHide();
  };

  const onSave = () => {
    if (isEditMode) {
      // Edit
      if (currentLayer?.id) {
        const update_id = currentLayer.id;
        delete currentLayer.id;
        delete currentLayer.created_by;
        updateResource(update_id, currentLayer).then(response => {
          if (!response) {
            return;
          }

          hide();
          addSuccessToast(t('Annotation template updated'));
        });
      }
    } else if (currentLayer) {
      // Create
      createResource(currentLayer).then(response => {
        if (!response) {
          return;
        }

        if (onLayerAdd) {
          onLayerAdd(response);
        }

        hide();
        addSuccessToast(t('Annotation template created'));
      });
    }
  };

  const onTextChange = (
    event: ChangeEvent<HTMLTextAreaElement> | ChangeEvent<HTMLInputElement>,
  ) => {
    const { target } = event;
    const data = {
      ...currentLayer,
      name: currentLayer ? currentLayer.name : '',
      descr: currentLayer ? currentLayer.descr : '',
    };

    data[target.name as AnnotationLayerObjectStringKeys] = target.value;
    setCurrentLayer(data);
  };

  const validate = () => {
    if (currentLayer?.name?.length) {
      setDisableSave(false);
    } else {
      setDisableSave(true);
    }
  };

  // Initialize
  useEffect(() => {
    if (
      isEditMode &&
      (!currentLayer?.id ||
        (layer && layer.id !== currentLayer.id) ||
        (isHidden && show))
    ) {
      if (show && layer && layer.id !== null && !loading) {
        const id = layer.id || 0;

        fetchResource(id);
      }
    } else if (
      !isEditMode &&
      (!currentLayer || currentLayer.id || (isHidden && show))
    ) {
      // Reset layer
      resetLayer();
    }
  }, [layer, show]);

  useEffect(() => {
    if (resource) {
      setCurrentLayer(resource);
    }
  }, [resource]);

  // Validation
  useEffect(() => {
    validate();
  }, [
    currentLayer ? currentLayer.name : '',
    currentLayer ? currentLayer.descr : '',
  ]);

  // Show/hide
  if (isHidden && show) {
    setIsHidden(false);
  }

  return (
    <Modal
      disablePrimaryButton={disableSave}
      onHandledPrimaryAction={onSave}
      onHide={hide}
      primaryButtonName={isEditMode ? t('Save') : t('Add')}
      show={show}
      width="55%"
      name={
        isEditMode
          ? t('Edit annotation layer properties')
          : t('Add annotation layer')
      }
      title={
        <ModalTitleWithIcon
          isEditMode={isEditMode}
          title={
            isEditMode
              ? t('Edit annotation layer properties')
              : t('Add annotation layer')
          }
          data-test="annotation-layer-modal-title"
        />
      }
    >
      <StyledAnnotationLayerTitle>
        <Typography.Title level={4}>
          {t('General information')}
        </Typography.Title>
      </StyledAnnotationLayerTitle>
      <LayerContainer>
        <div className="control-label">
          {t('Annotation layer name')}
          <span className="required">*</span>
        </div>
        <Input
          name="name"
          onChange={onTextChange}
          type="text"
          value={currentLayer?.name}
        />
      </LayerContainer>
      <LayerContainer>
        <div className="control-label">{t('description')}</div>
        <Input.TextArea
          name="descr"
          value={currentLayer?.descr}
          placeholder={t('Description (this can be seen in the list)')}
          onChange={onTextChange}
        />
      </LayerContainer>
    </Modal>
  );
};

export default withToasts(AnnotationLayerModal);
