import {
  Alert,
  Button,
  Card,
  CardActions,
  CardContent,
  Dialog,
  DialogActions,
  DialogContent,
  DialogContentText,
  DialogTitle,
  Divider,
  Grid,
  Link as MUILink,
  Pagination,
  PaginationItem,
  Snackbar,
  Typography,
  useMediaQuery,
  useTheme,
} from '@mui/material';
import { useMutation, useQueryClient, useSuspenseQuery } from '@tanstack/react-query';
import { createFileRoute, Link, redirect, useNavigate } from '@tanstack/react-router';
import { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useApi } from '../../api/Api';
import ErrorComponent from '../../components/Error/ErrorComponent';
import { ERRORS } from '../../components/Error/Errors';
import HeaderLayout from '../../components/Layouts/HeaderLayout';
import { usersQueryOptions } from '../../queries/usersQuery';
import { ROUTES } from '../../types/Routes';
import { UserPermissionsUpdate } from '../../types/User';

const Users = () => {
  const [deleteOpen, setDeleteOpen] = useState(false);
  //eslint-disable-next-line @typescript-eslint/no-explicit-any
  const [_error, setError] = useState<any>();

  const Api = useApi();
  const { page } = Route.useSearch();
  const { data: usersQuery, isFetching, failureReason, error } = useSuspenseQuery(usersQueryOptions(Api, page));
  const { t } = useTranslation();
  const navigate = useNavigate();
  const queryClient = useQueryClient();
  const theme = useTheme();
  const oneSibling = useMediaQuery(theme.breakpoints.not('xs'), { noSsr: true });

  if (failureReason && 'code' in failureReason && failureReason.code === ERRORS.UNAUTHORIZED) {
    throw failureReason;
  }
  if (error && 'code' in error && error.code === ERRORS.UNAUTHORIZED) {
    throw error;
  }

  const deleteMutation = useMutation({
    mutationFn: (id: number) => Api.deleteUser(id),
  });

  const permissionMutation = useMutation({
    mutationFn: ({ data, id }: { data: UserPermissionsUpdate; id: number }) => Api.updateUserPermissions(data, id),
  });

  useEffect(() => {
    if ((page ?? 0) >= usersQuery.pages) {
      navigate({ to: ROUTES.USERS, search: { page: usersQuery.pages - 1 } });
    }
  }, [page]); //eslint-disable-line react-hooks/exhaustive-deps

  return (
    <HeaderLayout>
      <Snackbar open={isFetching} message={t('Updating')} />
      <Grid container spacing={2} sx={{ marginTop: 0 }}>
        {usersQuery.data.map((user) => (
          <Grid item xs={12} key={user.id}>
            <Card>
              <CardContent>
                {user.id !== Api.authenticatedUser?.id ? (
                  <MUILink component={Link} to="/profile/$id" params={{ id: user.id }}>
                    {user.username}
                  </MUILink>
                ) : (
                  <Typography>{user.username}</Typography>
                )}
                <Typography>{user.email}</Typography>
              </CardContent>
              {user.id !== Api.authenticatedUser?.id && (
                <>
                  <CardActions>
                    <Button size="small" color="error" onClick={() => setDeleteOpen(true)}>
                      {t('Delete')}
                    </Button>
                    <Button
                      size="small"
                      onClick={() => {
                        permissionMutation.mutate(
                          { data: { isAdmin: !user.isAdmin }, id: user.id },
                          {
                            onSuccess: async () => {
                              await queryClient.invalidateQueries({
                                queryKey: ['users'],
                              });
                            },
                            onError: setError,
                          }
                        );
                      }}
                    >
                      {t(user.isAdmin ? 'Demote Admin' : 'Make Admin')}
                    </Button>
                    <Dialog open={deleteOpen} onClose={() => setDeleteOpen(false)}>
                      <DialogTitle>{t('Confirm user delete title')}</DialogTitle>
                      <DialogContent>
                        <DialogContentText>{t('Confirm user delete body', { name: user.username })}</DialogContentText>
                      </DialogContent>
                      <DialogActions>
                        <Button onClick={() => setDeleteOpen(false)} autoFocus variant="contained">
                          {t('No')}
                        </Button>
                        <Button
                          variant="outlined"
                          color="error"
                          onClick={() => {
                            deleteMutation.mutate(user.id, {
                              onSuccess: async (data) => {
                                await queryClient.invalidateQueries({
                                  queryKey: ['users'],
                                });
                                if ((page ?? 0) >= data.pages)
                                  navigate({ to: ROUTES.PROFILE, search: { page: data.pages - 1 } });
                              },
                              onError: setError,
                            });
                            setDeleteOpen(false);
                          }}
                        >
                          {t('Yes')}
                        </Button>
                      </DialogActions>
                    </Dialog>
                  </CardActions>
                  <Snackbar
                    open={deleteMutation.isError || permissionMutation.isError}
                    autoHideDuration={2000}
                    onClose={() => {
                      deleteMutation.reset();
                      permissionMutation.reset();
                    }}
                    TransitionProps={{
                      onExited: () => setError(undefined),
                    }}
                  >
                    <Alert severity="error" variant="filled" sx={{ width: '100%' }}>
                      {error && <ErrorComponent error={_error} context="delete|PermissionsUser" color="white" />}
                    </Alert>
                  </Snackbar>
                  <Snackbar open={deleteMutation.isPending} message={t('Deleting')} />
                  <Snackbar open={permissionMutation.isPending} message={t('Updating')} />
                </>
              )}
            </Card>
          </Grid>
        ))}
        <Grid item xs={12}>
          <Divider variant="middle" />
        </Grid>
        <Grid item xs={12} sx={{ display: 'flex', justifyContent: 'center' }}>
          <Pagination
            page={(page ?? 0) + 1}
            count={usersQuery.pages}
            siblingCount={oneSibling ? 1 : 0}
            color="primary"
            renderItem={(item) => (
              <PaginationItem
                {...item}
                component={Link}
                to="/"
                search={{ page: (item.page ?? 0) > 0 ? (item.page ?? 1) - 1 : undefined }}
                //eslint-disable-next-line @typescript-eslint/no-explicit-any
                onClick={(e) => item.onClick(e as any)}
              />
            )}
          />
        </Grid>
      </Grid>
    </HeaderLayout>
  );
};

export const Route = createFileRoute(`${ROUTES.USERS}/`)({
  loaderDeps: ({ search: { page } }) => ({ page }),
  loader: ({ context: { queryClient, Api }, deps: { page } }) =>
    queryClient.ensureQueryData(usersQueryOptions(Api, page)),
  validateSearch: (search: Record<string, unknown>): { page?: number } => {
    return {
      page: search?.page !== undefined ? Number(search?.page ?? 0) : undefined,
    };
  },
  beforeLoad: ({ context: { Api } }) => {
    if ((!Api.hasAuth && !Api.currentSession[0]) || !Api.authenticatedUser?.isAdmin)
      throw redirect({ to: ROUTES.INDEX });
  },
  component: Users,
});
