import { ActionIcon, Card, Flex, Text, Indicator } from "@mantine/core";
import { PlayIcon, PencilIcon, SpeakerHighIcon } from "@phosphor-icons/react";
import React, { useCallback, useMemo } from "react";
import { MatchSlot } from "./match-slot";
import { Match } from "@/features/matches/types";
import { Team } from "@/features/teams/types";
import { useSheet } from "@/hooks/use-sheet";
import { MatchForm } from "./match-form";
import Sheet from "@/components/sheet/sheet";
import { useServerMutation } from "@/lib/tanstack-query/hooks";
import { endMatch, startMatch } from "@/features/matches/server";
import { tournamentKeys } from "@/features/tournaments/queries";
import { useQueryClient } from "@tanstack/react-query";
import { useSpotifyPlayback } from "@/lib/spotify/hooks";

interface MatchCardProps {
  match: Match;
  orders: Record<number, number>;
  showControls?: boolean;
  groupConfig?: {
    num_groups: number;
    advance_per_group: number;
  };
}

export const MatchCard: React.FC<MatchCardProps> = ({
  match,
  orders,
  showControls,
  groupConfig,
}) => {
  const queryClient = useQueryClient();
  const editSheet = useSheet();
  const { playTrack, pause } = useSpotifyPlayback();

  const getGroupLabel = useCallback((seed: number | undefined) => {
    if (!seed || !groupConfig) return undefined;

    const groupNames = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'];
    const teamsPerRank = groupConfig.num_groups;

    const rankIndex = Math.floor((seed - 1) / teamsPerRank);
    const groupIndex = (seed - 1) % teamsPerRank;

    const rank = rankIndex + 1;
    const groupName = groupNames[groupIndex] || `${groupIndex + 1}`;
    const rankSuffix = rank === 1 ? '1st' : rank === 2 ? '2nd' : rank === 3 ? '3rd' : `${rank}th`;

    return `${groupName} ${rankSuffix}`;
  }, [groupConfig]);

  const homeSlot = useMemo(
    () => ({
      from: orders[match.home_from_lid],
      from_loser: match.home_from_loser,
      team: match.home,
      seed: match.home_seed,
      cups: match.status === "ended" ? match.home_cups : undefined,
      isWinner:
        match.status === "ended" &&
        match.home_cups !== undefined &&
        match.away_cups !== undefined &&
        match.home_cups > match.away_cups,
      groupLabel: !match.home && match.home_seed ? getGroupLabel(match.home_seed) : undefined,
    }),
    [match, getGroupLabel]
  );
  const awaySlot = useMemo(
    () => ({
      from: orders[match.away_from_lid],
      from_loser: match.away_from_loser,
      team: match.away,
      seed: match.away_seed,
      cups: match.status === "ended" ? match.away_cups : undefined,
      isWinner:
        match.status === "ended" &&
        match.away_cups !== undefined &&
        match.home_cups !== undefined &&
        match.away_cups > match.home_cups,
      groupLabel: !match.away && match.away_seed ? getGroupLabel(match.away_seed) : undefined,
    }),
    [match, getGroupLabel]
  );

  const showToolbar = useMemo(
    () => match.status === "ready" && showControls,
    [match.status, showControls]
  );

  const showEditButton = useMemo(
    () => showControls && match.status === "started",
    [showControls, match.status]
  );

  const hasWalkoutData = showControls && match.home && match.away && 'song_id' in match.home && 'song_id' in match.away;

  const start = useServerMutation({
    mutationFn: startMatch,
    successMessage: "Match started!",
    onSuccess: () => {
      queryClient.invalidateQueries({
        queryKey: tournamentKeys.details(match.tournament.id),
      });
    },
  });

  const end = useServerMutation({
    mutationFn: endMatch,
    onSuccess: () => {
      queryClient.invalidateQueries({
        queryKey: tournamentKeys.details(match.tournament.id),
      });
    },
  });

  const handleFormSubmit = useCallback(
    async (data: {
      home_cups: number;
      away_cups: number;
      ot_count: number;
    }) => {
      end.mutate({
        data: {
          ...data,
          matchId: match.id,
        },
      });
      editSheet.close();
    },
    [match.id, editSheet]
  );

  const speak = useCallback((text: string): Promise<void> => {
    return new Promise((resolve) => {
      if (!("speechSynthesis" in window)) {
        resolve();
        return;
      }

      const utterance = new SpeechSynthesisUtterance(text);
      const voices = window.speechSynthesis.getVoices();

      const preferredVoice =
        voices.find(
          (voice) =>
            voice.lang.startsWith("en") && voice.name.includes("Daniel")
        ) ||
        voices.find((voice) => voice.lang.startsWith("en") && voice.default);

      if (preferredVoice) {
        utterance.voice = preferredVoice;
      }

      utterance.rate = 0.9;
      utterance.volume = 0.8;
      utterance.pitch = 1.0;

      utterance.onend = () => resolve();
      utterance.onerror = () => resolve();

      window.speechSynthesis.speak(utterance);
    });
  }, []);

  const playTeamWalkout = useCallback((team: Team): Promise<void> => {
    return new Promise((resolve) => {
      const songDuration = (team.song_end - team.song_start) * 1000;

      playTrack(team.song_id, undefined, team.song_start * 1000);

      setTimeout(async () => {
        await pause();
        resolve();
      }, songDuration);
    });
  }, [playTrack, pause]);

  const handleSpeakerClick = useCallback(async () => {
    if (!hasWalkoutData || !match.home?.name || !match.away?.name) {
      await speak(`${match.home?.name || "Home"} vs. ${match.away?.name || "Away"}`);
      return;
    }

    try {
      const homeTeam = match.home as Team;
      const awayTeam = match.away as Team;

      await playTeamWalkout(homeTeam);
      await speak(homeTeam.name);
      await speak("versus");
      await playTeamWalkout(awayTeam);
      await speak(awayTeam.name);
      await speak("have fun, good luck!");

    } catch (error) {
      console.warn('Walkout sequence error:', error);
      await speak(`${match.home.name} vs. ${match.away.name}`);
    }
  }, [hasWalkoutData, match.home, match.away, speak, playTeamWalkout]);

  const handleStart = useCallback(async () => {
    start.mutate({
      data: match.id,
    });

    // Skip announcements for regional tournaments
    const isRegional = match.tournament?.regional === true;

    // Play walkout sequence after starting the match (only for non-regional tournaments)
    if (!isRegional && hasWalkoutData && match.home?.name && match.away?.name) {
      try {
        const homeTeam = match.home as Team;
        const awayTeam = match.away as Team;

        await playTeamWalkout(homeTeam);
        await speak(homeTeam.name);
        await speak("versus");
        await playTeamWalkout(awayTeam);
        await speak(awayTeam.name);
        await speak("have fun, good luck!");
      } catch (error) {
        console.warn('Auto-walkout sequence error:', error);
      }
    }
  }, [match, start, hasWalkoutData, playTeamWalkout, speak]);

  return (
    <Flex direction="row" align="center" justify="end" gap={8}>
      <Text
        c="dimmed"
        fw="bolder"
        px={6}
        py={2}
        style={{
          backgroundColor: 'var(--mantine-color-body)'
        }}
      >
        {match.order}
      </Text>
      <Flex align="stretch">
        <Indicator
          inline
          processing={match.status === "started"}
          color="red"
          size={12}
          disabled={match.status !== "started" || showEditButton}
        >
          <Card
            w={showToolbar || showEditButton ? 200 : 220}
            withBorder
            pos="relative"
            style={{
              overflow: "visible",
              backgroundColor: 'var(--mantine-color-body)',
              borderColor: 'var(--mantine-color-default-border)',
              boxShadow: 'var(--mantine-shadow-sm)',
            }}
            data-match-lid={match.lid}
          >
            <Card.Section withBorder p={0}>
              <MatchSlot {...homeSlot} />
            </Card.Section>

            <Card.Section p={0} mb={-16}>
              <MatchSlot {...awaySlot} />
            </Card.Section>

            {match.reset && (
              <Text
                pos="absolute"
                top={-20}
                left={8}
                size="xs"
                c="dimmed"
                fw="bold"
              >
                * If necessary
              </Text>
            )}

            {showControls && match.status !== "tbd" && (
              <ActionIcon
                pos="absolute"
                bottom={-2}
                left={-26}
                size="sm"
                variant="subtle"
                color="gray"
                onClick={handleSpeakerClick}
              >
                <SpeakerHighIcon size={12} />
              </ActionIcon>
            )}
          </Card>
        </Indicator>

        {showToolbar && (
          <Flex direction="column" justify="center" align="center">
            <ActionIcon
              color="green"
              onClick={handleStart}
              size="sm"
              h="100%"
              radius="sm"
              ml={-4}
              style={{
                borderTopLeftRadius: 0,
                borderBottomLeftRadius: 0,
              }}
            >
              <PlayIcon size={14} />
            </ActionIcon>
          </Flex>
        )}


        {showEditButton && (
          <Flex direction="column" justify="center" align="center">
            <ActionIcon
              color="blue"
              onClick={editSheet.open}
              size="sm"
              h="100%"
              radius="sm"
              ml={-4}
              style={{
                borderTopLeftRadius: 0,
                borderBottomLeftRadius: 0,
              }}
            >
              <PencilIcon size={14} />
            </ActionIcon>
          </Flex>
        )}
      </Flex>

      <Sheet title="Edit Match" {...editSheet.props}>
        <MatchForm
          match={match}
          onSubmit={handleFormSubmit}
          onCancel={editSheet.close}
        />
      </Sheet>
    </Flex>
  );
};
