import React, { useState, useEffect, useMemo, useCallback } from "react";
import { Checkbox, FormLabel } from "@material-ui/core";
import MUIDataTable, { debounceSearchRender } from "mui-datatables";
import { LoadingText } from "../../../../components";
import PageTitle from "../../../../components/PageTitle";
import { useResourcesApi, useDictionariesApi } from "../../api";
import { defaultResourcesFilters } from "../../../../constants/resourcesConstants";
import { useTranslation } from "react-i18next";
import ActionButton from "./ActionButton";
import SecondaryActionsGroup from "./SecondaryActionsGroup";
import {
  EditOutlined,
  FileCopyOutlined,
  OpenInNewOutlined,
  CloudDownloadOutlined,
  DeleteOutlined
} from "@material-ui/icons";
import {
  useToast,
  useResourceSecurity,
  useFileDownload
} from "../../../../hooks";
import { useHistory } from "react-router-dom";
import useResourceDeleteDialog from "../../hooks/useResourceDeleteDialog";

const __ROWS_PER_PAGE_OPTIONS = [10, 20, 50, 100];
const __RESOURCE_NAME_MAX_LENGTH = 35;

const ResourcesContainer = () => {
  const [state, setState] = useState({
    pageSize: 10,
    totalCount: 0,
    values: []
  });
  const [loading, setLoading] = useState(false);
  const [filters, setFilters] = useState({ ...defaultResourcesFilters });
  const [resourceCategories, setResourceCategories] = useState([]);

  const { t } = useTranslation();
  const { info } = useToast();
  const { getResources } = useResourcesApi();
  const { getResourceCategories } = useDictionariesApi();
  const { secureUrl } = useResourceSecurity();
  const { download } = useFileDownload();
  const history = useHistory();
  const {
    component: ResourceDeleteDialog,
    handleOpen: handleOpenDeleteDialog
  } = useResourceDeleteDialog(null, null, () =>
    changeFilters(defaultResourcesFilters)
  );

  useEffect(() => {
    getResourceCategories().then((r) => setResourceCategories(r));
  }, [getResourceCategories]);

  useEffect(() => {
    if (filters.loadedPages && filters.loadedPages.includes(filters.page))
      return;

    setLoading(true);
    getResources(filters, {
      onCompleted: (resources) => {
        setState((prev) => ({
          ...prev,
          ...resources,
          values: filters.loadedPages
            ? [...prev.values, ...resources.values]
            : resources.values
        }));

        setFilters((prev) => ({
          ...prev,
          loadedPages: prev?.loadedPages
            ? [...prev.loadedPages, resources.page]
            : [resources.page]
        }));

        setLoading(false);
      }
    });
  }, [getResources, filters]);

  const categoryFilterOptions = useMemo(
    () => resourceCategories.map((z) => z.categoryName),
    [resourceCategories]
  );

  const prepareUrl = useCallback(
    (url, download, secure) => {
      if (download) {
        url = `${url}?download=${download}`;
      }

      if (secure) {
        url = secureUrl(url);
      }

      return url;
    },
    [secureUrl]
  );

  const actions = useMemo(
    () => [
      {
        code: "edit",
        effect: (_event, resource) =>
          history.push(`/resources/${resource.resourceId}`),
        icon: EditOutlined,
        tooltip: t("Generic.Edit"),
        top: true
      },
      {
        code: "copy-url",
        effect: (_event, resource) => {
          const url = resource.secured ? secureUrl(resource.url) : resource.url;
          navigator.clipboard.writeText(url);
          info(t("Resource.List.Actions.LinkCopiedToClipboard"));
        },
        icon: FileCopyOutlined,
        tooltip: t("Resource.List.Actions.CopyUrl"),
        top: true
      },
      {
        code: "open-in-new-tab",
        effect: (event, resource) => {
          const url = prepareUrl(resource.url, false, resource.secured);
          window.open(url, "_blank");
          event.preventDefault();
        },
        icon: OpenInNewOutlined,
        tooltip: t("Generic.OpenInNewTab"),
        top: false
      },
      {
        code: "download",
        effect: (event, resource) => {
          const url = prepareUrl(resource.url, true, resource.secured);
          download(url);
          event.preventDefault();
        },
        icon: CloudDownloadOutlined,
        tooltip: t("Generic.Download"),
        top: false
      },
      {
        code: "delete",
        effect: (event, resource) => {
          handleOpenDeleteDialog(event, resource);
          event.preventDefault();
        },
        icon: DeleteOutlined,
        tooltip: t("Generic.Delete"),
        top: false
      }
    ],
    [t, info, secureUrl, history, download, prepareUrl, handleOpenDeleteDialog]
  );

  const columns = useMemo(
    () => [
      {
        label: t("Resource.Code"),
        name: "resourceCode",
        options: {
          display: true,
          draggable: true,
          download: true,
          print: false,
          searchable: true,
          sort: true,
          customFilterListOptions: {
            render: (v) =>
              v ? t("Resource.List.Filters.Code", { value: v }) : []
          },
          filter: true,
          filterType: "textField",
          filterOptions: {
            logic: (_prop, _filterValue, _row) => false
          },
          filterList: undefined,
          hint: undefined
        }
      },
      {
        label: t("Resource.Name"),
        name: "resourceName",
        options: {
          display: true,
          draggable: true,
          download: true,
          print: false,
          searchable: true,
          sort: true,
          customBodyRenderLite: (dataIndex, _rowIndex) => {
            if (loading) return;
            const value = state.values[dataIndex].resourceName;
            const formattedValue =
              value.length > __RESOURCE_NAME_MAX_LENGTH
                ? `${value.substring(0, __RESOURCE_NAME_MAX_LENGTH + 1)}[...]`
                : value;
            return formattedValue;
          },
          customFilterListOptions: {
            render: (v) =>
              v ? t("Resource.List.Filters.Name", { value: v }) : []
          },
          filter: true,
          filterType: "textField",
          filterOptions: {
            logic: (_prop, _filterValue, _row) => false
          },
          filterList: undefined,
          hint: undefined
        }
      },
      {
        label: t("Resource.Category"),
        name: "categoryName",
        options: {
          display: true,
          draggable: true,
          download: true,
          print: false,
          searchable: true,
          sort: true,
          filter: true,
          customFilterListOptions: {
            render: (v) => t("Resource.List.Filters.Category", { value: v })
          },
          filterType: "dropdown",
          filterOptions: {
            names: categoryFilterOptions,
            logic: (_prop, _filterValue, _row) => false
          },
          hint: undefined
        }
      },
      {
        label: t("Resource.Secured"),
        name: "secured",
        options: {
          display: true,
          draggable: true,
          download: true,
          print: false,
          searchable: true,
          sort: true,
          customBodyRender: (value, _tableMeta, _updateValue) => {
            return (
              <Checkbox
                disabled
                size="small"
                checked={value}
                style={{ padding: "0" }}
              />
            );
          },
          customFilterListOptions: {
            render: (v) => {
              const checked = v[0];
              return checked ? <span>{t("Resource.Secured")}</span> : [];
            }
          },
          filter: true,
          filterType: "custom",
          filterOptions: {
            logic: (_prop, _filterValue, _row) => false,
            display: (filterList, onChange, index, column) => {
              return (
                <div>
                  <FormLabel>{t("Resource.Secured")}</FormLabel>
                  <Checkbox
                    color="primary"
                    checked={filterList[index][0] || false}
                    onChange={(event) => {
                      filterList[index][0] = event.target.checked;
                      onChange(filterList[index], index, column);
                    }}
                  />
                </div>
              );
            }
          },
          hint: undefined
        }
      },
      {
        label: "",
        name: "actions",
        options: {
          customHeadLabelRender: (_options) => "",
          display: true,
          draggable: false,
          download: false,
          print: false,
          searchable: false,
          sort: false,
          customBodyRenderLite: (dataIndex, _rowIndex) => {
            if (loading) return;
            const resource = state.values[dataIndex];
            return (
              <>
                {actions
                  .filter((a) => a.top === true)
                  .map((action) => (
                    <ActionButton
                      key={`resource-${resource.resourceId}-${action.code}`}
                      action={action}
                      resource={resource}
                    />
                  ))}
                <SecondaryActionsGroup
                  resource={resource}
                  actions={actions.filter((a) => a.top === false)}
                />
              </>
            );
          },
          setCellProps: (_cellValue, _rowIndex, _columnIndex) => ({
            style: {
              paddingTop: "0px",
              paddingBottom: "0px",
              textAlign: "right"
            }
          }),
          filter: false
        }
      }
    ],
    [loading, state.values, categoryFilterOptions, t, actions]
  );

  const changeFilters = useCallback((obj) => {
    const keys = Object.keys(obj);
    const isPageChange = keys.length === 1 && keys[0] === "page";
    if (!isPageChange) {
      const { page, loadedPages } = defaultResourcesFilters;
      obj = { ...obj, page, loadedPages };
    }

    setFilters((prev) => ({ ...prev, ...obj }));
  }, []);

  const getCategoryId = useCallback(
    (name) => {
      const category = resourceCategories.find((z) => z.categoryName === name);
      return category?.categoryId;
    },
    [resourceCategories]
  );

  const handleFilterChange = useCallback(
    (changedColumn, filterList, type, changedColumnIndex, _displayData) => {
      if (type === "reset") {
        changeFilters(defaultResourcesFilters);
        return;
      }

      const filterValue = filterList[changedColumnIndex][0];

      if (changedColumn === "categoryName") {
        const categoryId = filterValue
          ? getCategoryId(filterValue)
          : filterValue;
        changeFilters({ categoryId });
        return;
      }

      changeFilters({ [changedColumn]: filterValue });
    },
    [changeFilters, getCategoryId]
  );

  return (
    <>
      <PageTitle title={t("Resource.List.Title")} />
      <MUIDataTable
        title={t("Resource.List.SubTitle")}
        columns={columns}
        data={state.values}
        options={{
          filterType: "textField",
          expandableRows: false,
          print: false,
          selectableRows: "none",
          page: filters.page - 1,
          rowsPerPage: state.pageSize,
          rowsPerPageOptions: __ROWS_PER_PAGE_OPTIONS,
          count: state.totalCount,
          customSearchRender: debounceSearchRender(500),
          onChangePage: (currentPage) =>
            changeFilters({ page: currentPage + 1 }),
          onChangeRowsPerPage: (numberOfRows) =>
            changeFilters({ pageSize: numberOfRows }),
          onColumnSortChange: (changedColumn, direction) =>
            changeFilters({
              sortBy: changedColumn,
              sortDirection: direction
            }),
          onFilterChange: handleFilterChange,
          onSearchChange: (text) => changeFilters({ fullTextSearch: text }),
          customSort: (data) => data,
          customSearch: () => true,
          setFilterChipProps: (_colIndex, _colName, _data) => {
            return {
              color: "primary",
              variant: "outlined"
            };
          },
          textLabels: {
            body: {
              noMatch: loading ? (
                <LoadingText lines={15} />
              ) : (
                <>{t("Generic.Table.Body.NoMatch")}</>
              )
            },
            filter: {
              all: t("Generic.Table.Filter.All"),
              reset: t("Generic.Table.Filter.Reset"),
              title: t("Generic.Table.Filter.Title")
            },
            pagination: {
              displayRows: t("Generic.Table.Pagination.DisplayRows"),
              next: t("Generic.Table.Pagination.Next"),
              previous: t("Generic.Table.Pagination.Previous"),
              rowsPerPage: t("Generic.Table.Pagination.RowsPerPage")
            },
            toolbar: {
              downloadCsv: t("Generic.Table.Toolbar.DownloadCsv"),
              filterTable: t("Generic.Table.Toolbar.FilterTable"),
              print: t("Generic.Table.Toolbar.Print"),
              search: t("Generic.Table.Toolbar.Search"),
              viewColumns: t("Generic.Table.Toolbar.ViewColumns")
            },
            viewColumns: {
              title: t("Generic.Table.ViewColumns.Title")
            }
          }
        }}
      />
      {ResourceDeleteDialog}
    </>
  );
};

export default ResourcesContainer;
