/* eslint-disable filenames/match-regex */
import { Error } from '@/components/Layout/Error';
import { Card, CardContent, CircularProgress } from '@mui/material';
import { styled, useTheme } from '@mui/material/styles';
import { SxProps } from '@mui/system';
import clsx from 'clsx';
import { RaRecord, useListContext } from 'ra-core';
import { ElementType, ReactElement, ReactNode, cloneElement } from 'react';
import * as React from 'react';
import {
  CreateButton,
  Pagination as DefaultPagination,
  FilterButton,
  SavedQueriesListClasses,
  Title,
  TopToolbar
} from 'react-admin';
import { ExportButton } from '@/components/ra-buttons/ExportButton';
import { ListToolbar } from './ListToolbar';
import { FilterSidebar } from './FilterSidebar';
import { MainCard } from '@/components/MainCard';
import { Empty } from '@/components/ra-lists/Empty';
import { type ListTabToolbarConfig } from './ListTabsToolbar';
import { FilterPicker } from './FilterPicker';

interface DefaultListActionsProps {
  filters?: ReactElement | ReactElement[];
}

function DefaultListActions({ filters }: DefaultListActionsProps) {
  const filterPickerFilters = Array.isArray(filters) ? filters : undefined;

  return (
    <TopToolbar>
      {filterPickerFilters ? <FilterPicker filters={filterPickerFilters} /> : null}
      {filters && !filterPickerFilters ? <FilterButton /> : null}
      <CreateButton />
      <ExportButton />
    </TopToolbar>
  );
}

function getDefaultActions(filters?: ReactElement | ReactElement[]) {
  return <DefaultListActions filters={filters} />;
}
const defaultPagination = <DefaultPagination />;
const defaultEmpty = <Empty />;
const DefaultComponent = Card;

function ListView<RecordType extends RaRecord = any>(props: ListViewProps): ReactElement | null {
  const {
    actions = undefined,
    aside,
    filters,
    bulkActionButtons,
    emptyWhileLoading,
    hasCreate,
    pagination = defaultPagination,
    children,
    className,
    component: Content = DefaultComponent,
    title,
    empty = defaultEmpty,
    tabs,
    ...rest
  } = props;
  const { defaultTitle, data, error, isLoading, filterValues, resource } = useListContext<RecordType>(props);
  // Se actions non è passato, usa quello di default con filters
  const resolvedActions = actions === undefined ? getDefaultActions(filters) : actions;
  const theme = useTheme() as any;
  const hasAsideSidebar = React.isValidElement(aside) && aside?.type !== FilterSidebar;
  const hasFilterSidebar = React.isValidElement(aside) && aside?.type === FilterSidebar;

  if (!children || (!data && isLoading && emptyWhileLoading)) {
    return null;
  }

  function renderList(shouldRenderEmptyList: boolean) {
    return (
      <div
        className={ListClasses.main}
        style={{
          border: hasAsideSidebar ? '1px solid' : 'none',
          borderRadius: hasAsideSidebar ? 4 : 0,
          borderColor: hasAsideSidebar
            ? theme.palette.mode === 'dark'
              ? theme.palette.divider
              : theme.palette.grey.A800
            : 'transparent',
          backgroundColor: hasAsideSidebar ? theme.palette.background.paper : 'transparent'
        }}
      >
        {filters || resolvedActions ? (
          <ListToolbar
            className={ListClasses.actions}
            filters={filters}
            actions={resolvedActions}
            hasCreate={hasCreate}
            hasFilterSidebar={hasFilterSidebar}
            tabs={tabs}
          />
        ) : null}
        {!error && (
          <Content className={ListClasses.content} sx={shouldRenderEmptyList ? { background: 'transparent' } : {}}>
            {bulkActionButtons && children && React.isValidElement<any>(children)
              ? cloneElement(children, { bulkActionButtons })
              : children}
          </Content>
        )}

        {error ? (
          <Error
            error={error}
            // @ts-ignore
            resetErrorBoundary={null}
          />
        ) : (
          pagination !== false && pagination
        )}
      </div>
    );
  }

  function renderEmpty() {
    return empty !== false && cloneElement(empty, { className: ListClasses.noResults, hasCreate });
  }

  const shouldRenderEmptyList = !isLoading && data?.length === 0;

  const shouldRenderEmptyPage =
    !isLoading && data?.length === 0 && !Object.keys(filterValues).length && empty !== false;

  // Check if 'aside' is a valid React element
  const isAsideValid = React.isValidElement(aside);

  // Determine if 'aside' is a FilterSidebar component
  const isFilterSidebar = isAsideValid && aside?.type === FilterSidebar;

  // Use React.Fragment if there's a generic 'aside', otherwise use MainCard
  const Wrapper = isLoading || shouldRenderEmptyPage || (isAsideValid && !isFilterSidebar) ? React.Fragment : MainCard;

  // Define props for the ListWrapper based on the presence of 'aside'
  const wrapperProps =
    !isLoading && !shouldRenderEmptyPage && (!aside || isFilterSidebar) ? { content: false } : undefined;
  return (
    <Root
      className={clsx('list-page', className)}
      {...rest}
      sx={
        shouldRenderEmptyList
          ? {
              '& .MuiPaper-root': {
                backgroundColor: 'transparent',
                border: 'none',
                borderRadius: 0
              },
              '& .RaList-actions': {
                border: '1px solid',
                borderRadius: `${theme.shape.borderRadius}px`,
                borderColor: theme.palette.mode === 'dark' ? theme.palette.divider : theme.palette.grey.A800,
                backgroundColor: theme.palette.background.paper
              }
            }
          : {}
      }
    >
      <Title title={title} defaultTitle={defaultTitle} preferenceKey={`${resource}.list.title`} />
      <Wrapper {...wrapperProps}>
        {isLoading ? (
          <CircularProgress
            sx={{
              position: 'absolute',
              top: '50%',
              left: '50%',
              marginTop: '-20px',
              marginLeft: '-20px'
            }}
          />
        ) : shouldRenderEmptyPage ? (
          renderEmpty()
        ) : (
          renderList(shouldRenderEmptyList)
        )}
      </Wrapper>
      {hasAsideSidebar ? <AsideCard aside={aside} /> : null}
      {/* @ts-ignore */}
      {hasFilterSidebar ? React.cloneElement(aside, { filters }) : null}
    </Root>
  );
}

interface AsideCardProps {
  aside: React.ReactElement;
}

function AsideCard({ aside }: AsideCardProps): ReactElement {
  const order = (aside?.props as { order?: number })?.order ?? -1;
  const theme = useTheme() as any;

  return (
    <Card
      className={ListClasses.asideCard}
      sx={{
        order,
        mr: order === -1 ? 2 : 0,
        ml: order !== -1 ? 2 : 0,
        width: 200,
        border: '1px solid',
        borderRadius: 1,
        borderColor: theme.palette.mode === 'dark' ? theme.palette.divider : theme.palette.grey.A800,
        backgroundColor: theme.palette.background.paper,
        backgroundImage: 'none'
      }}
    >
      <CardContent sx={{ pt: 1 }}>{cloneElement(aside, {})}</CardContent>
    </Card>
  );
}

const PREFIX = 'RaList';
const ListClasses = {
  main: `${PREFIX}-main`,
  content: `${PREFIX}-content`,
  actions: `${PREFIX}-actions`,
  noResults: `${PREFIX}-noResults`,
  asideCard: `${PREFIX}-asideCard`
};

interface ListViewProps {
  /**
   * Tabs to display in the toolbar. Each tab is a filter object with a label, key, icon, filter, and an optional default property.
   *
   * @example
   * import { List, ListTabToolbarConfig } from 'react-admin';
   * const tabs: ListTabToolbarConfig[] = [
   *    { label: 'Published', key: 'published', icon: <IconPublished />, filter: { status: 'published' }, default: true },
   *    { label: 'Drafts', key: 'drafts', icon: <IconDrafts />, filter: { status: 'draft' } },
   * ];
   *  const PostList = () => (
   *    <List tabs={tabs}>
   *        ...
   *    </List>
   *  );
   */
  tabs?: ListTabToolbarConfig[];

  /**
   * A unique key to identify the tab group. Used to persist the selected tab in session storage.
   * Must be stable across renders and unique among different List components.
   *
   * @example
   * import { List, ListTabToolbarConfig } from 'react-admin';
   * const tabs: ListTabToolbarConfig[] = [
   *    { label: 'Published', key: 'published', icon: <IconPublished />, filter: { status: 'published' }, default: true },
   *    { label: 'Drafts', key: 'drafts', icon: <IconDrafts />, filter: { status: 'draft' } },
   * ];
   *  const PostList = () => (
   *    <List tabs={tabs} tabGroupKey="post-list-tabs">
   *        ...
   *    </List>
   *  );
   */
  tabGroupKey?: string;

  /**
   * The actions to display in the toolbar. defaults to Filter + Create + Export.
   *
   * @see https://marmelab.com/react-admin/List.html#actions
   * @example
   * import {
   *     CreateButton,
   *     DatagridConfigurable,
   *     ExportButton,
   *     FilterButton,
   *     List,
   *     SelectColumnsButton,
   *     TopToolbar,
   * } from 'react-admin';
   * import IconEvent from '@mui/icons-material/Event';
   *
   * const ListActions = () => (
   *     <TopToolbar>
   *         <SelectColumnsButton />
   *         <FilterButton/>
   *         <CreateButton/>
   *         <ExportButton/>
   *     </TopToolbar>
   * );
   *
   * export const PostList = () => (
   *     <List actions={<ListActions/>}>
   *         <DatagridConfigurable>
   *             ...
   *         </DatagridConfigurable>
   *     </List>
   * );
   */
  actions?: ReactElement | false;

  /**
   * The content to render as a sidebar.
   * @see https://marmelab.com/react-admin/List.html#aside
   * @example
   * import { List, useListContext } from 'react-admin';
   * import { Typography } from '@mui/material';
   *
   * const Aside = () => {
   *     const { data, isLoading } = useListContext();
   *     if (isLoading) return null;
   *     return (
   *         <div style={{ width: 200, margin: '4em 1em' }}>
   *             <Typography variant="h6">Posts stats</Typography>
   *             <Typography variant="body2">
   *                 Total views: {data.reduce((sum, post) => sum + post.views, 0)}
   *             </Typography>
   *         </div>
   *     );
   * };
   *
   * const PostList = () => (
   *     <List aside={<Aside />}>
   *         ...
   *     </List>
   * );
   */
  aside?: ReactElement;

  /**
   * @deprecated pass the bulkActionButtons prop to the List child (Datagrid or SimpleList) instead
   */
  bulkActionButtons?: ReactElement | false;

  /**
   * A class name to apply to the root div element
   */
  className?: string;

  /**
   * The components rendering the list of records. Usually a <Datagrid> or <SimpleList>.
   *
   * @see https://marmelab.com/react-admin/List.html#children
   * @example
   * import { List, Datagrid, TextField, DateField, NumberField, BooleanField, ReferenceManyCount } from 'react-admin';
   *
   * export const BookList = () => (
   *     <List>
   *         <Datagrid rowClick="edit">
   *             <TextField source="id" />
   *             <TextField source="title" />
   *             <DateField source="published_at" />
   *             <ReferenceManyCount label="Nb comments" reference="comments" target="post_id" link />
   *             <BooleanField source="commentable" label="Com." />
   *             <NumberField source="nb_views" label="Views" />
   *         </Datagrid>
   *     </List>
   * );
   */
  children: ReactNode;

  /**
   * The component used to display the list. Defaults to <Card>.
   *
   * @see https://marmelab.com/react-admin/List.html#component
   * @example
   * import { List } from 'react-admin';
   *
   * const PostList = () => (
   *     <List component="div">
   *         ...
   *     </List>
   * );
   */
  component?: ElementType;

  /**
   * The component to display when the list is empty.
   *
   * @see https://marmelab.com/react-admin/List.html#empty
   * @example
   * import { CreateButton, List } from 'react-admin';
   * import { Box, Button, Typography } from '@mui/material';
   *
   * const Empty = () => (
   *     <Box textAlign="center" m={1}>
   *         <Typography variant="h4" paragraph>
   *             No products available
   *         </Typography>
   *         <Typography variant="body1">
   *             Create one or import products from a file
   *         </Typography>
   *         <CreateButton />
   *         <Button onClick={...}>Import</Button>
   *     </Box>
   * );
   *
   * const ProductList = () => (
   *     <List empty={<Empty />}>
   *         ...
   *     </List>
   * );
   */
  empty?: ReactElement | false;

  /**
   * Set to true to return null while the list is loading.
   *
   * @see https://marmelab.com/react-admin/List.html#emptywhileloading
   * @example
   * import { List } from 'react-admin';
   * import { SimpleBookList } from './BookList';
   *
   * const BookList = () => (
   *     <List emptyWhileLoading>
   *         <SimpleBookList />
   *     </List>
   * );
   */
  emptyWhileLoading?: boolean;

  /**
   * The filter inputs to display in the toolbar.
   *
   * @see https://marmelab.com/react-admin/List.html#filters
   * @example
   * import { List, TextInput } from 'react-admin';
   *
   * const postFilters = [
   *     <TextInput label="Search" source="q" alwaysOn />,
   *     <TextInput label="Title" source="title" defaultValue="Hello, World!" />,
   * ];
   *
   * export const PostList = () => (
   *     <List filters={postFilters}>
   *         ...
   *     </List>
   * );
   */
  filters?: ReactElement | ReactElement[];

  /**
   * Set to true to force a Create button in the toolbar, even if there is no create view declared in Resource
   *
   * @see https://marmelab.com/react-admin/List.html#hascreate
   * @example
   * import { List } from 'react-admin';
   *
   * export const PostList = () => (
   *     <List hasCreate={false}>
   *         ...
   *     </List>
   * );
   */
  hasCreate?: boolean;

  /**
   * The pagination component to display. defaults to <Pagination />
   *
   * @see https://marmelab.com/react-admin/List.html#pagination
   * @example
   * import { Pagination, List } from 'react-admin';
   *
   * const PostPagination = props => <Pagination rowsPerPageOptions={[10, 25, 50, 100]} {...props} />;
   *
   * export const PostList = () => (
   *     <List pagination={<PostPagination />}>
   *         ...
   *     </List>
   * );
   */
  pagination?: ReactElement | false;

  /**
   * The page title (main title) to display above the data. Defaults to the humanized resource name.
   *
   * @see https://marmelab.com/react-admin/List.html#title
   * @example
   * import { List } from 'react-admin';
   *
   * export const PostList = () => (
   *     <List title="List of posts">
   *         ...
   *     </List>
   * );
   */
  title?: string | ReactElement;

  /**
   * The CSS styles to apply to the component.
   *
   * @see https://marmelab.com/react-admin/List.html#sx-css-api
   * @example
   * const PostList = () => (
   *     <List
   *         sx={{
   *             backgroundColor: 'yellow',
   *             '& .RaList-content': {
   *                 backgroundColor: 'red',
   *             },
   *         }}
   *     >
   *             ...
   *     </List>
   * );
   */
  sx?: SxProps;
}

const Root = styled('div', {
  name: PREFIX,
  overridesResolver: (_, styles) => styles.root
})(({ theme }) => ({
  display: 'flex',

  '& >.MuiPaper-root': {
    flex: 1
  },
  [`& .${ListClasses.main}`]: {
    flex: '1 1 auto',
    display: 'flex',
    flexDirection: 'column'
  },

  [`& .${ListClasses.content}`]: {
    position: 'relative',
    [theme.breakpoints.down('sm')]: {
      boxShadow: 'none'
    },
    overflow: 'inherit'
  },

  [`& .${ListClasses.actions}`]: {},

  [`& .${ListClasses.noResults}`]: {
    alignContent: 'center'
  },

  [`& .${ListClasses.asideCard}`]: {
    [theme.breakpoints.down('md')]: {
      display: 'none'
    },
    [`& .${SavedQueriesListClasses.floatingIcon}`]: {
      fontSize: '1.125rem'
    },
    [`& .${SavedQueriesListClasses.floatingTooltip}`]: {
      top: '-1.2em'
    },
    '& form': {
      marginTop: theme.spacing(2)
    }
  }
}));

export { ListView };
export type { ListViewProps };
