import { useEffect, useState } from 'react';
import { useInView } from 'react-intersection-observer';
import { useInfiniteQuery, useQuery } from 'react-query';
import { useNavigate } from 'react-router-dom';

import { IconTrendingUp } from '@material-hu/icons/tabler';
import Box from '@material-hu/mui/Box';
import Stack from '@material-hu/mui/Stack';
import { useTheme } from '@material-hu/mui/styles';
import Typography from '@material-hu/mui/Typography';

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

import { useAuth } from 'src/contexts/JWTContext';
import {
  getCompetition,
  getRanking,
  getTournamentPrediction,
  getUserRanking,
  prodeKeys,
} from 'src/services/prode';
import { type RankingEntry } from 'src/types/prode';
import { useLokaliseTranslation } from 'src/utils/i18n';

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

import FloatingPositionCard from './FloatingPositionCard';
import PodiumPreviewCard, {
  PodiumPreviewCardSkeleton,
} from './PodiumPreviewCard';
import PodiumPreviewDialog from './PodiumPreviewDialog';
import RankingCard, { RankingCardSkeleton } from './RankingCard';
import RankingRow, {
  RankingRowSkeleton,
  RankingTableSkeleton,
} from './RankingRow';
import StatsCard, { StatsCardSkeleton } from './StatsCard';
import UserStatsDialog from './UserStatsDialog';

const RANKING_LIMIT = 20;

type RankingTabProps = {
  competitionId: number;
};

const RankingTab = ({ competitionId }: RankingTabProps) => {
  const { t, i18n } = useLokaliseTranslation('sportsPool');
  const { isAuthenticated, user } = useAuth();
  const theme = useTheme();
  const navigate = useNavigate();
  const routes = useSportsPoolRoutes();

  const [isPodiumPreviewOpen, setIsPodiumPreviewOpen] = useState(false);
  const [selectedEntry, setSelectedEntry] = useState<RankingEntry | null>(null);

  const isQueryEnabled = isAuthenticated && !!competitionId;

  const borderDefault = theme.palette.new.border.neutral.default;
  const defaultBg = theme.palette.new.background.elements.default;

  const { data: competition } = useQuery(
    prodeKeys.competition(competitionId),
    () => getCompetition(competitionId),
    {
      enabled: isQueryEnabled,
      select: res => res.data,
    },
  );

  const { data: userRanking, isFetching: isUserRankingFetching } = useQuery(
    prodeKeys.userRanking(competitionId),
    () => getUserRanking(competitionId),
    {
      enabled: isQueryEnabled,
      select: res => res.data,
    },
  );

  const { data: tournamentPrediction, isFetching: isTournamentFetching } =
    useQuery(
      prodeKeys.tournamentPrediction(competitionId),
      () => getTournamentPrediction(competitionId),
      {
        enabled: isQueryEnabled,
        select: res => res.data,
      },
    );

  const {
    data: rankingData,
    isFetching: isRankingFetching,
    fetchNextPage,
    hasNextPage,
    isFetchingNextPage,
  } = useInfiniteQuery(
    prodeKeys.ranking(competitionId, { limit: RANKING_LIMIT }),
    ({ pageParam = 0 }) =>
      getRanking(competitionId, { offset: pageParam, limit: RANKING_LIMIT }),
    {
      enabled: isQueryEnabled,
      getNextPageParam: lastPage => {
        const { offset, limit, total } = lastPage.data.pagination;
        const nextOffset = offset + limit;
        return nextOffset < total ? nextOffset : undefined;
      },
    },
  );

  const rankingEntries =
    rankingData?.pages.flatMap(page => page.data.data) ?? [];
  const isRankingInitialLoading = isRankingFetching && !rankingData;

  const [sentinelRef, inView] = useInView({ threshold: 0 });

  const userEntry = rankingEntries.find(entry => entry.userId === user?.id);
  const isUserRowLoaded = !!userEntry;

  const [userRowRef, isUserRowInView] = useInView({
    threshold: 0,
    initialInView: true,
  });

  const shouldShowFloatingCard =
    !isRankingInitialLoading &&
    !!userRanking &&
    (!isUserRowLoaded || !isUserRowInView);

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

  const canModifyPodium = !!tournamentPrediction?.isOpen;

  const handleFloatingCardClick = () => {
    if (userEntry) {
      setSelectedEntry(userEntry);
      return;
    }
    if (!userRanking || !user?.id) return;
    setSelectedEntry({
      userId: user.id,
      userName: `${user.firstName ?? ''} ${user.lastName ?? ''}`.trim(),
      userAvatarUrl: user.profilePicture ?? null,
      position: userRanking.position ?? 0,
      positionChange: userRanking.positionChange,
      positionDirection: userRanking.positionDirection,
      totalPoints: userRanking.totalPoints,
      exactResults: userRanking.exactResults,
    });
  };

  const handlePodiumPreviewClick = () => {
    setIsPodiumPreviewOpen(true);
  };

  const handleModifyPodium = () => {
    setIsPodiumPreviewOpen(false);
    if (canModifyPodium) navigate(routes.podium(competitionId));
  };

  const getDeadline = () => {
    if (competition?.startDate) {
      const date = new Date(competition.startDate);
      return date.toLocaleDateString(i18n.language, {
        day: '2-digit',
        month: '2-digit',
        hour: '2-digit',
        minute: '2-digit',
      });
    }
    return undefined;
  };

  const isInitialLoading = isUserRankingFetching && !userRanking;

  if (isInitialLoading) {
    return (
      <Stack
        sx={{
          gap: 2,
          width: '100%',
        }}
      >
        <RankingCardSkeleton />
        <StatsCardSkeleton />
        <Stack sx={{ gap: 1 }}>
          <Skeleton
            variant="text"
            width={180}
            height={24}
          />
          <Skeleton
            variant="text"
            width={120}
            height={18}
          />
        </Stack>
        <RankingTableSkeleton />
      </Stack>
    );
  }

  if (!userRanking) {
    return (
      <Stack
        sx={{
          p: 2,
          alignItems: 'center',
          justifyContent: 'center',
        }}
      >
        <Typography
          variant="globalXS"
          sx={{ color: theme.palette.new.text.neutral.lighter }}
        >
          {t('ranking_page.no_ranking')}
        </Typography>
      </Stack>
    );
  }

  return (
    <>
      <Stack
        sx={{
          pb: 2,
          gap: 2,
          width: '100%',
        }}
      >
        {/* Top cards: full-width RankingCard if there's no podium,
            otherwise a 2-column row with podium alongside. */}
        {!tournamentPrediction?.prediction ? (
          <Box sx={getStaggerAnimationSx(0)}>
            <RankingCard ranking={userRanking} />
          </Box>
        ) : (
          <Box sx={getStaggerAnimationSx(0)}>
            <Stack
              sx={{
                flexDirection: { xs: 'column', md: 'row' },
                gap: 2,
              }}
            >
              <Stack sx={{ flex: 1 }}>
                <RankingCard ranking={userRanking} />
              </Stack>

              <Stack sx={{ flex: 1 }}>
                {isTournamentFetching && !tournamentPrediction && (
                  <PodiumPreviewCardSkeleton />
                )}
                {tournamentPrediction && (
                  <PodiumPreviewCard
                    tournamentPrediction={tournamentPrediction}
                    deadline={getDeadline()}
                    onClick={handlePodiumPreviewClick}
                  />
                )}
              </Stack>
            </Stack>
          </Box>
        )}

        {/* Stats Card */}
        <Box sx={getStaggerAnimationSx(1)}>
          <StatsCard ranking={userRanking} />
        </Box>

        {/* General Standings */}
        <Box sx={getStaggerAnimationSx(2)}>
          <Stack sx={{ gap: 1 }}>
            <Typography
              variant="globalM"
              fontWeight="fontWeightSemiBold"
            >
              {t('ranking_page.general_standings')}
            </Typography>
            <Typography
              variant="globalXS"
              sx={{ color: theme.palette.new.text.neutral.lighter }}
            >
              {userRanking.totalParticipants === 1
                ? t('participants', {
                    count: userRanking.totalParticipants,
                  })
                : t('participants_plural', {
                    count: userRanking.totalParticipants,
                  })}
            </Typography>
          </Stack>
        </Box>

        {/* Ranking Table */}
        {isRankingInitialLoading && <RankingTableSkeleton />}

        {!isRankingInitialLoading && (
          <Box sx={getStaggerAnimationSx(3)}>
            <Stack sx={{ gap: 2 }}>
              <Stack
                sx={{
                  border: `1px solid ${borderDefault}`,
                  borderRadius: 2,
                  overflow: 'hidden',
                }}
              >
                {/* Header */}
                <Stack
                  sx={{
                    flexDirection: 'row',
                    alignItems: 'center',
                    px: 2,
                    py: 2,
                    gap: 1,
                    backgroundColor: theme.palette.new.background.elements.grey,
                    minHeight: 56,
                  }}
                >
                  <Stack
                    sx={{
                      width: 16,
                      alignItems: 'center',
                      justifyContent: 'center',
                    }}
                  >
                    <IconTrendingUp
                      size={16}
                      color={theme.palette.new.text.neutral.default}
                    />
                  </Stack>
                  <Typography
                    variant="globalXS"
                    fontWeight="fontWeightSemiBold"
                    sx={{
                      flex: 1,
                      color: theme.palette.new.text.neutral.default,
                    }}
                  >
                    {t('ranking_page.player')}
                  </Typography>
                  <Typography
                    variant="globalXS"
                    fontWeight="fontWeightSemiBold"
                    sx={{ color: theme.palette.new.text.neutral.default }}
                  >
                    {t('ranking_page.points_header')}
                  </Typography>
                </Stack>

                {/* Table Body */}
                <Stack
                  sx={{
                    py: 0,
                    backgroundColor: defaultBg,
                    borderRadius: '0 0 16px 16px',
                  }}
                >
                  {rankingEntries.map((entry, index) => {
                    const isUserRow = entry.userId === user?.id;
                    const isLast =
                      !hasNextPage && index === rankingEntries.length - 1;
                    if (isUserRow) {
                      return (
                        <Box
                          key={entry.userId}
                          ref={userRowRef}
                        >
                          <RankingRow
                            entry={entry}
                            isHighlighted
                            isLast={isLast}
                            onClick={setSelectedEntry}
                          />
                        </Box>
                      );
                    }
                    return (
                      <RankingRow
                        key={entry.userId}
                        entry={entry}
                        isHighlighted={false}
                        isLast={isLast}
                        onClick={setSelectedEntry}
                      />
                    );
                  })}
                  {isFetchingNextPage && <RankingRowSkeleton />}
                </Stack>
              </Stack>

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

      <UserStatsDialog
        open={!!selectedEntry}
        entry={selectedEntry}
        competitionId={competitionId}
        onClose={() => setSelectedEntry(null)}
      />

      {/* Podium Preview Modal */}
      <PodiumPreviewDialog
        open={isPodiumPreviewOpen && !!tournamentPrediction?.prediction}
        prediction={tournamentPrediction?.prediction}
        deadline={getDeadline()}
        isOpen={canModifyPodium}
        onClose={() => setIsPodiumPreviewOpen(false)}
        onModify={handleModifyPodium}
      />

      {shouldShowFloatingCard && userRanking && (
        <FloatingPositionCard
          position={userRanking.position}
          totalPoints={userRanking.totalPoints}
          positionDirection={userRanking.positionDirection}
          userName={
            userEntry?.userName ??
            `${user?.firstName ?? ''} ${user?.lastName ?? ''}`.trim()
          }
          userAvatarUrl={
            userEntry?.userAvatarUrl ?? user?.profilePicture ?? null
          }
          onClick={handleFloatingCardClick}
        />
      )}
    </>
  );
};

export default RankingTab;
