/**
 * 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 React, {
  FunctionComponent,
  useState,
  useRef,
  useEffect,
  useCallback,
} from 'react';
import Alert from 'src/components/Alert';
import { SupersetClient, t, styled } from '@superset-ui/core';
import TableView, { EmptyWrapperType } from 'src/components/TableView';
import { ServerPagination, SortByType } from 'src/components/TableView/types';
import StyledModal from 'src/components/Modal';
import Button from 'src/components/Button';
import { useListViewResource } from 'src/views/CRUD/hooks';
import Dataset from 'src/types/Dataset';
import { useDebouncedEffect } from 'src/explore/exploreUtils';
import { SLOW_DEBOUNCE } from 'src/constants';
import { getClientErrorObject } from 'src/utils/getClientErrorObject';
import Loading from 'src/components/Loading';
import withToasts from 'src/messageToasts/enhancers/withToasts';
import { Input, AntdInput } from 'src/common/components';
import {
  PAGE_SIZE as DATASET_PAGE_SIZE,
  SORT_BY as DATASET_SORT_BY,
} from 'src/views/CRUD/data/dataset/constants';
import FacePile from '../components/FacePile';

const CONFIRM_WARNING_MESSAGE = t(
  'Warning! Changing the dataset may break the chart if the metadata does not exist.',
);

const CHANGE_WARNING_MSG = t(
  'Changing the dataset may break the chart if the chart relies ' +
    'on columns or metadata that does not exist in the target dataset',
);

interface Datasource {
  type: string;
  id: number;
  uid: string;
}

interface ChangeDatasourceModalProps {
  addDangerToast: (msg: string) => void;
  addSuccessToast: (msg: string) => void;
  onChange: (uid: string) => void;
  onDatasourceSave: (datasource: object, errors?: Array<any>) => {};
  onHide: () => void;
  show: boolean;
}

const ConfirmModalStyled = styled.div`
  .btn-container {
    display: flex;
    justify-content: flex-end;
    padding: 0px 15px;
    margin: 10px 0 0 0;
  }

  .confirm-modal-container {
    margin: 9px;
  }
`;

const StyledSpan = styled.span`
  cursor: pointer;
  color: ${({ theme }) => theme.colors.primary.dark1};
  &: hover {
    color: ${({ theme }) => theme.colors.primary.dark2};
  }
`;

const ChangeDatasourceModal: FunctionComponent<ChangeDatasourceModalProps> = ({
  addDangerToast,
  addSuccessToast,
  onChange,
  onDatasourceSave,
  onHide,
  show,
}) => {
  const [filter, setFilter] = useState<any>(undefined);
  const [pageIndex, setPageIndex] = useState<number>(0);
  const [sortBy, setSortBy] = useState<SortByType>(DATASET_SORT_BY);
  const [confirmChange, setConfirmChange] = useState(false);
  const [confirmedDataset, setConfirmedDataset] = useState<Datasource>();
  const searchRef = useRef<AntdInput>(null);

  const {
    state: { loading, resourceCollection, resourceCount },
    fetchData,
  } = useListViewResource<Dataset>('dataset', t('dataset'), addDangerToast);

  const selectDatasource = useCallback((datasource: Datasource) => {
    setConfirmChange(true);
    setConfirmedDataset(datasource);
  }, []);

  const fetchDatasetPayload = {
    pageIndex,
    pageSize: DATASET_PAGE_SIZE,
    filters: [],
    sortBy,
  };

  useDebouncedEffect(
    () => {
      fetchData({
        ...fetchDatasetPayload,
        ...(filter && {
          filters: [
            {
              id: 'table_name',
              operator: 'ct',
              value: filter,
            },
          ],
        }),
      });
    },
    SLOW_DEBOUNCE,
    [filter, pageIndex, sortBy],
  );

  useEffect(() => {
    const onEnterModal = async () => {
      setTimeout(() => searchRef?.current?.focus(), 200);
    };

    if (show) {
      onEnterModal();
    }
  }, [
    addDangerToast,
    fetchData,
    onChange,
    onDatasourceSave,
    onHide,
    selectDatasource,
    show,
  ]);

  const changeSearch = (event: React.ChangeEvent<HTMLInputElement>) => {
    const searchValue = event.target.value ?? '';
    setFilter(searchValue);
    setPageIndex(0);
  };

  const handleChangeConfirm = () => {
    SupersetClient.get({
      endpoint: `/datasource/get/${confirmedDataset?.type}/${confirmedDataset?.id}/`,
    })
      .then(({ json }) => {
        onDatasourceSave(json);
        onChange(`${confirmedDataset?.id}__table`);
      })
      .catch(response => {
        getClientErrorObject(response).then(
          ({ error, message }: { error: any; message: string }) => {
            const errorMessage = error
              ? error.error || error.statusText || error
              : message;
            addDangerToast(errorMessage);
          },
        );
      });
    onHide();
    addSuccessToast('Successfully changed dataset!');
  };

  const handlerCancelConfirm = () => {
    setConfirmChange(false);
  };

  const columns = [
    {
      Cell: ({ row: { original } }: any) => (
        <StyledSpan
          role="button"
          tabIndex={0}
          data-test="datasource-link"
          onClick={() => selectDatasource({ type: 'table', ...original })}
        >
          {original?.table_name}
        </StyledSpan>
      ),
      Header: t('Name'),
      accessor: 'table_name',
    },
    {
      Header: t('Type'),
      accessor: 'kind',
      disableSortBy: true,
    },
    {
      Header: t('Schema'),
      accessor: 'schema',
    },
    {
      Header: t('Connection'),
      accessor: 'database.database_name',
      disableSortBy: true,
    },
    {
      Cell: ({
        row: {
          original: { owners = [] },
        },
      }: any) => <FacePile users={owners} />,
      Header: t('Owners'),
      id: 'owners',
      disableSortBy: true,
    },
  ];

  const onServerPagination = (args: ServerPagination) => {
    setPageIndex(args.pageIndex);
    if (args.sortBy) {
      // ensure default sort by
      setSortBy(args.sortBy.length > 0 ? args.sortBy : DATASET_SORT_BY);
    }
  };

  return (
    <StyledModal
      show={show}
      onHide={onHide}
      responsive
      title={t('Change dataset')}
      width={confirmChange ? '432px' : ''}
      height={confirmChange ? 'auto' : '540px'}
      hideFooter={!confirmChange}
      footer={
        <>
          {confirmChange && (
            <ConfirmModalStyled>
              <div className="btn-container">
                <Button onClick={handlerCancelConfirm}>Cancel</Button>
                <Button
                  className="proceed-btn"
                  buttonStyle="primary"
                  onClick={handleChangeConfirm}
                >
                  Proceed
                </Button>
              </div>
            </ConfirmModalStyled>
          )}
        </>
      }
    >
      <>
        {!confirmChange && (
          <>
            <Alert
              roomBelow
              type="warning"
              css={theme => ({ marginBottom: theme.gridUnit * 4 })}
              message={
                <>
                  <strong>{t('Warning!')}</strong> {CHANGE_WARNING_MSG}
                </>
              }
            />
            <Input
              ref={searchRef}
              type="text"
              value={filter}
              placeholder={t('Search / Filter')}
              onChange={changeSearch}
            />
            {loading && <Loading />}
            {!loading && (
              <TableView
                columns={columns}
                data={resourceCollection}
                pageSize={DATASET_PAGE_SIZE}
                initialPageIndex={pageIndex}
                initialSortBy={sortBy}
                totalCount={resourceCount}
                onServerPagination={onServerPagination}
                className="table-condensed"
                emptyWrapperType={EmptyWrapperType.Small}
                serverPagination
                isPaginationSticky
                scrollTable
              />
            )}
          </>
        )}
        {confirmChange && <>{CONFIRM_WARNING_MESSAGE}</>}
      </>
    </StyledModal>
  );
};

export default withToasts(ChangeDatasourceModal);
