// SPDX-FileCopyrightText: 2025 Weibo, Inc.
//
// SPDX-License-Identifier: Apache-2.0

'use client'

import React, { useCallback, useEffect, useState, useMemo } from 'react'
import '@/features/common/scrollbar.css'
import LoadingState from '@/features/common/LoadingState'
import {
  PencilIcon,
  TrashIcon,
  DocumentDuplicateIcon,
  ChatBubbleLeftEllipsisIcon,
  ShareIcon,
  CodeBracketIcon,
  LinkSlashIcon,
  SparklesIcon,
} from '@heroicons/react/24/outline'
import { Bot, Team } from '@/types/api'
import {
  fetchTeamsList,
  deleteTeam,
  shareTeam,
  checkTeamRunningTasks,
  copyTeam,
} from '../services/teams'
import { teamApis } from '@/apis/team'
import { CheckRunningTasksResponse } from '@/apis/common'
import { fetchBotsList } from '../services/bots'
import TeamEditDialog from './TeamEditDialog'
import BotList from './BotList'
import { ForceDeleteTaskSummary } from './ForceDeleteTaskSummary'
import UnifiedAddButton from '@/components/common/UnifiedAddButton'
import TeamShareModal from './TeamShareModal'
import TeamCreationWizard from './wizard/TeamCreationWizard'
import { TeamApiCallButton } from './TeamApiCallButton'
import { useTranslation } from '@/hooks/useTranslation'
import { useToast } from '@/hooks/use-toast'
import { getTeamDisplayName, sortTeamsByUpdatedAt } from '@/utils/team'
import { isGroupTeam, isPublicTeam, isSharedTeam } from '@/utils/team-permissions'
import type { BaseRole } from '@/types/base-role'
import { sortBotsByUpdatedAt } from '@/utils/bot'
import { useRouter } from 'next/navigation'
import { Loader2, Bot as BotIcon } from 'lucide-react'
import { Button } from '@/components/ui/button'
import { Card } from '@/components/ui/card'
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from '@/components/ui/dialog'
import { ResourceListItem } from '@/components/common/ResourceListItem'
import { TeamIconDisplay } from './teams/TeamIconDisplay'
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuTrigger,
} from '@/components/ui/dropdown'
import { listGroups } from '@/apis/groups'
import type { Group } from '@/types/group'

interface TeamListProps {
  scope?: 'personal' | 'group' | 'all'
  groupName?: string
  groupRoleMap?: Map<string, BaseRole>
  onEditResource?: (namespace: string) => void
}

// Mode filter type
type ModeFilter = 'all' | 'chat' | 'code'

export default function TeamList({
  scope = 'personal',
  groupName,
  groupRoleMap,
  onEditResource,
}: TeamListProps) {
  const { t } = useTranslation(['common', 'wizard'])
  const { toast } = useToast()
  const [teams, setTeams] = useState<Team[]>([])
  const [bots, setBots] = useState<Bot[]>([])
  const [isLoading, setIsLoading] = useState(true)
  const [editingTeamId, setEditingTeamId] = useState<number | null>(null)
  const [prefillTeam, setPrefillTeam] = useState<Team | null>(null)
  const [deleteConfirmVisible, setDeleteConfirmVisible] = useState(false)
  const [forceDeleteConfirmVisible, setForceDeleteConfirmVisible] = useState(false)
  const [teamToDelete, setTeamToDelete] = useState<number | null>(null)
  const [isUnbindingSharedTeam, setIsUnbindingSharedTeam] = useState(false)
  const [runningTasksInfo, setRunningTasksInfo] = useState<CheckRunningTasksResponse | null>(null)
  const [isCheckingTasks, setIsCheckingTasks] = useState(false)
  const [shareModalVisible, setShareModalVisible] = useState(false)
  const [shareData, setShareData] = useState<{ teamName: string; shareUrl: string } | null>(null)
  const [sharingId, setSharingId] = useState<number | null>(null)
  const [isDeleting, setIsDeleting] = useState(false)
  const [botListVisible, setBotListVisible] = useState(false)
  const [editDialogOpen, setEditDialogOpen] = useState(false)
  const [modeFilter, setModeFilter] = useState<ModeFilter>('all')
  const [wizardOpen, setWizardOpen] = useState(false)
  const [copyingTeamId, setCopyingTeamId] = useState<number | null>(null)
  const [skillsDialogOpen, setSkillsDialogOpen] = useState(false)
  const [pendingCopy, setPendingCopy] = useState<{
    team: Team
    targetNamespace: string
    personalSkills: Array<{ id: number; name: string; description: string }>
  } | null>(null)
  // Groups where user has at least Developer role (for copy target selection)
  const [writableGroups, setWritableGroups] = useState<Group[]>([])
  const router = useRouter()

  const setTeamsSorted = useCallback<React.Dispatch<React.SetStateAction<Team[]>>>(
    updater => {
      setTeams(prev => {
        const next =
          typeof updater === 'function' ? (updater as (value: Team[]) => Team[])(prev) : updater
        return sortTeamsByUpdatedAt(next)
      })
    },
    [setTeams]
  )

  const setBotsSorted = useCallback<React.Dispatch<React.SetStateAction<Bot[]>>>(
    updater => {
      setBots(prev => {
        const next =
          typeof updater === 'function' ? (updater as (value: Bot[]) => Bot[])(prev) : updater
        return sortBotsByUpdatedAt(next)
      })
    },
    [setBots]
  )

  useEffect(() => {
    async function loadData() {
      setIsLoading(true)
      try {
        const [teamsData, botsData] = await Promise.all([
          fetchTeamsList(scope, groupName),
          fetchBotsList(scope, groupName),
        ])
        setTeamsSorted(teamsData)
        setBotsSorted(botsData)
      } catch {
        toast({
          variant: 'destructive',
          title: t('teams.loading'),
        })
      } finally {
        setIsLoading(false)
      }
    }
    loadData()
  }, [toast, setBotsSorted, setTeamsSorted, t, scope, groupName])

  // Load groups where user has at least Developer role (for copy target selection)
  useEffect(() => {
    listGroups({ limit: 100 })
      .then(data => {
        const writable = (data.items || []).filter(
          g => g.my_role === 'Owner' || g.my_role === 'Maintainer' || g.my_role === 'Developer'
        )
        setWritableGroups(writable)
      })
      .catch(() => {})
  }, [])

  useEffect(() => {
    if (editingTeamId === null) {
      setPrefillTeam(null)
    }
  }, [editingTeamId])

  const handleCreateTeam = () => {
    // Validation for group scope: must have groupName
    if (scope === 'group' && !groupName) {
      toast({
        variant: 'destructive',
        title: t('teams.group_required_title'),
        description: t('teams.group_required_message'),
      })
      return
    }

    setPrefillTeam(null)
    setEditingTeamId(0) // Use 0 to mark new creation
    setEditDialogOpen(true)
  }

  const handleEditTeam = (team: Team) => {
    // Notify parent to update group selector if editing a group resource
    if (onEditResource && team.namespace && team.namespace !== 'default') {
      onEditResource(team.namespace)
    }
    setPrefillTeam(null)
    setEditingTeamId(team.id)
    setEditDialogOpen(true)
  }

  const executeCopyTeam = async (team: Team, targetNamespace: string, copySkills: boolean) => {
    setCopyingTeamId(team.id)
    try {
      const copied = await copyTeam(team.id, targetNamespace, copySkills)
      // Only update local list if copying to the same namespace we're currently viewing
      const currentNamespace = scope === 'group' ? groupName : 'default'
      const copiedNamespace = copied.namespace || 'default'
      if (copiedNamespace === currentNamespace) {
        setTeamsSorted(prev => [copied, ...prev])
      }
      // Refresh bots so the cloned bot (solo mode) is available in edit dialog
      fetchBotsList(scope, groupName)
        .then(setBotsSorted)
        .catch(() => {})
      toast({
        title: t('teams.copy_success'),
      })
    } catch (error) {
      toast({
        variant: 'destructive',
        title: (error as Error)?.message || t('teams.copy_failed'),
      })
    } finally {
      setCopyingTeamId(null)
    }
  }

  const handleSkillsDialogConfirm = async (copySkills: boolean) => {
    setSkillsDialogOpen(false)
    if (!pendingCopy) return
    await executeCopyTeam(pendingCopy.team, pendingCopy.targetNamespace, copySkills)
    setPendingCopy(null)
  }

  const handleCopyTeam = async (team: Team, targetNamespace?: string) => {
    const resolvedNamespace = targetNamespace ?? 'default'
    try {
      // Only do preflight when copying to a group namespace (not personal)
      if (resolvedNamespace !== 'default') {
        const preflight = await teamApis.copyPreflight(team.id, resolvedNamespace)
        if (preflight.personal_skills.length > 0) {
          setPendingCopy({
            team,
            targetNamespace: resolvedNamespace,
            personalSkills: preflight.personal_skills,
          })
          setSkillsDialogOpen(true)
          return
        }
      }
      // No personal skills or copying to personal — copy directly
      await executeCopyTeam(team, resolvedNamespace, false)
    } catch (error) {
      console.error('Copy preflight failed:', error)
      // Still try copying even if preflight fails
      await executeCopyTeam(team, resolvedNamespace, false)
    }
  }

  const handleCloseEditDialog = () => {
    setEditDialogOpen(false)
    setEditingTeamId(null)
    setPrefillTeam(null)
  }

  const handleWizardSuccess = async (_teamId: number, teamName: string) => {
    toast({
      title: t('wizard:create_agent'),
      description: `${teamName}`,
    })
    // Reload teams list
    const teamsData = await fetchTeamsList(scope, groupName)
    setTeamsSorted(teamsData)
    setWizardOpen(false)
  }

  const handleOpenWizard = () => {
    // Validation for group scope: must have groupName
    if (scope === 'group' && !groupName) {
      toast({
        variant: 'destructive',
        title: t('teams.group_required_title'),
        description: t('teams.group_required_message'),
      })
      return
    }
    setWizardOpen(true)
  }

  // Get target page based on team's bind_mode and current filter
  const getTargetPage = (team: Team): 'chat' | 'code' | 'knowledge' | 'task' | 'video' => {
    const bindMode = team.bind_mode || ['chat', 'code']
    // If team only supports one mode, use that
    if (bindMode.length === 1) {
      return bindMode[0] as 'chat' | 'code' | 'knowledge' | 'task' | 'video'
    }
    // If team supports both, use current filter (default to 'chat' if filter is 'all')
    if (modeFilter !== 'all') {
      return modeFilter
    }
    // Default to 'chat' when filter is 'all' and team supports both
    return 'chat'
  }

  const handleChatTeam = (team: Team) => {
    const params = new URLSearchParams()
    params.set('teamId', String(team.id))
    const targetPage = getTargetPage(team)
    router.push(`/${targetPage}?${params.toString()}`)
  }

  // Filter teams based on mode filter
  const filteredTeams = useMemo(() => {
    if (modeFilter === 'all') {
      return teams
    }
    return teams.filter(team => {
      const bindMode = team.bind_mode || ['chat', 'code']
      return bindMode.includes(modeFilter)
    })
  }, [teams, modeFilter])

  // Helper function to check permissions for a specific group resource
  const canEditGroupResource = (namespace: string) => {
    if (!groupRoleMap) return false
    const role = groupRoleMap.get(namespace)
    return role === 'Owner' || role === 'Maintainer' || role === 'Developer'
  }

  const canDeleteGroupResource = (namespace: string) => {
    if (!groupRoleMap) return false
    const role = groupRoleMap.get(namespace)
    return role === 'Owner' || role === 'Maintainer'
  }

  // Check if user can create in the current group context
  // When scope is 'group', check the specific groupName; only Owner/Maintainer can create
  const canCreateInCurrentGroup = (() => {
    if (scope !== 'group' || !groupName || !groupRoleMap) return false
    const role = groupRoleMap.get(groupName)
    return role === 'Owner' || role === 'Maintainer'
  })()

  const handleDelete = async (teamId: number) => {
    setTeamToDelete(teamId)
    setIsCheckingTasks(true)

    // Check if this is a shared team
    const team = teams.find(t => t.id === teamId)
    const isShared = team?.share_status === 2
    setIsUnbindingSharedTeam(isShared)

    // For shared teams, skip running tasks check and show unbind confirmation directly
    if (isShared) {
      setIsCheckingTasks(false)
      setDeleteConfirmVisible(true)
      return
    }

    try {
      // Check if team has running tasks
      const result = await checkTeamRunningTasks(teamId)
      setRunningTasksInfo(result)

      if (result.has_running_tasks) {
        // Show force delete confirmation dialog
        setForceDeleteConfirmVisible(true)
      } else {
        // Show normal delete confirmation dialog
        setDeleteConfirmVisible(true)
      }
    } catch (e) {
      // If check fails, show normal delete dialog
      console.error('Failed to check running tasks:', e)
      setDeleteConfirmVisible(true)
    } finally {
      setIsCheckingTasks(false)
    }
  }

  const handleConfirmDelete = async () => {
    if (!teamToDelete) return

    setIsDeleting(true)
    try {
      await deleteTeam(teamToDelete)
      setTeamsSorted(prev => prev.filter(team => team.id !== teamToDelete))
      setDeleteConfirmVisible(false)
      setTeamToDelete(null)
      setRunningTasksInfo(null)
    } catch {
      toast({
        variant: 'destructive',
        title: t('teams.delete'),
      })
    } finally {
      setIsDeleting(false)
    }
  }

  const handleForceDelete = async () => {
    if (!teamToDelete) return

    setIsDeleting(true)
    try {
      await deleteTeam(teamToDelete, true)
      setTeamsSorted(prev => prev.filter(team => team.id !== teamToDelete))
      setForceDeleteConfirmVisible(false)
      setTeamToDelete(null)
      setRunningTasksInfo(null)
    } catch {
      toast({
        variant: 'destructive',
        title: t('teams.delete'),
      })
    } finally {
      setIsDeleting(false)
    }
  }

  const handleCancelDelete = () => {
    setDeleteConfirmVisible(false)
    setForceDeleteConfirmVisible(false)
    setTeamToDelete(null)
    setRunningTasksInfo(null)
    setIsUnbindingSharedTeam(false)
  }

  const handleShareTeam = async (team: Team) => {
    setSharingId(team.id)
    try {
      const response = await shareTeam(team.id)
      setShareData({
        teamName: team.name,
        shareUrl: response.share_url,
      })
      setShareModalVisible(true)
      // Update team status to sharing
      setTeamsSorted(prev => prev.map(t => (t.id === team.id ? { ...t, share_status: 1 } : t)))
    } catch {
      toast({
        variant: 'destructive',
        title: t('teams.share_failed'),
      })
    } finally {
      setSharingId(null)
    }
  }

  const handleCloseShareModal = () => {
    setShareModalVisible(false)
    setShareData(null)
  }

  // Check if edit button should be shown (uses shared permission utility)
  // Note: shouldShowEdit doesn't need userId because it checks structural properties
  // For personal teams, TeamList always shows edit (the team owner is always viewing their own teams)
  const shouldShowEdit = (team: Team) => {
    if (isPublicTeam(team)) return false
    if (isSharedTeam(team)) return false
    if (isGroupTeam(team)) {
      return canEditGroupResource(team.namespace!)
    }
    return true
  }

  // Check if delete/unbind button should be shown
  const shouldShowDelete = (team: Team) => {
    // Public teams cannot be deleted by regular users (managed by admin)
    if (isPublicTeam(team)) return false
    // For group teams, check group permissions
    if (isGroupTeam(team)) {
      return canDeleteGroupResource(team.namespace!)
    }
    // For personal teams, always show
    return true
  }

  // Check if share button should be shown
  const shouldShowShare = (team: Team) => {
    // Public teams don't support sharing (they're already globally available)
    if (isPublicTeam(team)) return false
    // Group teams don't support sharing (for now)
    if (isGroupTeam(team)) return false
    // Personal teams (no share_status or share_status=0 or share_status=1) show share button
    return !team.share_status || team.share_status === 0 || team.share_status === 1
  }

  // Check if copy button should be shown (same permission as create)
  const shouldShowCopy = (team: Team) => {
    // Read-only teams (public or shared from others) cannot be copied
    if (isPublicTeam(team)) return false
    if (isSharedTeam(team)) return false
    // For group teams, check group permissions (need create permission)
    if (isGroupTeam(team)) {
      return canDeleteGroupResource(team.namespace!) // Maintainer/Owner can create
    }
    // For personal teams, always show
    return true
  }

  return (
    <>
      <div className="flex flex-col h-full min-h-0 overflow-hidden w-full max-w-full">
        <div className="flex-shrink-0 mb-3">
          <h2 className="text-xl font-semibold text-text-primary mb-1">{t('teams.title')}</h2>
          <p className="text-sm text-text-muted mb-1">{t('teams.description')}</p>
        </div>
        <div className="bg-base border border-border rounded-md p-2 w-full max-w-full overflow-hidden max-h-[70vh] flex flex-col overflow-y-auto custom-scrollbar">
          {/* Mode filter tabs */}
          <div className="flex items-center gap-1 mb-3 pb-2 border-b border-border">
            <button
              type="button"
              onClick={() => setModeFilter('all')}
              className={`flex items-center gap-1.5 px-3 py-1.5 text-sm font-medium rounded-md transition-colors ${
                modeFilter === 'all'
                  ? 'bg-primary text-white'
                  : 'bg-muted text-text-secondary hover:text-text-primary hover:bg-hover'
              }`}
            >
              {t('teams.filter_all')}
            </button>
            <button
              type="button"
              onClick={() => setModeFilter('chat')}
              className={`flex items-center gap-1.5 px-3 py-1.5 text-sm font-medium rounded-md transition-colors ${
                modeFilter === 'chat'
                  ? 'bg-primary text-white'
                  : 'bg-muted text-text-secondary hover:text-text-primary hover:bg-hover'
              }`}
            >
              <ChatBubbleLeftEllipsisIcon className="w-4 h-4" />
              {t('teams.filter_chat')}
            </button>
            <button
              type="button"
              onClick={() => setModeFilter('code')}
              className={`flex items-center gap-1.5 px-3 py-1.5 text-sm font-medium rounded-md transition-colors ${
                modeFilter === 'code'
                  ? 'bg-primary text-white'
                  : 'bg-muted text-text-secondary hover:text-text-primary hover:bg-hover'
              }`}
            >
              <CodeBracketIcon className="w-4 h-4" />
              {t('teams.filter_code')}
            </button>
          </div>
          {isLoading ? (
            <LoadingState fullScreen={false} message={t('teams.loading')} />
          ) : (
            <>
              <div className="flex-1 overflow-y-auto overflow-x-hidden custom-scrollbar space-y-3 p-1">
                {filteredTeams.length > 0 ? (
                  filteredTeams.map(team => (
                    <Card
                      key={team.id}
                      className="p-3 sm:p-4 bg-base hover:bg-hover transition-colors overflow-hidden"
                    >
                      <div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-2 sm:gap-0 min-w-0">
                        <ResourceListItem
                          name={team.name}
                          displayName={getTeamDisplayName(team)}
                          description={team.description}
                          icon={
                            <TeamIconDisplay
                              iconId={team.icon}
                              size="md"
                              className="text-primary"
                            />
                          }
                          tags={[
                            ...(isPublicTeam(team)
                              ? [
                                  {
                                    key: 'public',
                                    label: t('teams.public'),
                                    variant: 'default' as const,
                                  },
                                ]
                              : []),
                            ...(team.workflow?.mode
                              ? [
                                  {
                                    key: 'mode',
                                    label: t(`team_model.${String(team.workflow.mode)}`),
                                    variant: 'default' as const,
                                    className: 'capitalize text-xs',
                                  },
                                ]
                              : []),
                            ...(team.share_status === 1
                              ? [
                                  {
                                    key: 'sharing',
                                    label: t('teams.sharing'),
                                    variant: 'info' as const,
                                  },
                                ]
                              : []),
                            ...(team.share_status === 2 && team.user?.user_name
                              ? [
                                  {
                                    key: 'shared',
                                    label: t('teams.shared_by', {
                                      author: team.user.user_name,
                                    }),
                                    variant: 'success' as const,
                                  },
                                ]
                              : []),
                            ...(team.bots.length > 0
                              ? [
                                  {
                                    key: 'bots',
                                    label: `${team.bots.length} ${team.bots.length === 1 ? 'Bot' : 'Bots'}`,
                                    variant: 'info' as const,
                                    className: 'hidden sm:inline-flex text-xs',
                                  },
                                ]
                              : []),
                          ]}
                        >
                          <div className="flex items-center space-x-1 flex-shrink-0">
                            <div
                              className="w-2 h-2 rounded-full"
                              style={{
                                backgroundColor: team.is_active
                                  ? 'rgb(var(--color-success))'
                                  : 'rgb(var(--color-border))',
                              }}
                            ></div>
                            <span className="text-xs text-text-muted">
                              {team.is_active ? t('teams.active') : t('teams.inactive')}
                            </span>
                          </div>
                        </ResourceListItem>
                        <div className="flex items-center gap-0.5 sm:gap-1 flex-shrink-0 sm:ml-3 self-end sm:self-auto">
                          <Button
                            variant="ghost"
                            size="icon"
                            onClick={() => handleChatTeam(team)}
                            title={
                              getTargetPage(team) === 'code'
                                ? t('teams.go_to_code')
                                : t('teams.go_to_chat')
                            }
                            className="h-7 w-7 sm:h-8 sm:w-8"
                          >
                            {getTargetPage(team) === 'code' ? (
                              <CodeBracketIcon className="w-3.5 h-3.5 sm:w-4 sm:h-4" />
                            ) : (
                              <ChatBubbleLeftEllipsisIcon className="w-3.5 h-3.5 sm:w-4 sm:h-4" />
                            )}
                          </Button>
                          <TeamApiCallButton team={team} />
                          {shouldShowEdit(team) && (
                            <Button
                              variant="ghost"
                              size="icon"
                              onClick={() => handleEditTeam(team)}
                              title={t('teams.edit')}
                              className="h-7 w-7 sm:h-8 sm:w-8"
                            >
                              <PencilIcon className="w-3.5 h-3.5 sm:w-4 sm:h-4" />
                            </Button>
                          )}
                          {shouldShowCopy(team) && (
                            <DropdownMenu>
                              <DropdownMenuTrigger asChild>
                                <Button
                                  variant="ghost"
                                  size="icon"
                                  disabled={copyingTeamId === team.id}
                                  title={t('teams.copy')}
                                  className="h-7 w-7 sm:h-8 sm:w-8"
                                  data-testid={`copy-team-button-${team.id}`}
                                >
                                  {copyingTeamId === team.id ? (
                                    <Loader2 className="w-3.5 h-3.5 sm:w-4 sm:h-4 animate-spin" />
                                  ) : (
                                    <DocumentDuplicateIcon className="w-3.5 h-3.5 sm:w-4 sm:h-4" />
                                  )}
                                </Button>
                              </DropdownMenuTrigger>
                              <DropdownMenuContent
                                align="end"
                                className="w-44 max-h-64 overflow-y-auto py-1"
                                style={{ boxShadow: 'var(--shadow-popover)' }}
                              >
                                {/* Section label */}
                                <div className="px-2.5 pb-1 pt-0.5 text-[10px] font-medium uppercase tracking-wide text-text-muted">
                                  {t('teams.copy_to_label')}
                                </div>
                                {/* Personal space */}
                                <DropdownMenuItem
                                  onClick={() => handleCopyTeam(team, 'default')}
                                  className="gap-2 px-2.5 py-1.5 text-xs focus:bg-muted"
                                  data-testid={`copy-team-to-personal-${team.id}`}
                                >
                                  <div className="flex h-[18px] w-[18px] flex-shrink-0 items-center justify-center rounded-[4px] bg-primary/10 text-primary">
                                    <svg
                                      className="h-3 w-3"
                                      fill="none"
                                      stroke="currentColor"
                                      strokeWidth="1.5"
                                      viewBox="0 0 24 24"
                                    >
                                      <path
                                        strokeLinecap="round"
                                        strokeLinejoin="round"
                                        d="M15.75 6a3.75 3.75 0 1 1-7.5 0 3.75 3.75 0 0 1 7.5 0ZM4.501 20.118a7.5 7.5 0 0 1 14.998 0A17.933 17.933 0 0 1 12 21.75c-2.676 0-5.216-.584-7.499-1.632Z"
                                      />
                                    </svg>
                                  </div>
                                  <span className="truncate">{t('teams.copy_to_personal')}</span>
                                </DropdownMenuItem>
                                {/* Groups */}
                                {writableGroups.length > 0 && (
                                  <>
                                    <div className="my-1 h-px bg-border/60" />
                                    {writableGroups.map(group => {
                                      const label = group.display_name || group.name
                                      const initials = label.slice(0, 2).toUpperCase()
                                      return (
                                        <DropdownMenuItem
                                          key={group.name}
                                          onClick={() => handleCopyTeam(team, group.name)}
                                          className="gap-2 px-2.5 py-1.5 text-xs focus:bg-muted"
                                          data-testid={`copy-team-to-group-${team.id}-${group.name}`}
                                        >
                                          <div className="flex h-[18px] w-[18px] flex-shrink-0 items-center justify-center rounded-[4px] bg-primary/10 text-[9px] font-semibold text-primary">
                                            {initials}
                                          </div>
                                          <span className="truncate">{label}</span>
                                        </DropdownMenuItem>
                                      )
                                    })}
                                  </>
                                )}
                              </DropdownMenuContent>
                            </DropdownMenu>
                          )}
                          {shouldShowShare(team) && (
                            <Button
                              variant="ghost"
                              size="icon"
                              onClick={() => handleShareTeam(team)}
                              title={t('teams.share.title')}
                              className="h-7 w-7 sm:h-8 sm:w-8"
                              disabled={sharingId === team.id}
                            >
                              <ShareIcon className="w-3.5 h-3.5 sm:w-4 sm:h-4" />
                            </Button>
                          )}
                          {shouldShowDelete(team) && (
                            <Button
                              variant="ghost"
                              size="icon"
                              onClick={() => handleDelete(team.id)}
                              disabled={isCheckingTasks}
                              title={isSharedTeam(team) ? t('teams.unbind') : t('teams.delete')}
                              className="h-7 w-7 sm:h-8 sm:w-8 hover:text-error"
                            >
                              {isSharedTeam(team) ? (
                                <LinkSlashIcon className="w-3.5 h-3.5 sm:w-4 sm:h-4" />
                              ) : (
                                <TrashIcon className="w-3.5 h-3.5 sm:w-4 sm:h-4" />
                              )}
                            </Button>
                          )}
                        </div>
                      </div>
                    </Card>
                  ))
                ) : (
                  <div className="text-center text-text-muted py-8">
                    <p className="text-sm">{t('teams.no_teams')}</p>
                  </div>
                )}
              </div>
              <div className="border-t border-border pt-3 mt-3 bg-base">
                <div className="flex justify-center gap-3">
                  {(scope === 'personal' || canCreateInCurrentGroup) && (
                    <UnifiedAddButton onClick={handleCreateTeam}>
                      {t('teams.new_team')}
                    </UnifiedAddButton>
                  )}
                  {(scope === 'personal' || canCreateInCurrentGroup) && (
                    <TooltipProvider>
                      <Tooltip>
                        <TooltipTrigger asChild>
                          <Button
                            variant="primary"
                            size="sm"
                            onClick={handleOpenWizard}
                            className="gap-2"
                          >
                            <SparklesIcon className="w-4 h-4" />
                            {t('wizard:wizard_button')}
                          </Button>
                        </TooltipTrigger>
                        <TooltipContent>
                          <p>{t('wizard:wizard_button_tooltip')}</p>
                        </TooltipContent>
                      </Tooltip>
                    </TooltipProvider>
                  )}
                  <UnifiedAddButton
                    variant="outline"
                    onClick={() => setBotListVisible(true)}
                    icon={<BotIcon className="w-4 h-4" />}
                  >
                    {t('bots.manage_bots')}
                  </UnifiedAddButton>
                </div>
              </div>
            </>
          )}
        </div>
      </div>

      {/* Team Edit Dialog */}
      <TeamEditDialog
        open={editDialogOpen}
        onClose={handleCloseEditDialog}
        teams={teams}
        setTeams={setTeamsSorted}
        editingTeamId={editingTeamId}
        initialTeam={prefillTeam}
        bots={bots}
        setBots={setBotsSorted}
        toast={toast}
        scope={scope}
        groupName={groupName}
      />

      {/* Delete/Unbind confirmation dialog */}
      <Dialog
        open={deleteConfirmVisible}
        onOpenChange={open => !open && !isDeleting && setDeleteConfirmVisible(false)}
      >
        <DialogContent>
          <DialogHeader>
            <DialogTitle>
              {isUnbindingSharedTeam
                ? t('teams.unbind_confirm_title')
                : t('teams.delete_confirm_title')}
            </DialogTitle>
            <DialogDescription>
              {isUnbindingSharedTeam
                ? t('teams.unbind_confirm_message')
                : t('teams.delete_confirm_message')}
            </DialogDescription>
          </DialogHeader>
          <DialogFooter>
            <Button variant="secondary" onClick={handleCancelDelete} disabled={isDeleting}>
              {t('common.cancel')}
            </Button>
            <Button variant="destructive" onClick={handleConfirmDelete} disabled={isDeleting}>
              {isDeleting ? (
                <div className="flex items-center">
                  <svg
                    className="animate-spin -ml-1 mr-2 h-4 w-4"
                    xmlns="http://www.w3.org/2000/svg"
                    fill="none"
                    viewBox="0 0 24 24"
                  >
                    <circle
                      className="opacity-25"
                      cx="12"
                      cy="12"
                      r="10"
                      stroke="currentColor"
                      strokeWidth="4"
                    ></circle>
                    <path
                      className="opacity-75"
                      fill="currentColor"
                      d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
                    ></path>
                  </svg>
                  {t('actions.deleting')}
                </div>
              ) : (
                t('common.confirm')
              )}
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      {/* Force delete confirmation dialog for running tasks */}
      <Dialog
        open={forceDeleteConfirmVisible}
        onOpenChange={open => !open && !isDeleting && setForceDeleteConfirmVisible(false)}
      >
        <DialogContent>
          <DialogHeader>
            <DialogTitle>{t('teams.force_delete_confirm_title')}</DialogTitle>
            <DialogDescription>
              {t('teams.force_delete_confirm_message', {
                count: runningTasksInfo?.running_tasks_count || 0,
              })}
            </DialogDescription>
          </DialogHeader>
          <ForceDeleteTaskSummary
            runningTasks={runningTasksInfo?.running_tasks || []}
            runningTasksTitle={t('teams.running_tasks_list')}
            warning={t('teams.force_delete_warning')}
            andMoreLabel={
              runningTasksInfo && runningTasksInfo.running_tasks.length > 5
                ? `... ${t('teams.and_more_tasks', {
                    count: runningTasksInfo.running_tasks.length - 5,
                  })}`
                : undefined
            }
          />
          <DialogFooter>
            <Button variant="secondary" onClick={handleCancelDelete} disabled={isDeleting}>
              {t('common.cancel')}
            </Button>
            <Button variant="destructive" onClick={handleForceDelete} disabled={isDeleting}>
              {isDeleting ? (
                <div className="flex items-center">
                  <svg
                    className="animate-spin -ml-1 mr-2 h-4 w-4"
                    xmlns="http://www.w3.org/2000/svg"
                    fill="none"
                    viewBox="0 0 24 24"
                  >
                    <circle
                      className="opacity-25"
                      cx="12"
                      cy="12"
                      r="10"
                      stroke="currentColor"
                      strokeWidth="4"
                    ></circle>
                    <path
                      className="opacity-75"
                      fill="currentColor"
                      d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
                    ></path>
                  </svg>
                  {t('actions.deleting')}
                </div>
              ) : (
                t('teams.force_delete')
              )}
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      {/* Share success dialog */}
      {shareData && (
        <TeamShareModal
          visible={shareModalVisible}
          onClose={handleCloseShareModal}
          teamName={shareData.teamName}
          shareUrl={shareData.shareUrl}
        />
      )}

      {/* Bot list dialog */}
      <Dialog
        open={botListVisible}
        onOpenChange={open => {
          setBotListVisible(open)
          // Refresh bots list when dialog is closed to sync any changes made in BotList
          if (!open) {
            fetchBotsList(scope, groupName)
              .then(setBotsSorted)
              .catch(() => {})
          }
        }}
      >
        <DialogContent className="max-w-4xl max-h-[90vh] overflow-hidden flex flex-col">
          <DialogHeader>
            <DialogTitle>{t('bots.title')}</DialogTitle>
            <DialogDescription>{t('bots.description')}</DialogDescription>
          </DialogHeader>
          <div className="flex-1 overflow-y-auto">
            <BotList scope={scope} groupName={groupName} groupRoleMap={groupRoleMap} />
          </div>
        </DialogContent>
      </Dialog>

      {/* Team Creation Wizard */}
      <TeamCreationWizard
        open={wizardOpen}
        onClose={() => setWizardOpen(false)}
        onSuccess={handleWizardSuccess}
        scope={scope === 'all' ? undefined : scope}
        groupName={groupName}
      />

      {/* Copy Skills Confirmation Dialog */}
      <Dialog open={skillsDialogOpen} onOpenChange={setSkillsDialogOpen}>
        <DialogContent className="flex flex-col max-h-[85vh]">
          <DialogHeader className="flex-shrink-0">
            <DialogTitle>{t('teams.copy_skills_dialog_title')}</DialogTitle>
            <DialogDescription>{t('teams.copy_skills_dialog_desc')}</DialogDescription>
          </DialogHeader>
          {pendingCopy && (
            <ul className="overflow-y-auto flex-1 mt-2 space-y-1 text-sm text-text-secondary">
              {pendingCopy.personalSkills.map(s => (
                <li key={s.id} className="flex items-center gap-2">
                  <span className="w-1.5 h-1.5 rounded-full bg-primary flex-shrink-0" />
                  <span className="font-medium">{s.name}</span>
                  {s.description && (
                    <span className="text-text-muted truncate">— {s.description}</span>
                  )}
                </li>
              ))}
            </ul>
          )}
          <DialogFooter className="mt-4 flex-shrink-0">
            <Button variant="outline" onClick={() => handleSkillsDialogConfirm(false)}>
              {t('teams.copy_skills_skip')}
            </Button>
            <Button variant="primary" onClick={() => handleSkillsDialogConfirm(true)}>
              {t('teams.copy_skills_with')}
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      {/* Error prompt unified with antd message, no local rendering */}
    </>
  )
}
