import {
  Badge,
  Box,
  ClipboardRoot,
  ClipboardTrigger,
  Flex,
  HStack,
  Spinner,
  Stack,
  Table,
  Tabs,
  Text,
} from '@chakra-ui/react'
import { Copy, Users } from 'lucide-react'
import { useEffect, useState } from 'react'
import { useOutletContext } from 'react-router-dom'
import {
  CalledItButton,
  CalledItCard,
  CalledItDialog,
  CalledItTextInput,
} from '../components'
import {
  createGroup,
  deleteGroup,
  fetchGroupLeaderboard,
  joinGroup,
  leaveGroup,
  type GroupDto,
} from '../features/groups/groupApi'
import { useGroups } from '../features/groups/useGroups'
import { fetchLeaderboard, type LeaderboardEntry, type LeaderboardResult } from '../features/leaderboard/leaderboardApi'
import type { AppOutletContext } from '../types/auth'

function rankPalette(rank: number): string {
  if (rank === 1) return 'yellow'
  if (rank === 2) return 'gray'
  if (rank === 3) return 'orange'
  return 'brand'
}

function LeaderboardRow({ entry, currentUsername }: { entry: LeaderboardEntry; currentUsername: string }) {
  return (
    <Table.Row key={entry.username}>
      <Table.Cell textAlign="center">
        <Badge colorPalette={rankPalette(entry.rank)} variant="subtle">
          {entry.rank}
        </Badge>
      </Table.Cell>
      <Table.Cell>
        <Stack direction="row" align="center" gap="2">
          <Text fontWeight={entry.username === currentUsername ? '700' : '400'}>
            {entry.username}
          </Text>
          {entry.username === currentUsername && (
            <Badge colorPalette="brand" variant="solid" fontSize="2xs">
              You
            </Badge>
          )}
        </Stack>
      </Table.Cell>
      <Table.Cell textAlign="right" fontWeight="700">
        {entry.totalPoints}
      </Table.Cell>
      <Table.Cell textAlign="right" color="muted">
        {entry.betsEvaluated}
      </Table.Cell>
      <Table.Cell textAlign="right" color="muted">
        {entry.betsPlaced}
      </Table.Cell>
    </Table.Row>
  )
}

function LeaderboardTable({
  entries,
  currentUsername,
  currentUserEntry,
}: {
  entries: LeaderboardEntry[]
  currentUsername: string
  currentUserEntry?: LeaderboardEntry | null
}) {
  if (entries.length === 0 && !currentUserEntry) {
    return <Text color="muted">No bets have been placed yet.</Text>
  }
  return (
    <Table.Root variant="line" size="sm">
      <Table.Header>
        <Table.Row>
          <Table.ColumnHeader w="12" textAlign="center">#</Table.ColumnHeader>
          <Table.ColumnHeader>Player</Table.ColumnHeader>
          <Table.ColumnHeader textAlign="right">Points</Table.ColumnHeader>
          <Table.ColumnHeader textAlign="right">Evaluated</Table.ColumnHeader>
          <Table.ColumnHeader textAlign="right">Placed</Table.ColumnHeader>
        </Table.Row>
      </Table.Header>
      <Table.Body>
        {entries.map((entry) => (
          <LeaderboardRow key={entry.username} entry={entry} currentUsername={currentUsername} />
        ))}
        {currentUserEntry && (
          <>
            <Table.Row>
              <Table.Cell colSpan={5} py="0">
                <Box borderTop="2px dashed" borderColor="border" />
              </Table.Cell>
            </Table.Row>
            <LeaderboardRow entry={currentUserEntry} currentUsername={currentUsername} />
          </>
        )}
      </Table.Body>
    </Table.Root>
  )
}

function GroupLeaderboardTab({
  token,
  group,
  currentUsername,
}: {
  token: string
  group: GroupDto
  currentUsername: string
}) {
  const [entries, setEntries] = useState<LeaderboardEntry[]>([])
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState<string | null>(null)

  useEffect(() => {
    setLoading(true)
    setError(null)
    fetchGroupLeaderboard(token, group.id)
      .then((data) => {
        setEntries(data)
        setLoading(false)
      })
      .catch((err: unknown) => {
        setError(err instanceof Error ? err.message : 'Failed to load')
        setLoading(false)
      })
  }, [token, group.id])

  if (loading) return <Flex justify="center" py="6"><Spinner /></Flex>
  if (error) return <Text color="red.500">{error}</Text>
  return <LeaderboardTable entries={entries} currentUsername={currentUsername} />
}

type GroupsDialogView = 'menu' | 'create' | 'join' | 'created' | 'leave-confirm'

export function LeaderboardPage() {
  const { session, selectedCompetitionId } = useOutletContext<AppOutletContext>()
  const competitionId = selectedCompetitionId ? Number(selectedCompetitionId) : null

  const [globalResult, setGlobalResult] = useState<LeaderboardResult | null>(null)
  const [globalLoading, setGlobalLoading] = useState(false)
  const [globalError, setGlobalError] = useState<string | null>(null)

  const { groups, refetch: refetchGroups } = useGroups(session.token, competitionId)

  const [dialogOpen, setDialogOpen] = useState(false)
  const [dialogView, setDialogView] = useState<GroupsDialogView>('menu')
  const [groupName, setGroupName] = useState('')
  const [groupNameError, setGroupNameError] = useState<string | undefined>()
  const [inviteCodeInput, setInviteCodeInput] = useState('')
  const [inviteCodeError, setInviteCodeError] = useState<string | undefined>()
  const [createdGroup, setCreatedGroup] = useState<GroupDto | null>(null)
  const [actionLoading, setActionLoading] = useState(false)
  const [pendingLeaveGroup, setPendingLeaveGroup] = useState<GroupDto | null>(null)

  function openLeaveConfirm(group: GroupDto) {
    setPendingLeaveGroup(group)
    setDialogView('leave-confirm')
  }

  useEffect(() => {
    if (!competitionId) return
    setGlobalLoading(true)
    setGlobalError(null)
    fetchLeaderboard(session.token, competitionId)
      .then((data) => {
        setGlobalResult(data)
        setGlobalLoading(false)
      })
      .catch((err: unknown) => {
        setGlobalError(err instanceof Error ? err.message : 'Failed to load leaderboard')
        setGlobalLoading(false)
      })
  }, [session.token, competitionId])

  function openDialog() {
    setDialogView('menu')
    setGroupName('')
    setGroupNameError(undefined)
    setInviteCodeInput('')
    setInviteCodeError(undefined)
    setCreatedGroup(null)
    setDialogOpen(true)
  }

  function closeDialog() {
    setDialogOpen(false)
  }

  async function handleCreateGroup() {
    if (!groupName.trim()) {
      setGroupNameError('Required')
      return
    }
    if (!competitionId) return
    setActionLoading(true)
    try {
      const group = await createGroup(session.token, groupName.trim(), competitionId)
      setCreatedGroup(group)
      setDialogView('created')
      refetchGroups()
    } catch (err) {
      setGroupNameError(err instanceof Error ? err.message : 'Failed to create group')
    } finally {
      setActionLoading(false)
    }
  }

  async function handleJoinGroup() {
    if (!inviteCodeInput.trim()) {
      setInviteCodeError('Required')
      return
    }
    setActionLoading(true)
    try {
      await joinGroup(session.token, inviteCodeInput.trim())
      refetchGroups()
      closeDialog()
    } catch (err) {
      setInviteCodeError(err instanceof Error ? err.message : 'Failed to join group')
    } finally {
      setActionLoading(false)
    }
  }

  async function confirmLeaveGroup() {
    if (!pendingLeaveGroup) return
    try {
      await leaveGroup(session.token, pendingLeaveGroup.id)
      refetchGroups()
      setPendingLeaveGroup(null)
      setDialogView('menu')
    } catch (err) {
      alert(err instanceof Error ? err.message : 'Failed to leave group')
      setDialogView('menu')
    }
  }

  async function handleDeleteGroup(group: GroupDto) {
    if (!confirm(`Delete group "${group.name}"? This cannot be undone.`)) return
    try {
      await deleteGroup(session.token, group.id)
      refetchGroups()
    } catch (err) {
      alert(err instanceof Error ? err.message : 'Failed to delete group')
    }
  }

  if (!selectedCompetitionId) {
    return (
      <CalledItCard cardTitle="Leaderboard">
        <Text color="muted">Select a competition from the header to view the leaderboard.</Text>
      </CalledItCard>
    )
  }

  const dialogTitle =
    dialogView === 'create' ? 'Create Group' :
    dialogView === 'join' ? 'Join Group' :
    dialogView === 'created' ? 'Group Created' :
    dialogView === 'leave-confirm' ? 'Leave Group' :
    'Groups'

  return (
    <>
      <CalledItCard
        cardTitle={
          <Flex justify="space-between" align="center" w="full">
            <Text color="heading" fontWeight="semibold" fontSize="lg">Leaderboard</Text>
            <CalledItButton size="sm" variant="outline" onClick={openDialog}>
              <Users size={14} />
              Groups
            </CalledItButton>
          </Flex>
        }
      >
        {globalLoading ? (
          <Flex justify="center" py="6"><Spinner /></Flex>
        ) : globalError ? (
          <Text color="red.500">{globalError}</Text>
        ) : (
          <Tabs.Root defaultValue="global" variant="line">
            <Tabs.List>
              <Tabs.Trigger value="global">Global</Tabs.Trigger>
              {groups.map((g) => (
                <Tabs.Trigger key={g.id} value={`group-${g.id}`}>
                  {g.name}
                  <Badge colorPalette="brand" variant="subtle" fontSize="2xs" ml="1">
                    {g.memberCount}
                  </Badge>
                </Tabs.Trigger>
              ))}
            </Tabs.List>

            <Tabs.Content value="global">
              <Box pt="3">
                <LeaderboardTable
                  entries={globalResult?.entries ?? []}
                  currentUsername={session.username}
                  currentUserEntry={globalResult?.currentUserEntry}
                />
              </Box>
            </Tabs.Content>

            {groups.map((g) => (
              <Tabs.Content key={g.id} value={`group-${g.id}`}>
                <Box pt="3">
                  <GroupLeaderboardTab
                    token={session.token}
                    group={g}
                    currentUsername={session.username}
                  />
                </Box>
              </Tabs.Content>
            ))}
          </Tabs.Root>
        )}
      </CalledItCard>

      <CalledItDialog open={dialogOpen} onClose={closeDialog} title={dialogTitle}>
        {dialogView === 'menu' && (
          <Stack gap="3">
            <Stack gap="2">
              <CalledItButton onClick={() => setDialogView('create')} disabled={!competitionId}>
                Create a new group
              </CalledItButton>
              <CalledItButton variant="outline" onClick={() => setDialogView('join')}>
                Join with invite code
              </CalledItButton>
            </Stack>

            {groups.length > 0 && (
              <Box borderTop="1px solid" borderColor="border" pt="3">
                <Text fontSize="sm" fontWeight="semibold" color="heading" mb="2">
                  Your groups
                </Text>
                <Stack gap="2">
                  {groups.map((g) => (
                    <Flex key={g.id} align="center" justify="space-between" gap="2">
                      <Stack gap="0">
                        <Text fontSize="sm" fontWeight="medium">{g.name}</Text>
                        <Text fontSize="xs" color="muted">{g.memberCount} member{g.memberCount !== 1 ? 's' : ''}</Text>
                      </Stack>
                      <HStack gap="1">
                        <ClipboardRoot value={g.inviteCode} timeout={2000}>
                          <ClipboardTrigger asChild>
                            <CalledItButton size="xs" variant="ghost" aria-label="Copy invite code">
                              <Copy size={12} />
                            </CalledItButton>
                          </ClipboardTrigger>
                        </ClipboardRoot>
                        {g.isOwner ? (
                          <CalledItButton
                            size="xs"
                            colorPalette="red"
                            variant="ghost"
                            onClick={() => handleDeleteGroup(g)}
                          >
                            Delete
                          </CalledItButton>
                        ) : (
                          <CalledItButton
                            size="xs"
                            variant="ghost"
                            onClick={() => openLeaveConfirm(g)}
                          >
                            Leave
                          </CalledItButton>
                        )}
                      </HStack>
                    </Flex>
                  ))}
                </Stack>
              </Box>
            )}
          </Stack>
        )}

        {dialogView === 'create' && (
          <Stack gap="4">
            <CalledItTextInput
              label="Group name"
              placeholder="e.g. Office Crew"
              value={groupName}
              onChange={(e) => { setGroupName(e.target.value); setGroupNameError(undefined) }}
              errorText={groupNameError}
            />
            <HStack justify="flex-end">
              <CalledItButton variant="outline" onClick={() => setDialogView('menu')}>
                Back
              </CalledItButton>
              <CalledItButton onClick={handleCreateGroup} loading={actionLoading}>
                Create
              </CalledItButton>
            </HStack>
          </Stack>
        )}

        {dialogView === 'join' && (
          <Stack gap="4">
            <CalledItTextInput
              label="Invite code"
              placeholder="e.g. AB3X7KNP"
              value={inviteCodeInput}
              onChange={(e) => { setInviteCodeInput(e.target.value); setInviteCodeError(undefined) }}
              errorText={inviteCodeError}
            />
            <HStack justify="flex-end">
              <CalledItButton variant="outline" onClick={() => setDialogView('menu')}>
                Back
              </CalledItButton>
              <CalledItButton onClick={handleJoinGroup} loading={actionLoading}>
                Join
              </CalledItButton>
            </HStack>
          </Stack>
        )}

        {dialogView === 'leave-confirm' && pendingLeaveGroup && (
          <Stack gap="4">
            <Text color="text">
              Leave <strong>{pendingLeaveGroup.name}</strong>? You can rejoin later with the invite code.
            </Text>
            <HStack justify="flex-end">
              <CalledItButton variant="outline" onClick={() => { setPendingLeaveGroup(null); setDialogView('menu') }}>
                Cancel
              </CalledItButton>
              <CalledItButton colorPalette="red" onClick={confirmLeaveGroup}>
                Leave
              </CalledItButton>
            </HStack>
          </Stack>
        )}

        {dialogView === 'created' && createdGroup && (
          <Stack gap="4">
            <Text color="text">
              Group <strong>{createdGroup.name}</strong> created! Share the invite code below with friends.
            </Text>
            <Flex
              align="center"
              justify="space-between"
              bg="accentSubtle"
              border="1px solid"
              borderColor="border"
              borderRadius="lg"
              px="4"
              py="3"
              gap="2"
            >
              <Text fontFamily="mono" fontWeight="bold" fontSize="lg" letterSpacing="wider" color="heading">
                {createdGroup.inviteCode}
              </Text>
              <ClipboardRoot value={createdGroup.inviteCode} timeout={2000}>
                <ClipboardTrigger asChild>
                  <CalledItButton size="sm" variant="outline" aria-label="Copy invite code">
                    <Copy size={14} />
                  </CalledItButton>
                </ClipboardTrigger>
              </ClipboardRoot>
            </Flex>
            <Flex justify="flex-end">
              <CalledItButton onClick={closeDialog}>Done</CalledItButton>
            </Flex>
          </Stack>
        )}
      </CalledItDialog>

    </>
  )
}
