import { type FC, useEffect, useRef } from 'react';
import { useInView } from 'react-intersection-observer';
import { type InfiniteQueryObserverBaseResult } from 'react-query';

import { IconCircleCheck, IconInfoCircle } from '@material-hu/icons/tabler';
import Box from '@material-hu/mui/Box';
import Stack from '@material-hu/mui/Stack';
import Typography from '@material-hu/mui/Typography';

import StateCard from '@material-hu/components/composed-components/StateCard';
import Skeleton from '@material-hu/components/design-system/Skeleton';

import { MatchFilter, type MatchWithPrediction } from 'src/types/prode';
import { useLokaliseTranslation } from 'src/utils/i18n';

import { getStaggerAnimationSx } from '../constants';

import { MatchCardSkeleton } from './CardSkeletons';
import MatchCard from './MatchCard';
import MatchFilterChips from './MatchFilterChips';

// Type for grouped matches by date (with predictions)
type GroupedMatchesByDate = {
  date: string;
  dateDisplay: string;
  matches: MatchWithPrediction[];
};

type MatchesListProps = {
  matchesByDate: GroupedMatchesByDate[];
  onMatchClick?: (matchId: number) => void;
  activeFilter: MatchFilter;
  onFilterChange: (filter: MatchFilter) => void;
  hasTournamentStarted?: boolean;
} & Partial<
  Pick<
    InfiniteQueryObserverBaseResult,
    'hasNextPage' | 'isFetchingNextPage' | 'fetchNextPage' | 'isLoading'
  >
>;

const MatchesList: FC<MatchesListProps> = ({
  matchesByDate,
  onMatchClick,
  activeFilter,
  onFilterChange,
  hasTournamentStarted = false,
  isLoading = false,
  hasNextPage,
  isFetchingNextPage,
  fetchNextPage,
}) => {
  const [sentinelRef, inView] = useInView({ threshold: 0 });

  useEffect(() => {
    if (inView && hasNextPage && !isFetchingNextPage) {
      fetchNextPage?.();
    }
  }, [inView, hasNextPage, isFetchingNextPage, fetchNextPage]);

  const totalMatches = matchesByDate.reduce(
    (acc, g) => acc + g.matches.length,
    0,
  );
  const prevCountRef = useRef(totalMatches);

  useEffect(() => {
    prevCountRef.current = totalMatches;
  }, [totalMatches]);

  const { t } = useLokaliseTranslation('sportsPool');

  const hasMatches = matchesByDate && matchesByDate.length > 0;

  return (
    <Stack sx={{ gap: 2 }}>
      {/* Filter chips */}
      <Box sx={getStaggerAnimationSx(0)}>
        <MatchFilterChips
          activeFilter={activeFilter}
          onFilterChange={onFilterChange}
          hasTournamentStarted={hasTournamentStarted}
        />
      </Box>

      {isLoading && (
        <Stack sx={{ gap: 1 }}>
          <Skeleton
            variant="text"
            width={180}
            height={18}
            sx={{ py: 1 }}
          />
          <Box
            sx={{
              gap: { xs: 1, md: 2 },
              display: 'grid',
              gridTemplateColumns: { xs: '1fr', md: 'repeat(2, 1fr)' },
            }}
          >
            <MatchCardSkeleton />
            <MatchCardSkeleton />
            <MatchCardSkeleton />
          </Box>
        </Stack>
      )}

      {!isLoading && !hasMatches && (
        <>
          {activeFilter === MatchFilter.Finished && (
            <StateCard
              slotProps={{
                title: {
                  title: t('matches.empty_finished_title'),
                  description: t('matches.empty_finished_description'),
                },
                avatar: {
                  Icon: IconInfoCircle,
                  color: 'primary',
                },
              }}
            />
          )}
          {activeFilter === MatchFilter.NeedsPrediction && (
            <StateCard
              slotProps={{
                title: {
                  title: t('matches.empty_needs_prediction_title'),
                  description: t('matches.empty_needs_prediction_description'),
                },
                avatar: {
                  Icon: IconCircleCheck,
                  color: 'success',
                },
              }}
            />
          )}
          {activeFilter !== MatchFilter.Finished &&
            activeFilter !== MatchFilter.NeedsPrediction && (
              <StateCard
                slotProps={{
                  title: {
                    title: t('matches.empty_upcoming_title'),
                    description: t('matches.empty_upcoming_description'),
                  },
                  avatar: {
                    Icon: IconInfoCircle,
                    color: 'primary',
                  },
                }}
              />
            )}
        </>
      )}

      {!isLoading &&
        hasMatches &&
        matchesByDate.map((dateGroup, groupIndex) => (
          <Stack
            key={dateGroup.date}
            sx={{
              gap: 1,
            }}
          >
            <Typography
              variant="globalXS"
              fontWeight={600}
            >
              {dateGroup.dateDisplay}
            </Typography>

            <Box
              sx={{
                gap: {
                  xs: 1,
                  md: 2,
                },
                display: 'grid',
                gridTemplateColumns: {
                  xs: '1fr',
                  md: 'repeat(2, 1fr)',
                },
              }}
            >
              {dateGroup.matches.map((mwp, matchIndex) => {
                const accumulatedOffset = matchesByDate
                  .slice(0, groupIndex)
                  .reduce((acc, g) => acc + g.matches.length, 0);
                const globalIndex = accumulatedOffset + matchIndex;
                const staggerIndex = Math.max(
                  globalIndex - prevCountRef.current,
                  0,
                );
                return (
                  <Box
                    key={mwp.match.id}
                    sx={getStaggerAnimationSx(staggerIndex + 1)}
                  >
                    <MatchCard
                      match={mwp.match}
                      prediction={mwp.prediction}
                      isPredictionOpen={mwp.isPredictionOpen}
                      onClick={() => onMatchClick?.(mwp.match.id)}
                    />
                  </Box>
                );
              })}
            </Box>
          </Stack>
        ))}

      {!isLoading && hasNextPage && (
        <Box
          ref={sentinelRef}
          sx={{ height: '2px' }}
        />
      )}

      {isFetchingNextPage && (
        <Box
          sx={{
            gap: { xs: 1, md: 2 },
            display: 'grid',
            gridTemplateColumns: { xs: '1fr', md: 'repeat(2, 1fr)' },
          }}
        >
          <MatchCardSkeleton />
          <MatchCardSkeleton />
          <MatchCardSkeleton />
        </Box>
      )}
    </Stack>
  );
};

export default MatchesList;
