import { useState, useMemo, useCallback, memo, useRef, useEffect } from "react";
import {
  Text,
  TextInput,
  Stack,
  Group,
  Box,
  ThemeIcon,
  Container,
  Title,
  Divider,
  UnstyledButton,
  Popover,
  ActionIcon,
  ScrollArea,
} from "@mantine/core";
import {
  MagnifyingGlassIcon,
  CaretUpIcon,
  CaretDownIcon,
  ChartBarIcon,
  InfoIcon,
} from "@phosphor-icons/react";
import { PlayerStats } from "../types";
import Avatar from "@/components/avatar";
import { useNavigate } from "@tanstack/react-router";
import { useAllPlayerStats } from "../queries";

type SortKey = keyof PlayerStats | "mmr";
type SortDirection = "asc" | "desc";

interface SortConfig {
  key: SortKey;
  direction: SortDirection;
}

interface PlayerListItemProps {
  stat: PlayerStats;
  onPlayerClick: (playerId: string) => void;
  mmr: number;
  onRegisterViewport: (viewport: HTMLDivElement) => void;
  onUnregisterViewport: (viewport: HTMLDivElement) => void;
}

interface StatCellProps {
  label: string;
  value: string | number;
}

const StatCell = memo(({ label, value }: StatCellProps) => (
  <Stack justify="center" gap={0} style={{ textAlign: 'center', flexShrink: 0 }}>
    <Text size="xs" c="dimmed" fw={700}>
      {label}
    </Text>
    <Text size="xs" c="dimmed">
      {value}
    </Text>
  </Stack>
));

const PlayerListItem = memo(({ stat, onPlayerClick, mmr, onRegisterViewport, onUnregisterViewport }: PlayerListItemProps) => {
  const viewportRef = useRef<HTMLDivElement>(null);

  const avg_cups_against = useMemo(() => stat.total_cups_against / stat.matches || 0, [stat.total_cups_against, stat.matches]);

  useEffect(() => {
    if (viewportRef.current) {
      onRegisterViewport(viewportRef.current);
      return () => {
        if (viewportRef.current) {
          onUnregisterViewport(viewportRef.current);
        }
      };
    }
  }, [onRegisterViewport, onUnregisterViewport]);

  return (
    <>
      <UnstyledButton
        w="100%"
        p="md"
        onClick={() => onPlayerClick(stat.id)}
        style={{
          borderRadius: 0,
          transition: "background-color 0.15s ease",
        }}
        styles={{
          root: {
            '&:hover': {
              backgroundColor: 'var(--mantine-color-gray-0)',
            },
          },
        }}
      >
        <Group p={0} gap="sm" align="center" w="100%" wrap="nowrap" style={{ overflow: 'hidden' }}>
          <Avatar name={stat.player_name} size={40} style={{ flexShrink: 0 }} />
          <Stack gap={2} style={{ flexGrow: 1, overflow: 'hidden', minWidth: 0 }}>
            <Group gap='xs'>
              <Text size="sm" fw={600}>
                {stat.player_name}
              </Text>
              <Text size="xs" c="dimmed" ta="right">
                {stat.matches}
                <Text span fw={800}>M</Text>
              </Text>
              <Text size="xs" c="dimmed" ta="right">
                {stat.tournaments}
                <Text span fw={800}>T</Text>
              </Text>
            </Group>

            <ScrollArea
              viewportRef={viewportRef}
              type="never"
              styles={{
                viewport: {
                  WebkitOverflowScrolling: 'touch',
                  scrollBehavior: 'auto',
                  willChange: 'scroll-position',
                  transform: 'translateZ(0)',
                  backfaceVisibility: 'hidden',
                },
              }}
            >
              <Group gap='xs' wrap="nowrap">
                <StatCell label="MMR" value={mmr.toFixed(1)} />
                <StatCell label="W" value={stat.wins} />
                <StatCell label="L" value={stat.losses} />
                <StatCell label="W%" value={`${stat.win_percentage.toFixed(1)}%`} />
                <StatCell label="AWM" value={stat.margin_of_victory?.toFixed(1) || 0} />
                <StatCell label="ALM" value={stat.margin_of_loss?.toFixed(1) || 0} />
                <StatCell label="AC" value={stat.avg_cups_per_match.toFixed(1)} />
                <StatCell label="ACA" value={avg_cups_against?.toFixed(1) || 0} />
                <StatCell label="CF" value={stat.total_cups_made} />
                <StatCell label="CA" value={stat.total_cups_against} />
              </Group>
            </ScrollArea>
          </Stack>
        </Group>
      </UnstyledButton>
    </>
  );
});

const PlayerStatsTable = () => {
  const { data: playerStats } = useAllPlayerStats();
  const navigate = useNavigate();
  const [search, setSearch] = useState("");
  const [sortConfig, setSortConfig] = useState<SortConfig>({
    key: "mmr" as SortKey,
    direction: "desc",
  });

  const viewportsRef = useRef<Set<HTMLDivElement>>(new Set());
  const scrollHandlersRef = useRef<Map<HTMLDivElement, (e: Event) => void>>(new Map());
  const scrollLeaderRef = useRef<HTMLDivElement | null>(null);
  const scrollTimeoutRef = useRef<number | null>(null);

  const handleRegisterViewport = useCallback((viewport: HTMLDivElement) => {
    viewportsRef.current.add(viewport);

    const handleScrollStart = () => {
      scrollLeaderRef.current = viewport;
    };

    const handleScroll = (e: Event) => {
      const target = e.target as HTMLDivElement;

      if (!scrollLeaderRef.current) {
        scrollLeaderRef.current = target;
      }

      if (scrollLeaderRef.current !== target) {
        return;
      }

      const scrollLeft = target.scrollLeft;

      viewportsRef.current.forEach((vp) => {
        if (vp !== target && Math.abs(vp.scrollLeft - scrollLeft) > 0.5) {
          vp.scrollLeft = scrollLeft;
        }
      });

      if (scrollTimeoutRef.current) {
        clearTimeout(scrollTimeoutRef.current);
      }
      scrollTimeoutRef.current = window.setTimeout(() => {
        scrollLeaderRef.current = null;
      }, 150);
    };

    viewport.addEventListener('touchstart', handleScrollStart, { passive: true });
    viewport.addEventListener('mousedown', handleScrollStart, { passive: true });
    viewport.addEventListener('scroll', handleScroll, { passive: true });

    scrollHandlersRef.current.set(viewport, handleScroll);
  }, []);

  const handleUnregisterViewport = useCallback((viewport: HTMLDivElement) => {
    viewportsRef.current.delete(viewport);

    const handler = scrollHandlersRef.current.get(viewport);
    if (handler) {
      viewport.removeEventListener('scroll', handler);
      viewport.removeEventListener('touchstart', handler);
      viewport.removeEventListener('mousedown', handler);
      scrollHandlersRef.current.delete(viewport);
    }
  }, []);

  const calculateMMR = (stat: PlayerStats): number => {
    if (stat.matches === 0) return 0;

    const winScore = stat.win_percentage;
    const matchConfidence = Math.min(stat.matches / 15, 1);
    const avgCupsScore = Math.min(stat.avg_cups_per_match * 10, 100);
    const marginScore = stat.margin_of_victory
      ? Math.min(stat.margin_of_victory * 20, 50)
      : 0;
    const volumeBonus = Math.min(stat.matches * 0.5, 10);

    const baseMMR =
      winScore * 0.5 +
      avgCupsScore * 0.25 +
      marginScore * 0.15 +
      volumeBonus * 0.1;

    const finalMMR = baseMMR * matchConfidence;
    return Math.round(finalMMR * 10) / 10;
  };

  const statsWithMMR = useMemo(() => {
    return playerStats.map((stat) => ({
      ...stat,
      mmr: calculateMMR(stat),
    }));
  }, [playerStats]);

  const filteredAndSortedStats = useMemo(() => {
    let filtered = statsWithMMR.filter((stat) =>
      stat.player_name.toLowerCase().includes(search.toLowerCase())
    );

    return filtered.sort((a, b) => {
      let aValue: number | string;
      let bValue: number | string;

      if (sortConfig.key === "mmr") {
        aValue = a.mmr;
        bValue = b.mmr;
      } else {
        aValue = a[sortConfig.key];
        bValue = b[sortConfig.key];
      }

      if (typeof aValue === "number" && typeof bValue === "number") {
        return sortConfig.direction === "desc"
          ? bValue - aValue
          : aValue - bValue;
      }

      if (typeof aValue === "string" && typeof bValue === "string") {
        return sortConfig.direction === "desc"
          ? bValue.localeCompare(aValue)
          : aValue.localeCompare(bValue);
      }

      return 0;
    });
  }, [statsWithMMR, search, sortConfig]);

  const handlePlayerClick = useCallback((playerId: string) => {
    navigate({ to: `/profile/${playerId}` });
  }, [navigate]);

  const handleSort = (key: SortKey) => {
    setSortConfig((prev) => ({
      key,
      direction: prev.key === key && prev.direction === "desc" ? "asc" : "desc",
    }));
  };

  const getSortIcon = (key: SortKey) => {
    if (sortConfig.key !== key) return null;
    return sortConfig.direction === "desc" ? (
      <CaretDownIcon size={14} />
    ) : (
      <CaretUpIcon size={14} />
    );
  };

  if (playerStats.length === 0) {
    return (
      <Container px={0} size="md">
        <Stack align="center" gap="md" py="xl">
          <ThemeIcon size="xl" variant="light" radius="md">
            <ChartBarIcon size={32} />
          </ThemeIcon>
          <Title order={3} c="dimmed">
            No Stats Available
          </Title>
        </Stack>
      </Container>
    );
  }

  return (
    <Container size="100%" px={0}>
      <Stack gap="xs">
        <Text px="md" size="10px" lh={0} c="dimmed">
          Showing {filteredAndSortedStats.length} of {playerStats.length} players
        </Text>
        <TextInput
          placeholder="Search players"
          value={search}
          onChange={(e) => setSearch(e.currentTarget.value)}
          leftSection={<MagnifyingGlassIcon size={16} />}
          size="md"
          px="md"
        />

        <Group px="md" justify="space-between" align="center">
          <Group gap="xs" w="100%">
            <div></div>
            <Text ml='auto' size="xs" c="dimmed">Sort:</Text>
            <UnstyledButton
              onClick={() => handleSort("mmr")}
              style={{ display: "flex", alignItems: "center", gap: 4 }}
            >
              <Text size="xs" fw={sortConfig.key === "mmr" ? 600 : 400} c={sortConfig.key === "mmr" ? "dark" : "dimmed"}>
                MMR
              </Text>
              {getSortIcon("mmr")}
            </UnstyledButton>
            <Text size="xs" c="dimmed">•</Text>
            <UnstyledButton
              onClick={() => handleSort("wins")}
              style={{ display: "flex", alignItems: "center", gap: 4 }}
            >
              <Text size="xs" fw={sortConfig.key === "wins" ? 600 : 400} c={sortConfig.key === "wins" ? "dark" : "dimmed"}>
                Wins
              </Text>
              {getSortIcon("wins")}
            </UnstyledButton>
            <Text size="xs" c="dimmed">•</Text>
            <UnstyledButton
              onClick={() => handleSort("matches")}
              style={{ display: "flex", alignItems: "center", gap: 4 }}
            >
              <Text size="xs" fw={sortConfig.key === "matches" ? 600 : 400} c={sortConfig.key === "matches" ? "dark" : "dimmed"}>
                Matches
              </Text>
              {getSortIcon("matches")}
            </UnstyledButton>
            <Popover position="bottom-end" withArrow shadow="md">
              <Popover.Target>
                <ActionIcon variant="subtle" size="sm">
                  <InfoIcon size={14} />
                </ActionIcon>
              </Popover.Target>
              <Popover.Dropdown>
                <Box maw={280}>
                  <Text size="sm" fw={500} mb="xs">
                    Stat Abbreviations:
                  </Text>
                  <Text size="xs" mb={2}>
                    • <strong>M:</strong> Matches
                  </Text>
                  <Text size="xs" mb={2}>
                    • <strong>T:</strong> Tournaments
                  </Text>
                  <Text size="xs" mb={2}>
                    • <strong>MMR:</strong> Matchmaking Rating
                  </Text>
                  <Text size="xs" mb={2}>
                    • <strong>W:</strong> Wins
                  </Text>
                  <Text size="xs" mb={2}>
                    • <strong>L:</strong> Losses
                  </Text>
                  <Text size="xs" mb={2}>
                    • <strong>W%:</strong> Win Percentage
                  </Text>
                  <Text size="xs" mb={2}>
                    • <strong>AWM:</strong> Average Win Margin
                  </Text>
                  <Text size="xs" mb={2}>
                    • <strong>ALM:</strong> Average Loss Margin
                  </Text>
                  <Text size="xs" mb={2}>
                    • <strong>AC:</strong> Average Cups Per Match
                  </Text>
                  <Text size="xs" mb={2}>
                    • <strong>ACA:</strong> Average Cups Against
                  </Text>
                  <Text size="xs" mb={2}>
                    • <strong>CF:</strong> Cups For
                  </Text>
                  <Text size="xs" mb={2}>
                    • <strong>CA:</strong> Cups Against
                  </Text>

                  <Divider my="sm" />

                  <Text size="sm" fw={500} mb="xs">
                    MMR Calculation:
                  </Text>
                  <Text size="xs" mb={2}>
                    • Win Rate (50%)
                  </Text>
                  <Text size="xs" mb={2}>
                    • Average Cups/Match (25%)
                  </Text>
                  <Text size="xs" mb={2}>
                    • Average Win Margin (15%)
                  </Text>
                  <Text size="xs" mb={2}>
                    • Match Volume Bonus (10%)
                  </Text>
                  <Text size="xs" mt="xs" c="dimmed">
                    * Confidence penalty applied for players with &lt;15 matches
                  </Text>
                  <Text size="xs" mt="xs" c="dimmed">
                    ** Not an official rating
                  </Text>
                </Box>
              </Popover.Dropdown>
            </Popover>
          </Group>
        </Group>

        <Stack gap={0}>
          {filteredAndSortedStats.map((stat, index) => (
            <Box key={stat.id}>
              <PlayerListItem
                stat={stat}
                onPlayerClick={handlePlayerClick}
                mmr={stat.mmr}
                onRegisterViewport={handleRegisterViewport}
                onUnregisterViewport={handleUnregisterViewport}
              />
              {index < filteredAndSortedStats.length - 1 && <Divider />}
            </Box>
          ))}
        </Stack>

        {filteredAndSortedStats.length === 0 && search && (
          <Text ta="center" c="dimmed" py="xl">
            No players found matching "{search}"
          </Text>
        )}
      </Stack>
    </Container>
  );
};

export default PlayerStatsTable;
