// eslint-disable-next-line filenames/match-regex
import { CircularProgress, Stack } from '@mui/material';
import { Theme, styled } from '@mui/material/styles';
import _ from 'lodash';
import { PropsWithChildren, createContext, useCallback, useContext, useMemo } from 'react';
import {
  CreateProps,
  Identifier,
  Create as RaCreate,
  RaRecord,
  useDataProvider,
  useResourceContext
} from 'react-admin';
import { UseQueryOptions, useQuery } from 'react-query';
import { useLocation } from 'react-router';

type ICreateProps<
  RecordType extends Omit<RaRecord, 'id'> = any,
  ResultRecordType extends RaRecord = RecordType & { id: Identifier }
> = CreateProps<RecordType, Error, ResultRecordType> &
  PropsWithChildren<{
    useDefaults?: boolean;
    queryOptions?: UseQueryOptions;
  }>;

type IResourceDefaultValue = object;
const ResourceDefaultValueContext = createContext<IResourceDefaultValue>({});

function CreateWithDefaults(props: ICreateProps) {
  const { useDefaults = false, queryOptions = {} } = props;
  const resource = useResourceContext();
  const dataProvider = useDataProvider();
  const { search } = useLocation();
  const url = `${resource}/new`;
  const fetch = useCallback(() => {
    if (!useDefaults || !_.isFunction(dataProvider.get)) {
      return Promise.resolve({});
    }

    const params: { [key in string]: string } = {};
    new URLSearchParams(search ?? '').forEach((v, k) => {
      params[k] = v;
    });

    return dataProvider
      .get(url, params)
      .then((response: { data: object }) => response.data)
      .then((data: { responseCode: string; value: object }) => {
        const { responseCode, value } = data;
        if (responseCode === 'ok') {
          return value;
        } else {
          return Promise.reject(data);
        }
      });
  }, [useDefaults, search, dataProvider, url]);
  const _queryOptions = useMemo<UseQueryOptions>(
    () =>
      _.chain(queryOptions)
        .extend({ queryKey: [resource, search], queryFn: fetch })
        .value(),
    [resource, search, fetch, queryOptions]
  );
  const { data, isLoading } = useQuery(_queryOptions);
  const passProps = _.omit(props, ['useDefaults']);

  return isLoading ? (
    <Stack alignItems={'center'} justifyContent="center" flex={1} p={2}>
      <CircularProgress />
    </Stack>
  ) : (
    <ResourceDefaultValueContext.Provider value={data ?? {}}>
      <RaCreate {...(passProps as CreateProps)}>{props.children}</RaCreate>
    </ResourceDefaultValueContext.Provider>
  );
}
const Create = styled(CreateWithDefaults, { slot: 'root' })(({ theme }: { theme: Theme }) => ({
  '& .RaCreate-card, & > div > div > form': {
    backgroundColor: theme.palette.background.default
  },
  '& .RaCreate-main': {
    marginTop: 0
  },
  '& .RaCreate-main>.MuiPaper-root:first-of-type': {
    backgroundColor: theme.palette.background.default
  },
  '& .RaToolbar-mobileToolbar': {
    paddingLeft: `${theme.spacing(2.5)} !important`,
    paddingRight: `${theme.spacing(2.5)} !important`,
    paddingTop: '0 !important'
  },
  // Ci ho messo 4 ore per scrivere questa riga di codice e risolvere un problema con react-sticky-box ed i Long Form.
  // L'overflow è di default 'hidden', a noi serve visibile per consentire a react-sticky-box di funzionare e gestire la visiblità con ancore
  // di tutti gli elementi presenti all'interno della pagina.
  '& .RaCreate-main:has(.LongFormView)>.MuiPaper-root:first-of-type': {
    overflow: 'visible'
  },
  '& .RaCreate-main:has(.tabbed-form) .MuiTableContainer-root': {
    width: 'inherit'
  }
}));

function useResourceDefaultValues(): IResourceDefaultValue {
  return useContext(ResourceDefaultValueContext);
}

export { Create, useResourceDefaultValues };
export type { ICreateProps, IResourceDefaultValue };
