import React from 'react';
import { 
  Box, Button, HStack, IconButton, Image, Input, Modal, ModalOverlay, ModalContent, 
  ModalHeader, ModalCloseButton, ModalBody, ModalFooter, FormControl, FormLabel, FormHelperText,
  useToast, VStack, Text, SimpleGrid, useColorModeValue, useDisclosure,
  Textarea, Icon, useBreakpointValue, InputGroup, InputLeftElement,
  ButtonGroup, Spinner, Heading, Td, Th, Thead, Tr, Tbody, Table, Switch,
  Select, Badge, Tabs, TabList, TabPanels, Tab, TabPanel, Accordion, AccordionItem,
  AccordionButton, AccordionPanel, AccordionIcon, AspectRatio, Link, Alert, AlertIcon
} from '@chakra-ui/react';
import { FiEdit2, FiTrash2, FiPlus, FiSearch, FiUpload, FiExternalLink, FiVideo, FiX, FiRefreshCcw } from 'react-icons/fi';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import AdminLayout from '../../layouts/AdminLayout';
import { Article, deleteArticle, getArticles, createArticle, updateArticle, uploadFile, CreateArticlePayload, UpdateArticlePayload, getArticleMatchLink, putArticleMatchLink, deleteArticleMatchLink } from '../../services/articles';
import { generateBlogAI } from '../../services/ai';
import { useState, useRef, useCallback, useMemo } from 'react';
import DOMPurify from 'dompurify';
import RichTextEditor from '../../components/common/RichTextEditor';
import { assetUrl } from '../../utils/url';
import { getPublicSettings } from '../../services/settings';
import { getZoneramaManifestWithFallbacks, getZoneramaAlbum, putZoneramaPick, saveAlbumToCache } from '../../services/zonerama';
import { facrApi } from '../../services/facr/facrApi';
import AlbumPhotoPicker from '../../components/admin/AlbumPhotoPicker';
import PollLinker from '../../components/admin/PollLinker';
import ThumbnailPreview from '../../components/common/ThumbnailPreview';
import FilePreview from '../../components/common/FilePreview';
import SaveStatusIndicator from '../../components/common/SaveStatusIndicator';
import DraftRecoveryModal from '../../components/common/DraftRecoveryModal';
import { useAutoSave, loadDraft, getDraftMetadata } from '../../hooks/useAutoSave';

import { getCachedYouTube, YouTubeVideo } from '../../services/youtube';

// Inline small component to show match link badge in list (with short label)
const MatchLinkBadge: React.FC<{ articleId: number }> = ({ articleId }) => {
  const linkQ = useQuery({
    queryKey: ['article-match-link', articleId],
    queryFn: () => getArticleMatchLink(articleId),
    enabled: typeof articleId !== 'undefined' && articleId !== null && (typeof articleId === 'number' ? articleId > 0 : String(articleId).trim() !== ''),
    staleTime: 60_000,
    retry: false,
  });
  
  // Show loading state while fetching
  if (linkQ.isLoading) {
    return <Badge colorScheme="gray">Načítání...</Badge>;
  }
  
  const mid = (linkQ.data as any)?.external_match_id;
  if (!mid) return <Badge colorScheme="gray">Nepropojeno</Badge>;

  const facrQ = useQuery({
    queryKey: ['facr-cached-match', mid],
    enabled: !!mid,
    staleTime: 60_000,
    retry: false,
    queryFn: async () => {
      try {
        const apiUrl = process.env.REACT_APP_API_URL || 'http://localhost:8080/api/v1';
        const origin = new URL(apiUrl).origin;
        const url = `${origin}/cache/prefetch/facr_club_info.json`;
        const res = await fetch(url, { cache: 'no-cache' });
        if (!res.ok) return null;
        const json = await res.json();
        const comps = Array.isArray(json?.competitions) ? json.competitions : [];
        for (const c of comps) {
          const matches = Array.isArray(c.matches) ? c.matches : [];
          for (const m of matches) {
            const id = String(m.match_id || m.id);
            if (id === String(mid)) return { ...m, competitionName: c.name };
          }
        }
        return null;
      } catch (error) {
        console.error('Failed to fetch FACR match data:', error);
        return null;
      }
    }
  });

  // Guard against errors
  if (facrQ.isError || linkQ.isError) {
    return <Badge colorScheme="red">Chyba načítání</Badge>;
  }

  const m: any = facrQ.data;
  const scoreText = m ? (m.score || (m.result_home!=null && m.result_away!=null ? `${m.result_home}:${m.result_away}` : 'vs')) : '';
  const hasScore = !!m && !!scoreText && scoreText !== 'vs';
  const color = hasScore ? 'green' : 'yellow';
  const label = m
    ? `${String(m.home || m.home_team || '')} ${String(scoreText)} ${String(m.away || m.away_team || '')}`
    : `ID: ${String(mid)}`;
  return (
    <HStack spacing={2}>
      <Badge colorScheme={color as any} title={m?.competitionName ? String(m.competitionName) : undefined}>Zápas: {label}</Badge>
      {m?.report_url ? (
        <IconButton
          aria-label="Otevřít FACR"
          size="xs"
          as="a"
          href={String(m.report_url)}
          target="_blank"
          rel="noopener noreferrer"
          icon={<FiExternalLink />}
          variant="ghost"
        />
      ) : null}
    </HStack>
  );
};
import { getCompetitionAliasesPublic } from '../../services/competitionAliases';

// Note: Image resize module removed due to incompatibility with Quill v2

const PAGE_SIZE = 10;

const inputBg = 'white'; // Temporary placeholder for dark mode support

const parseYoutubeVideoId = (raw: string): string => {
  const value = String(raw || '').trim();
  if (!value) return '';

  // Try to parse as URL first
  try {
    const url = new URL(value.startsWith('http') ? value : `https://${value}`);
    if (url.hostname.includes('youtu.be')) {
      const parts = url.pathname.split('/').filter(Boolean);
      if (parts.length > 0) {
        return parts[0];
      }
    }
    if (url.pathname.includes('/shorts/')) {
      const parts = url.pathname.split('/shorts/');
      if (parts.length > 1) {
        const idCandidate = parts[1].split(/[?&]/)[0];
        if (/^[0-9A-Za-z_-]{11}$/.test(idCandidate)) {
          return idCandidate;
        }
      }
    }
    const vParam = url.searchParams.get('v');
    if (vParam && /^[0-9A-Za-z_-]{11}$/.test(vParam)) {
      return vParam;
    }
  } catch {
    // ignore and fall back to regex parsing
  }

  const regex = /(?:v=|\/)([0-9A-Za-z_-]{11})(?![0-9A-Za-z_-])/;
  const match = value.match(regex);
  if (match && match[1]) {
    return match[1];
  }

  if (/^[0-9A-Za-z_-]{11}$/.test(value)) {
    return value;
  }

  return '';
};

const ArticlesAdminPage = () => {
  const toast = useToast();
  const qc = useQueryClient();
  const [page, setPage] = useState(1);
  const [search, setSearch] = useState('');

  interface EditingArticle extends Partial<Article> {
    slug?: string;
    seo_title?: string;
    seo_description?: string;
    og_image_url?: string;
    slugModified?: boolean;
    // category is inherited from Article, no need to redefine
    category_id?: number;
    category_name?: string;
  }

  const [editing, setEditing] = useState<EditingArticle | null>(null);
  const [showDraftRecovery, setShowDraftRecovery] = useState(false);
  const [draftKey, setDraftKey] = useState<string>('');

  

  

  // Load cached matches list for quick picker (from prefetch cache like MatchesAdminPage)
  React.useEffect(() => {
    (async () => {
      try {
        const apiUrl = process.env.REACT_APP_API_URL || 'http://localhost:8080/api/v1';
        const origin = new URL(apiUrl).origin;
        const url = `${origin}/cache/prefetch/facr_club_info.json`;
        const res = await fetch(url, { headers: { 'Cache-Control': 'no-cache' } });
        if (!res.ok) return;
        const json = await res.json();
        const comps = Array.isArray(json?.competitions) ? json.competitions : [];
        const items: any[] = comps.flatMap((c: any) => (Array.isArray(c.matches) ? c.matches : []).map((m: any) => {
          const score = m.score || (m.result_home!=null&&m.result_away!=null?`${m.result_home}:${m.result_away}`:'vs');
          return {
            id: String(m.match_id || m.id || ''),
            date: m.date_time || m.date || '',
            label: `${m.date_time || m.date || ''} • ${m.home || m.home_team || ''} ${score} ${m.away || m.away_team || ''} ${c?.name ? '('+c.name+')' : ''}`.trim(),
            competition: c?.name || '',
            home: m.home || m.home_team || '',
            away: m.away || m.away_team || '',
            score: score
          };
        }));
        // keep latest 200 for performance
        setMatchOptions(items.slice(-200).reverse());
      } catch { /* ignore */ }
    })();
  }, []);

  const { data, isLoading } = useQuery({
    queryKey: ['admin-articles', { page, page_size: PAGE_SIZE, q: search, published: false }],
    // Important: pass published=false to fetch ALL (backend defaults to only published when param missing)
    queryFn: () => getArticles({ page, page_size: PAGE_SIZE, published: false, q: search }),
    keepPreviousData: true,
  });

  // Settings for logo fetch (for placeholder image)
  const settingsQ = useQuery({
    queryKey: ['public-settings'],
    queryFn: getPublicSettings,
    staleTime: 5 * 60_000,
  });

  
  const { isOpen, onOpen, onClose } = useDisclosure();
  const [aiPrompt, setAiPrompt] = useState('');
  const [aiAudience, setAiAudience] = useState('Fanoušci klubu');
  const [aiMinWords, setAiMinWords] = useState<number>(500);
  const [featSwitchLoading, setFeatSwitchLoading] = useState<boolean>(false);
  const [competitions, setCompetitions] = useState<Array<{ code?: string; name: string }>>([]);
  const [aliasesMap, setAliasesMap] = useState<Record<string, string>>({});
  // Match link state
  const [linkedMatchId, setLinkedMatchId] = useState<string>('');
  const [linkedMatchTitle, setLinkedMatchTitle] = useState<string>('');
  const [matchIdInput, setMatchIdInput] = useState<string>('');
  const [matchOptions, setMatchOptions] = useState<Array<{ id: string; label: string; date?: string; competition?: string; home?: string; away?: string; score?: string }>>([]);
  const [matchSearch, setMatchSearch] = useState('');
  const [activeTabIndex, setActiveTabIndex] = useState(0);
  const [matchDateFilter, setMatchDateFilter] = useState<string>('');
  const [tempMatchLink, setTempMatchLink] = useState<string>(''); // Temporary storage for new articles

  // Zonerama picker state
  const [zAlbumLink, setZAlbumLink] = useState<string>('');
  const [zAlbumPhotos, setZAlbumPhotos] = useState<Array<{ id: string; page_url: string; image_1500?: string; title?: string }>>([]);
  const [zLoading, setZLoading] = useState<boolean>(false);
  const [albumPickerOpen, setAlbumPickerOpen] = useState<boolean>(false);
  const { isOpen: isAlbumPickerOpen, onOpen: onAlbumPickerOpen, onClose: onAlbumPickerClose } = useDisclosure();
  const { isOpen: isGalleryPickerOpen, onOpen: onGalleryPickerOpen, onClose: onGalleryPickerClose } = useDisclosure();
  const [cachedAlbums, setCachedAlbums] = useState<Array<{ id: string; date: string; title?: string; photos: Array<{ id: string; image_1500: string; page_url: string }> }>>([]);
  const [galleryLoading, setGalleryLoading] = useState<boolean>(false);
  const [youtubeVideos, setYoutubeVideos] = useState<YouTubeVideo[]>([]);
  const [youtubeLoading, setYoutubeLoading] = useState<boolean>(false);
  const [youtubeSearch, setYoutubeSearch] = useState<string>('');
  const [youtubeManualInput, setYoutubeManualInput] = useState<string>('');
  const { isOpen: isYouTubeModalOpen, onOpen: onYouTubeModalOpen, onClose: onYouTubeModalClose } = useDisclosure();

  // Auto-save hook - saves draft automatically
  const { saveStatus, lastSaved, forceSave, clearDraft } = useAutoSave({
    data: editing || {},
    storageKey: draftKey,
    onSave: async (data) => {
      // If article has ID, update it as draft
      if (data.id) {
        return await updateArticle(data.id, { ...data as any, published: false });
      }
      // If no ID, create as draft
      if (data.title?.trim()) {
        const payload: CreateArticlePayload = {
          title: data.title || 'Koncept článku',
          content: data.content || '',
          image_url: data.image_url || '',
          category_name: data.category_name,
          published: false, // Always save as draft
          slug: data.slug || '',
          seo_title: data.seo_title || '',
          seo_description: data.seo_description || '',
          og_image_url: data.og_image_url || '',
          featured: data.featured || false,
        };
        const created = await createArticle(payload);
        // Update editing state with new ID
        if (created?.id) {
          setEditing(prev => ({ ...prev, id: created.id } as any));
        }
        return created;
      }
      // Don't save if no title
      return {};
    },
    debounceMs: 2000,
    enabled: isOpen && editing !== null,
  });

  // Check for draft on component mount
  React.useEffect(() => {
    const key = 'draft-article-new';
    setDraftKey(key);
    const metadata = getDraftMetadata(key);
    if (metadata && metadata.age < 1440) { // Less than 24 hours old
      setShowDraftRecovery(true);
    }
  }, []);

  // Fetch cached Zonerama gallery from prefetch
  const fetchCachedGallery = useCallback(async () => {
    try {
      setGalleryLoading(true);
      const apiUrl = process.env.REACT_APP_API_URL || 'http://localhost:8080/api/v1';
      const origin = new URL(apiUrl).origin;
      const url = `${origin}/cache/prefetch/zonerama_profile.json`;
      const res = await fetch(url, { cache: 'no-cache' });
      if (!res.ok) throw new Error('Failed to load gallery cache');
      const data = await res.json();
      const albums = Array.isArray(data?.albums) ? data.albums : [];
      // Filter albums with photos
      const validAlbums = albums.filter((a: any) => Array.isArray(a.photos) && a.photos.length > 0);
      setCachedAlbums(validAlbums);
      if (validAlbums.length === 0) {
        toast({ title: 'Žádné alba nenalezena', description: 'Cache galerie je prázdná nebo neobsahuje fotografie.', status: 'info', duration: 4000 });
      }
    } catch (e: any) {
      toast({ title: 'Načtení galerie selhalo', description: e?.message || 'Zkuste to prosím znovu.', status: 'error' });
    } finally {
      setGalleryLoading(false);
    }
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  // Remove toast from dependencies to prevent infinite loops
  const fetchYouTubeVideos = useCallback(async () => {
    try {
      setYoutubeLoading(true);
      const payload = await getCachedYouTube();
      let videos: YouTubeVideo[] = [];
      if (payload && Array.isArray(payload.videos)) {
        videos = payload.videos;
      }
      setYoutubeVideos(videos);
      if (!payload || videos.length === 0) {
        toast({ title: 'YouTube videa nenalezena', description: 'Zkontrolujte nastavení YouTube kanálu nebo zkuste obnovit cache.', status: 'info', duration: 4000 });
      }
    } catch (e: any) {
      toast({ title: 'Načtení YouTube videí selhalo', description: e?.message || 'Zkuste to prosím znovu.', status: 'error' });
    } finally {
      setYoutubeLoading(false);
    }
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  React.useEffect(() => {
    if (isYouTubeModalOpen && youtubeVideos.length === 0 && !youtubeLoading) {
      fetchYouTubeVideos();
    }
  }, [isYouTubeModalOpen, youtubeVideos.length, youtubeLoading, fetchYouTubeVideos]);

  React.useEffect(() => {
    if (isGalleryPickerOpen && cachedAlbums.length === 0 && !galleryLoading) {
      fetchCachedGallery();
    }
  }, [isGalleryPickerOpen, cachedAlbums.length, galleryLoading, fetchCachedGallery]);

  const filteredYoutubeVideos = useMemo(() => {
    const q = youtubeSearch.trim().toLowerCase();
    if (!q) return youtubeVideos;
    return youtubeVideos.filter((video) => {
      const title = (video.title || '').toLowerCase();
      return title.includes(q) || video.video_id.toLowerCase().includes(q);
    });
  }, [youtubeVideos, youtubeSearch]);

  const handleSelectYoutubeVideo = useCallback((video: YouTubeVideo) => {
    setEditing((prev) => ({
      ...(prev as any),
      youtube_video_id: video.video_id,
      youtube_video_title: video.title,
      youtube_video_url: `https://www.youtube.com/watch?v=${video.video_id}`,
      youtube_video_thumbnail: video.thumbnail_url,
    }));
    toast({ title: 'Video přidáno k článku', description: video.title, status: 'success' });
    onYouTubeModalClose();
  }, [toast, onYouTubeModalClose]);

  const handleClearYoutubeVideo = useCallback(() => {
    setEditing((prev) => ({
      ...(prev as any),
      youtube_video_id: '',
      youtube_video_title: '',
      youtube_video_url: '',
      youtube_video_thumbnail: '',
    }));
    toast({ title: 'Video odstraněno', status: 'info' });
  }, [toast]);

  const handleManualYoutubeSubmit = useCallback(() => {
    const id = parseYoutubeVideoId(youtubeManualInput);
    if (!id) {
      toast({ title: 'Neplatný YouTube odkaz', description: 'Zadejte prosím platné ID nebo odkaz na video.', status: 'warning' });
      return;
    }
    const existing = youtubeVideos.find((v) => v.video_id === id);
    const title = existing?.title || 'YouTube video';
    const thumbnail = existing?.thumbnail_url || `https://i.ytimg.com/vi/${id}/hqdefault.jpg`;
    setEditing((prev) => ({
      ...(prev as any),
      youtube_video_id: id,
      youtube_video_title: title,
      youtube_video_url: `https://www.youtube.com/watch?v=${id}`,
      youtube_video_thumbnail: thumbnail,
    }));
    toast({ title: 'Video nastaveno', description: title, status: 'success' });
    setYoutubeManualInput('');
  }, [youtubeManualInput, youtubeVideos, toast]);

  const pickZoneramaImage = useCallback(async (pick: { id: string; album_id?: string; album_url: string; page_url?: string; image_url: string; title?: string }) => {
    try {
      // Set cover image immediately
      setEditing((prev) => ({ ...(prev as any), image_url: pick.image_url }));
      // Persist pick to unified cache (admin)
      await putZoneramaPick({
        id: pick.id,
        album_id: pick.album_id,
        album_url: pick.album_url,
        page_url: pick.page_url,
        image_url: pick.image_url,
        title: pick.title,
      } as any);
      toast({ title: 'Obrázek vybrán ze Zonerama', status: 'success' });
    } catch (e: any) {
      toast({ title: 'Uložení výběru selhalo', description: e?.response?.data?.error || e?.message || 'Chyba', status: 'error' });
    }
  }, [toast]);

  // Handle album photo selection for blog content
  const handleAlbumPhotosSelected = useCallback(async (photos: Array<{ id: string; page_url: string; image_1500: string }>, albumInfo: any) => {
    try {
      // Save album to cache
      toast({ title: 'Ukládám album...', status: 'info', duration: 2000 });
      await saveAlbumToCache(albumInfo.url, photos.length);
      
      // Store album info with article and append images to content
      setEditing((prev) => {
        const currentContent = (prev as any)?.content || '';
        const photosHTML = photos.map(p => `<img src="${p.image_1500}" alt="Gallery photo" />`).join('\n');
        return {
          ...(prev as any),
          gallery_album_id: albumInfo.id,
          gallery_album_url: albumInfo.url,
          gallery_photo_ids: photos.map(p => p.id),
          content: currentContent + '\n' + photosHTML,
        };
      });
      
      // REUSE ALBUM: Also populate the album in Media tab so it doesn't need to be fetched twice
      // Map album photos to the format used in zAlbumPhotos state
      const mappedPhotos = albumInfo.photos?.map((p: any) => ({
        id: p.id,
        page_url: p.page_url,
        image_1500: p.image_1500 || '',
        title: p.title || '',
      })) || photos.map(p => ({
        id: p.id,
        page_url: p.page_url,
        image_1500: p.image_1500 || '',
        title: '',
      }));
      
      setZAlbumLink(albumInfo.url || '');
      setZAlbumPhotos(mappedPhotos);

      toast({ 
        title: 'Album přidáno', 
        description: `${photos.length} fotografií vloženo do článku. Album dostupné také v sekci Média.`,
        status: 'success',
        duration: 4000 
      });
    } catch (error: any) {
      toast({
        title: 'Chyba',
        description: error.message || 'Nepodařilo se přidat album',
        status: 'error',
        duration: 5000,
      });
    }
  }, [toast]);

  const fetchAlbumByLink = useCallback(async () => {
    const link = zAlbumLink.trim();
    if (!link) return;
    try {
      setZLoading(true);
      // Use correct API endpoint format based on album-api.md
      const apiUrl = process.env.REACT_APP_API_URL || 'http://localhost:8080/api/v1';
      const params = new URLSearchParams({
        link: link,
        photo_limit: '48',
        rendered: 'true'
      });
      const res = await fetch(`${apiUrl}/zonerama-album?${params.toString()}`);
      if (!res.ok) throw new Error('Failed to fetch album');
      const data = await res.json();
      
      // Handle the response structure from API - it can be:
      // 1. { albums: [{ photos: [...] }] } - new format
      // 2. { album: {...}, photos: [...] } - direct format
      let photos: any[] = [];
      
      if (Array.isArray(data?.albums) && data.albums.length > 0) {
        // New format with albums array
        photos = data.albums[0]?.photos || [];
      } else if (Array.isArray(data?.photos)) {
        // Direct format with photos array
        photos = data.photos;
      }
      
      if (photos.length === 0) {
        toast({ title: 'Album načteno, ale neobsahuje žádné fotografie', status: 'info' });
      }
      
      setZAlbumPhotos(photos);
    } catch (e: any) {
      toast({ title: 'Načtení alba selhalo', description: e?.message || 'Chyba', status: 'error' });
    } finally {
      setZLoading(false);
    }
  }, [zAlbumLink, toast]);

  // Match link is now included in article data, no need to fetch separately
  // The openEdit function handles setting it from the article data

  const filteredMatchOptions = useMemo(() => {
    let opts = matchOptions;
    
    // Get category name and find all possible matches (including via aliases)
    const cat = String((editing as any)?.category_name || '').trim().toLowerCase();
    if (cat) {
      // Find matching competition codes from aliases
      const matchingCodes = Object.entries(aliasesMap)
        .filter(([code, alias]) => alias.toLowerCase() === cat)
        .map(([code]) => code);
      
      // Find matching competition names from competitions list
      const matchingNames = competitions
        .filter(c => c.name.toLowerCase() === cat)
        .map(c => c.code)
        .filter(Boolean) as string[];
      
      const allCodes = [...new Set([...matchingCodes, ...matchingNames])];
      
      // Filter matches by competition code or name
      opts = opts.filter(o => {
        const compName = (o.competition || '').toLowerCase();
        // Match by alias, category name, or competition name
        if (compName.includes(cat)) return true;
        // Check if competition name matches any of our codes via reverse lookup
        const compCode = Object.entries(aliasesMap).find(([code, alias]) => 
          compName.includes(alias.toLowerCase())
        )?.[0];
        if (compCode && allCodes.includes(compCode)) return true;
        // Direct code matching
        return allCodes.some(code => {
          const aliasForCode = aliasesMap[code] || '';
          return compName.includes(code.toLowerCase()) || compName.includes(aliasForCode.toLowerCase());
        });
      });
    }
    
    // Search filter
    const q = matchSearch.trim().toLowerCase();
    if (q) {
      opts = opts.filter(o => o.label.toLowerCase().includes(q));
    }
    
    // Date filter
    if (matchDateFilter) {
      opts = opts.filter(o => {
        const dateStr = o.date || '';
        return dateStr.includes(matchDateFilter);
      });
    }
    
    // Sort by proximity to current date (recent matches first)
    const now = Date.now();
    opts = opts.sort((a, b) => {
      const dateA = new Date(a.date || 0).getTime();
      const dateB = new Date(b.date || 0).getTime();
      const diffA = Math.abs(now - dateA);
      const diffB = Math.abs(now - dateB);
      return diffA - diffB; // Closest to today first
    });
    
    return opts;
  }, [matchOptions, matchSearch, matchDateFilter, (editing as any)?.category_name, aliasesMap, competitions]);

  // Load club competitions + aliases for quick category pick
  React.useEffect(() => {
    (async () => {
      try {
        const settings = await getPublicSettings();
        const clubId = (settings as any)?.club_id || '';
        const clubType = ((settings as any)?.club_type || 'football') as 'football' | 'futsal';
        let comps: Array<{ code?: string; name: string }> = [];
        if (clubId) {
          try {
            const club = await facrApi.getClub(String(clubId), clubType);
            comps = (club?.competitions || []).map((c: any) => ({ code: c.code, name: c.name || c.code }));
          } catch {}
        }
        // Aliases
        let amap: Record<string, string> = {};
        try {
          const list = await getCompetitionAliasesPublic();
          list.forEach((a) => { if (a.code && a.alias) amap[a.code] = a.alias; });
        } catch {}
        // Apply aliases to names for display
        const withAliases = comps.map((c) => ({ code: c.code, name: (c.code && amap[c.code]) ? amap[c.code] : c.name }));
        setAliasesMap(amap);
        setCompetitions(withAliases);
      } catch {}
    })();
  }, []);

  const aiMut = useMutation({
    mutationFn: () => generateBlogAI({ prompt: aiPrompt, audience: aiAudience, min_words: aiMinWords }),
    onSuccess: (res) => {
      console.log('AI blog response:', res);
      
      // Insert AI output into the editing state
      const aiTitle = String(res?.title || '').trim();
      const aiSlug = String(res?.slug || '').trim();
      const aiHtml = String(res?.html || '').trim();
      
      if (!aiTitle || !aiHtml) {
        console.error('AI response missing title or html:', res);
        toast({ 
          title: 'AI odpověď neúplná', 
          description: 'AI nevrátila všechny požadované údaje. Zkuste to prosím znovu.', 
          status: 'warning' 
        });
        return;
      }
      
      const { seoTitle, seoDescription } = generateSeoMetadata(aiTitle);
      setEditing((prev) => ({
        ...(prev || {}),
        title: aiTitle,
        content: aiHtml,
        // store slug into editing (accepted by backend payload)
        ...(aiSlug ? { slug: aiSlug } as any : {}),
        seo_title: seoTitle,
        seo_description: seoDescription,
      }));
      
      // Clear AI prompt and switch to Základní tab to show results
      setAiPrompt('');
      setActiveTabIndex(1); // Switch to "Základní" tab
      
      toast({ title: 'Článek hotov', description: 'AI rozvinula váš text a vyplnila název, slug a obsah. Zkontrolujte výsledek v záložce Základní.', status: 'success', duration: 5000 });
    },
    onError: (e: any) => {
      console.error('AI generation error:', e);
      toast({ title: 'Generování selhalo', description: e?.response?.data?.error || e?.message || 'Zkuste to prosím znovu.', status: 'error' });
    },
  });

  const openCreate = () => {
    // Check for existing draft
    const key = 'draft-article-new';
    setDraftKey(key);
    const metadata = getDraftMetadata(key);
    if (metadata && metadata.age < 1440) {
      // Show recovery modal
      setShowDraftRecovery(true);
    } else {
      // No draft, start fresh
      setEditing({ title: '', content: '', featured: false, published: false } as any);
      setActiveTabIndex(0); // Start on AI tab for new articles
      setAiPrompt(''); // Clear AI prompt
      onOpen();
    }
  };

  const openEdit = (a: Article) => {
    // Set unique draft key for this article
    const key = `draft-article-${a.id}`;
    setDraftKey(key);
    
    setEditing({ 
      ...a, 
      category_name: a.category?.name || a.category_name || '' 
    });
    
    // If match_link is already in the article data, set it immediately
    if ((a as any)?.match_link?.external_match_id) {
      const matchId = String((a as any).match_link.external_match_id);
      setLinkedMatchId(matchId);
      setMatchIdInput(matchId);
    } else {
      // Clear match link state if not present
      setLinkedMatchId('');
      setMatchIdInput('');
    }
    
    setActiveTabIndex(1); // Start on Základní tab for editing
    setAiPrompt(''); // Clear AI prompt
    onOpen();
  };

  const closeModal = () => {
    // Clear temporary match link if user backs out without saving
    setTempMatchLink('');
    setMatchIdInput('');
    setEditing(null);
    onClose();
  };

  // Draft recovery handlers
  const handleRecoverDraft = () => {
    const draft = loadDraft<EditingArticle>(draftKey);
    if (draft) {
      setEditing(draft);
      setActiveTabIndex(1); // Go to Základní tab
      onOpen();
    }
    setShowDraftRecovery(false);
  };

  const handleDiscardDraft = () => {
    clearDraft();
    setEditing({ title: '', content: '', featured: false, published: false } as any);
    setActiveTabIndex(0);
    setShowDraftRecovery(false);
    onOpen();
  };

  const handleDeleteOnly = () => {
    clearDraft();
    setShowDraftRecovery(false);
    // Don't open the modal - just delete and close
  };

  const createMut = useMutation({
    mutationFn: (payload: CreateArticlePayload) =>
      // Forward the payload as-is so new fields (youtube, gallery) are persisted
      createArticle(payload),
    onSuccess: async (created: any) => {
      console.log('Article created successfully in mutation callback:', created);
      // Note: Match linking is now handled in onSubmit() to avoid race conditions
      // Clear temporary storage
      setTempMatchLink('');
      setMatchIdInput('');
      
      // Invalidate queries to refresh the list
      qc.invalidateQueries({ queryKey: ['admin-articles'] });
      qc.invalidateQueries({ queryKey: ['articles'] });
      qc.invalidateQueries({ queryKey: ['recentArticles'] });
      qc.invalidateQueries({ queryKey: ['article-match-link'] }); // Invalidate match links
      
      // Don't close modal here - let onSubmit handle it after match linking
    },
    onError: (e: any) => {
      console.error('Error creating article:', e);
      toast({ 
        title: 'Chyba při vytváření článku', 
        description: e?.response?.data?.message || 'Došlo k chybě při ukládání',
        status: 'error',
        duration: 5000,
        isClosable: true
      });
    },
  });

  const updateMut = useMutation({
    mutationFn: ({ id, payload }: { id: number | string; payload: UpdateArticlePayload }) =>
      // Forward the payload as-is so new fields (youtube, gallery) are persisted
      updateArticle(id, payload),
    onSuccess: (_, variables) => {
      const articleId = variables.id;
      console.log('Article updated successfully in mutation callback:', articleId);
      
      // Invalidate queries to refresh the list
      qc.invalidateQueries({ queryKey: ['admin-articles'] });
      qc.invalidateQueries({ queryKey: ['articles'] });
      qc.invalidateQueries({ queryKey: ['recentArticles'] });
      qc.invalidateQueries({ queryKey: ['article-match-link', articleId] }); // Invalidate specific match link
      qc.invalidateQueries({ queryKey: ['article', `id:${articleId}`] }); // Invalidate article detail
      
      // Success toast and modal closing handled in onSubmit()
    },
    onError: (e: any) => {
      console.error('Error updating article:', e);
      toast({ 
        title: 'Chyba při aktualizaci článku', 
        description: e?.response?.data?.message || 'Došlo k chybě při ukládání',
        status: 'error',
        duration: 5000,
        isClosable: true
      });
    },
  });

  const deleteMut = useMutation({
    mutationFn: (id: number | string) => deleteArticle(id),
    onSuccess: () => {
      toast({ title: 'Článek smazán', status: 'success' });
      qc.invalidateQueries({ queryKey: ['admin-articles'] });
    },
    onError: (e: any) => toast({ title: 'Smazání selhalo', description: e?.response?.data?.message || e?.response?.data?.chyba || 'Chyba', status: 'error' }),
  });

  const handleDeleteArticle = useCallback(
    (article: Partial<Article> & Record<string, any>) => {
      const candidate = article?.id ?? article?.ID ?? article?.article_id ?? article?.articleId;
      if (candidate === undefined || candidate === null || candidate === '') {
        toast({
          title: 'Chybějící ID článku',
          description: 'Nepodařilo se zjistit identifikátor článku pro smazání.',
          status: 'error',
        });
        return;
      }

      const idValue = typeof candidate === 'number' || typeof candidate === 'string'
        ? candidate
        : Number(candidate);

      if (idValue === undefined || idValue === null || (typeof idValue === 'number' && Number.isNaN(idValue))) {
        toast({
          title: 'Neplatné ID článku',
          description: 'Zadaný identifikátor článku není platný.',
          status: 'error',
        });
        return;
      }

      deleteMut.mutate(idValue);
    },
    [deleteMut, toast]
  );

  const generateSeoMetadata = (title: string) => {
    const baseTitle = title ? `${title} | ${process.env.REACT_APP_SITE_NAME || 'Fotbalový klub'}` : (process.env.REACT_APP_SITE_NAME || 'Fotbalový klub');
    const description = title 
      ? `Přečtěte si více o ${title.toLowerCase()}. Aktuální informace, novinky a zajímavosti z našeho fotbalového klubu.`
      : 'Oficiální stránky našeho fotbalového klubu. Aktuality, zápasy, výsledky a další informace.';
    
    return {
      seoTitle: baseTitle,
      seoDescription: description.length > 160 ? description.substring(0, 157) + '...' : description
    };
  };

  const makeSlug = (text: string) => {
    // Map of Czech/Slovak diacritics to ASCII equivalents
    const diacriticsMap: Record<string, string> = {
      'á': 'a', 'č': 'c', 'ď': 'd', 'é': 'e', 'ě': 'e', 'í': 'i', 'ň': 'n',
      'ó': 'o', 'ř': 'r', 'š': 's', 'ť': 't', 'ú': 'u', 'ů': 'u', 'ý': 'y', 'ž': 'z',
      'Á': 'a', 'Č': 'c', 'Ď': 'd', 'É': 'e', 'Ě': 'e', 'Í': 'i', 'Ň': 'n',
      'Ó': 'o', 'Ř': 'r', 'Š': 's', 'Ť': 't', 'Ú': 'u', 'Ů': 'u', 'Ý': 'y', 'Ž': 'z'
    };
    
    return text
      .toLowerCase()
      // Replace diacritics with ASCII equivalents
      .split('')
      .map(char => diacriticsMap[char] || char)
      .join('')
      // Remove special characters except word chars, spaces, and hyphens
      .replace(/[^\w\s-]/g, '')
      // Replace spaces with hyphens
      .replace(/\s+/g, '-')
      // Remove consecutive hyphens
      .replace(/--+/g, '-')
      .trim();
  };

  const handleTitleChange = (title: string) => {
    if (!editing) return;
    const { seoTitle, seoDescription } = generateSeoMetadata(title);
    setEditing(prev => ({
      ...(prev as any),
      title,
      seo_title: seoTitle,
      seo_description: seoDescription,
      // Auto-generate slug from title if not manually modified
      ...(!(prev as any)?.slugModified ? { 
        slug: makeSlug(title)
      } : {})
    }));
  };

  const handleSlugChange = (slug: string) => {
    if (!editing) return;
    setEditing(prev => ({
      ...(prev as any),
      slug,
      slugModified: true // Mark as manually modified
    }));
  };

  const ensurePlaceholderImage = async (): Promise<string | undefined> => {
    try {
      const logoUrl = String(settingsQ.data?.club_logo_url || '/dist/img/logo-club-empty.svg');
      const canvas = document.createElement('canvas');
      const W = 1200, H = 630;
      canvas.width = W; canvas.height = H;
      const ctx = canvas.getContext('2d');
      if (!ctx) return undefined;
      // White background
      ctx.fillStyle = '#ffffff';
      ctx.fillRect(0, 0, W, H);
      // Border for visibility
      ctx.strokeStyle = '#000000';
      ctx.lineWidth = 6;
      ctx.strokeRect(3, 3, W - 6, H - 6);
      // Draw club logo centered
      const img = new window.Image();
      img.crossOrigin = 'anonymous';
      const loadImg = () => new Promise<HTMLImageElement>((resolve, reject) => {
        img.onload = () => resolve(img);
        img.onerror = reject;
        img.src = logoUrl;
      });
      try { await loadImg(); } catch { /* fallback */ }
      const boxW = Math.round(W * 0.5);
      const boxH = Math.round(H * 0.5);
      const x = Math.round((W - boxW) / 2);
      const y = Math.round((H - boxH) / 2);
      try { ctx.drawImage(img, x, y, boxW, boxH); } catch {}
      // Export and upload
      const blob: Blob | null = await new Promise(resolve => canvas.toBlob(b => resolve(b), 'image/jpeg', 0.92));
      if (!blob) return undefined;
      const file = new File([blob], 'article-cover.jpg', { type: 'image/jpeg' });
      const res = await uploadFile(file);
      return (res as any)?.url || undefined;
    } catch { return undefined; }
  };

  const onSubmit = async (options: { keepOpen?: boolean } = {}) => {
    if (!editing) return;
    // Require category selection by name (kategorie je povinná)
    if (!String((editing as any)?.category_name || '').trim()) {
      toast({ title: 'Vyberte kategorii', description: 'Nejprve vyberte kategorii článku (soutěž).', status: 'warning' });
      return;
    }
    
    // Check if content contains raw AI JSON (invalid state)
    const contentText = String(editing.content || '').trim();
    if (contentText.includes('"title":') && contentText.includes('"slug":') && contentText.includes('"html":')) {
      toast({ 
        title: 'Neplatný obsah', 
        description: 'Obsah obsahuje nezpracovanou AI odpověď. Zkuste AI generování znovu nebo použijte záložku "Základní" pro ruční vytvoření.', 
        status: 'error',
        duration: 8000 
      });
      return;
    }
    
    try {
      // Auto-generate image if missing
      let imageUrl = (editing as any).image_url as string | undefined;
      if (!imageUrl) {
        imageUrl = await ensurePlaceholderImage();
        if (imageUrl) setEditing(prev => ({ ...(prev || {}), image_url: imageUrl }));
      }

      // Clean HTML content
      const cleanHTML = DOMPurify.sanitize(editing.content || '', {
        USE_PROFILES: { html: true },
        ADD_TAGS: ['iframe'],
        ADD_ATTR: ['target', 'rel', 'allow', 'allowfullscreen'],
      });
      
      // Prepare the payload according to the backend's expected format
      const payload = {
        title: editing.title || '',
        content: cleanHTML,
        image_url: imageUrl || '',
        ...(typeof (editing as any).category_id === 'number' ? { category_id: (editing as any).category_id as number } : {}),
        category_name: (editing as any).category_name || undefined,
        published: true, // Always publish articles
        slug: (editing as any).slug || makeSlug(editing.title || ''),
        seo_title: (editing as any).seo_title || '',
        seo_description: (editing as any).seo_description || '',
        og_image_url: (editing as any).og_image_url || imageUrl || '',
        featured: !!(editing as any)?.featured,
        // Persist gallery fields when present
        ...((editing as any).gallery_album_id ? { gallery_album_id: (editing as any).gallery_album_id } : {}),
        ...((editing as any).gallery_album_url ? { gallery_album_url: (editing as any).gallery_album_url } : {}),
        ...(Array.isArray((editing as any).gallery_photo_ids) && (editing as any).gallery_photo_ids.length > 0
            ? { gallery_photo_ids: (editing as any).gallery_photo_ids }
            : {}),
        // Persist YouTube fields when present
        ...((editing as any).youtube_video_id ? { youtube_video_id: (editing as any).youtube_video_id } : {}),
        ...((editing as any).youtube_video_title ? { youtube_video_title: (editing as any).youtube_video_title } : {}),
        ...((editing as any).youtube_video_url ? { youtube_video_url: (editing as any).youtube_video_url } : {}),
        ...((editing as any).youtube_video_thumbnail ? { youtube_video_thumbnail: (editing as any).youtube_video_thumbnail } : {}),
        // Persist attachments when present
        ...(Array.isArray((editing as any)?.attachments) && (editing as any).attachments.length > 0
            ? { attachments: (editing as any).attachments.map((a: any) => ({ name: a.name, url: a.url, mime_type: a.mime_type, size: a.size })) }
            : {}),
      } as CreateArticlePayload;
      
      // Log the payload for debugging
      console.log('Saving article with payload:', JSON.stringify(payload, null, 2));
      
      // Debug: Log match link state before submission
      console.log('Match link state before submit:', {
        tempMatchLink,
        matchIdInput,
        linkedMatchId,
        isNewArticle: !(editing as any)?.id
      });
      
      if ((editing as any)?.id) {
        // Update existing article
        await updateMut.mutateAsync({ id: (editing as any).id, payload });
        
        // Handle match linking for existing articles (update or delete)
        const matchRaw = matchIdInput || linkedMatchId;
        const matchId = String(matchRaw || '').trim();
        let matchLinked = false;
        if (matchId) {
          try {
            await putArticleMatchLink((editing as any).id, { external_match_id: matchId, title: editing.title || '' });
            console.log('Match link updated for existing article');
            matchLinked = true;
          } catch (err: any) {
            console.error('Failed to update match link:', err);
          }
        }
        
        // Show success message
        toast({ 
          title: matchLinked ? 'Článek aktualizován a propojen se zápasem' : 'Článek byl úspěšně aktualizován',
          status: 'success',
          duration: 3000,
          isClosable: true
        });
      } else {
        // Create new article
        const created = await createMut.mutateAsync(payload);
        
        // Handle match linking for new articles
        const matchRaw = tempMatchLink || matchIdInput;
        const matchId = String(matchRaw || '').trim();
        if (matchId && created?.id) {
          console.log('Linking new article', created.id, 'with match', matchId);
          try {
            await putArticleMatchLink(created.id, { external_match_id: matchId, title: editing.title || '' });
            console.log('Match link created for new article');
            setLinkedMatchId(matchId);
            toast({ 
              title: 'Článek vytvořen a propojen se zápasem', 
              description: `Match ID: ${matchId}`,
              status: 'success',
              duration: 3000,
              isClosable: true
            });
          } catch (err: any) {
            console.error('Failed to link match:', err);
            toast({
              title: 'Článek vytvořen, ale propojení se zápasem selhalo',
              description: err?.response?.data?.error || err?.message || 'Zkuste propojit zápas ručně',
              status: 'warning',
              duration: 5000,
              isClosable: true
            });
          }
        } else if (created?.id) {
          // No match to link, just show success
          toast({ 
            title: 'Článek byl úspěšně vytvořen', 
            status: 'success',
            duration: 3000,
            isClosable: true
          });
        }
      }
      
      // Close modal after successful save (unless keepOpen is true)
      if (!options.keepOpen) {
        closeModal();
      }
      
    } catch (error: any) {
      console.error('Error saving article:', error);
      // Error is handled by the mutation's onError handler
    }
  };

  const onUpload = async (file?: File | null) => {
    if (!file) return;
    const res = await uploadFile(file);
    setEditing((prev) => ({ ...(prev || {}), image_url: res.url }));
  };

  const onUploadOg = async (file?: File | null) => {
    if (!file) return;
    const res = await uploadFile(file);
    setEditing((prev) => ({ ...(prev || {}), og_image_url: (res as any).url } as any));
  };

  const articles = data?.data || [];
  const total = data?.total || 0;
  const totalPages = Math.max(1, Math.ceil(total / PAGE_SIZE));

  const handleFeaturedToggle = async (next: boolean) => {
    if (!editing) return;
    const currentIsFeatured = !!(editing as any)?.featured;
    // If turning off or no change, simply update local state
    if (!next || (next === currentIsFeatured)) {
      setEditing((prev) => ({ ...(prev as any), featured: next }));
      return;
    }
    // Turning on featured
    try {
      setFeatSwitchLoading(true);
      // Count featured from current page as a quick check
      let list = (articles || []).filter((a) => a.featured);
      if (list.length >= 3) {
        // Fetch a larger set of featured across pages to be safe
        try {
          const all = await getArticles({ page: 1, page_size: 50, featured: true, published: false });
          list = all.data || list;
        } catch {}
      }
      if (list.length >= 3) {
        // Find the oldest featured article by published_at/created_at/updated_at
        const toTs = (a: any) => {
          const s = a?.published_at || a?.created_at || a?.updated_at || '';
          const t = Date.parse(s);
          return isNaN(t) ? 0 : t;
        };
        const sorted = [...list].sort((a, b) => {
          const dt = toTs(a) - toTs(b);
          if (dt !== 0) return dt;
          // Fallback stable ordering by id
          return (a.id || 0) - (b.id || 0);
        });
        const oldest = sorted[0];
        if (oldest && oldest.id !== (editing as any)?.id) {
          try {
            await updateArticle(oldest.id, { featured: false });
            toast({ title: 'Uvolněno místo pro primární', description: `Zrušena primárnost: ${oldest.title}`, status: 'info' });
            // Refresh caches that may rely on featured
            qc.invalidateQueries({ queryKey: ['admin-articles'] });
            qc.invalidateQueries({ queryKey: ['articles'] });
            qc.invalidateQueries({ queryKey: ['featured-articles'] });
          } catch (e: any) {
            toast({ title: 'Nelze uvolnit místo', description: e?.response?.data?.message || 'Zkuste znovu.', status: 'error' });
            setFeatSwitchLoading(false);
            return;
          }
        }
      }
      setEditing((prev) => ({ ...(prev as any), featured: true }));
    } finally {
      setFeatSwitchLoading(false);
    }
  };

  return (
    <AdminLayout requireAdmin={false}>
      <Box>
        <HStack justify="space-between" mb={4}>
          <Heading size="lg">Články</Heading>
          <Button leftIcon={<FiPlus />} colorScheme="blue" onClick={openCreate}>
            Nový článek
          </Button>
        </HStack>
        <Text color="gray.500" mb={6}>
          Správa článků a novinek na webu. Můžete vytvářet, upravovat a publikovat články.
        </Text>

        <SimpleGrid columns={{ base: 1, md: 2 }} spacing={4} mb={6}>
          <Input
            placeholder="Hledat články..."
            value={search}
            onChange={(e) => setSearch(e.target.value)}
            mr={2}
          />
        </SimpleGrid>

        <Box 
          bg={useColorModeValue('white', 'gray.800')}
          borderWidth="1px"
          borderRadius="lg"
          overflowX="auto"
          boxShadow="sm"
          mb={6}
        >
          <Table size="sm">
            <Thead>
              <Tr>
                <Th>Obrázek</Th>
                <Th>Titulek</Th>
                <Th>Kategorie</Th>
                <Th>⭐ Primární</Th>
                <Th>Zápas</Th>
                <Th isNumeric>Akce</Th>
              </Tr>
            </Thead>
            <Tbody>
              {isLoading && (
                <Tr><Td colSpan={6}><Spinner size="sm" /></Td></Tr>
              )}
              {!isLoading && articles.map((a) => (
                <Tr key={a.id}>
                  <Td>
                    <ThumbnailPreview 
                      src={assetUrl(a.image_url) || '/dist/img/logo-club-empty.svg'} 
                      alt={a.title} 
                      size="48px"
                      previewSize="350px"
                    />
                  </Td>
                  <Td>
                    <VStack align="start" spacing={0}>
                      <Text fontWeight="medium">{a.title}</Text>
                      <Text fontSize="xs" color="gray.500">
                        {a.published ? '✓ Publikováno' : '○ Koncept'}
                      </Text>
                    </VStack>
                  </Td>
                  <Td>
                    <Badge colorScheme="blue" fontSize="xs">
                      {a.category?.name || a.category_name || 'Bez kategorie'}
                    </Badge>
                  </Td>
                  <Td>
                    <Switch
                      size="sm"
                      isChecked={!!a.featured}
                      onChange={async (e) => {
                        try {
                          await updateArticle(a.id, { featured: e.target.checked });
                          qc.invalidateQueries({ queryKey: ['admin-articles'] });
                          qc.invalidateQueries({ queryKey: ['articles'] });
                          qc.invalidateQueries({ queryKey: ['featured-articles'] });
                          toast({ 
                            title: e.target.checked ? 'Článek nastaven jako primární' : 'Článek odstraněn z primárních',
                            status: 'success',
                            duration: 2000
                          });
                        } catch (error: any) {
                          toast({
                            title: 'Chyba při aktualizaci',
                            description: error?.response?.data?.error || 'Nepodařilo se změnit stav',
                            status: 'error'
                          });
                        }
                      }}
                    />
                  </Td>
                  <Td><MatchLinkBadge articleId={a.id} /></Td>
                  <Td isNumeric>
                    <HStack spacing={1}>
                      <IconButton aria-label="Upravit" size="sm" icon={<FiEdit2 />} onClick={() => openEdit(a)} />
                      <IconButton aria-label="Smazat" size="sm" colorScheme="red" icon={<FiTrash2 />} onClick={() => handleDeleteArticle(a)} />
                    </HStack>
                  </Td>
                </Tr>
              ))}
            </Tbody>
          </Table>
        </Box>

        <HStack mt={4} justify="flex-end">
          <Button onClick={() => setPage((p) => Math.max(1, p - 1))} isDisabled={page <= 1}>Předchozí</Button>
          <Button onClick={() => setPage((p) => Math.min(totalPages, p + 1))} isDisabled={page >= totalPages}>Další</Button>
        </HStack>
      </Box>

      {/* Create/Edit Modal (90% viewport) */}
      <Modal isOpen={isOpen} onClose={closeModal} size="xl" isCentered>
        <ModalOverlay />
        <ModalContent maxW="90vw" maxH="90vh">
          <ModalHeader>
            <HStack justify="space-between" align="center" w="full" pr={8}>
              <Text>{(editing as any)?.id ? 'Upravit článek' : 'Nový článek'}</Text>
              <SaveStatusIndicator status={saveStatus} lastSaved={lastSaved} />
            </HStack>
          </ModalHeader>
          <ModalCloseButton />
          <ModalBody maxH="calc(90vh - 120px)" overflowY="auto">
            <Tabs variant="enclosed" colorScheme="blue" isFitted index={activeTabIndex} onChange={(index) => setActiveTabIndex(index)}>
              <TabList>
                <Tab>AI</Tab>
                <Tab>Základní</Tab>
                <Tab>Obsah</Tab>
                <Tab>Média</Tab>
                <Tab>SEO</Tab>
                <Tab>Anketa</Tab>
              </TabList>
              <TabPanels>
                {/* AI first */}
                <TabPanel>
                  <Box borderWidth="1px" borderRadius="md" p={4} bg="blue.50">
                    <Heading as="h3" size="sm" mb={2}>✍️ AI: Rozviňte VÁŠ TEXT na článek</Heading>
                    <Text fontSize="sm" color="gray.700" mb={3}>
                      <strong>Napište svůj text</strong> s důležitými informacemi - fakta, jména, výsledky, události. 
                      AI váš text použije jako základ, přidá strukturu a pokud je text krátký, rozšíří ho o kontext a detaily 
                      kolem vašich informací. <strong>Čím více napíšete, tím méně AI přidává.</strong> Dlouhý text = jen formátování.
                    </Text>
                    <VStack align="stretch" spacing={3}>
                      <FormControl>
                        <FormLabel fontWeight="bold">Váš text (česky)</FormLabel>
                        <Textarea 
                          rows={8} 
                          placeholder="Napište svůj text s důležitými informacemi. Příklad:&#10;&#10;Dnes naše mužstvo zvládlo důležitý zápas proti TJ Sokol Příbram. Konečný výsledek 3:1 pro nás. První poloasu jsme dominovali, Jana Novák dal dva góly. Ve druhé poloasu sice soupeř snížil, ale Petr Černý svým třetím gólem rozhodl.&#10;&#10;AI váš text rozšíří, přidá strukturu a doplní kontext pokud je krátký." 
                          value={aiPrompt} 
                          onChange={(e) => setAiPrompt(e.target.value)} 
                          fontSize="md"
                          bg={inputBg}
                        />
                        <FormHelperText>
                          💡 Krátký text: AI ho rozšíří o atmosféru a detaily. Dlouhý text: AI jen přidá HTML strukturu. Vždy zachová vaše informace.
                        </FormHelperText>
                      </FormControl>
                      <HStack>
                        <FormControl>
                          <FormLabel>Publikum</FormLabel>
                          <Input value={aiAudience} onChange={(e) => setAiAudience(e.target.value)} bg={inputBg} />
                        </FormControl>
                        <FormControl w="180px">
                          <FormLabel>Min. slov</FormLabel>
                          <Input type="number" value={aiMinWords} onChange={(e) => setAiMinWords(Math.max(200, Number(e.target.value || 0)))} bg={inputBg} />
                        </FormControl>
                      </HStack>
                      <HStack>
                        <Button size="md" colorScheme="purple" onClick={() => aiMut.mutate()} isLoading={aiMut.isLoading} isDisabled={!aiPrompt.trim()}>
                          Rozvinout text na článek
                        </Button>
                        <Box fontSize="sm" color="gray.600">AI zachová váš text a rozšíří ho pokud je krátký, přidá strukturu a vygeneruje název.</Box>
                      </HStack>
                    </VStack>
                  </Box>
                </TabPanel>

                {/* Základní second (includes match linking) */}
                <TabPanel>
                  <VStack align="stretch" spacing={4}>
                    <FormControl isRequired>
                      <FormLabel fontWeight="bold">Název článku</FormLabel>
                      <Input 
                        value={editing?.title || ''} 
                        onChange={(e) => handleTitleChange(e.target.value)} 
                        placeholder="Zadejte název článku"
                        size="lg"
                      />
                    </FormControl>
                    <FormControl>
                      <FormLabel>URL adresa (slug)</FormLabel>
                      <Input 
                        placeholder="moje-clanek-slug" 
                        value={(editing as any)?.slug || ''} 
                        onChange={(e) => handleSlugChange(e.target.value)} 
                      />
                      <FormHelperText>Automaticky generováno z názvu článku</FormHelperText>
                    </FormControl>
                    <FormControl isRequired>
                      <FormLabel fontWeight="bold">Kategorie (soutěž)</FormLabel>
                      <Select
                        placeholder="Vyberte kategorii článku"
                        value={(editing as any)?.category_name || ''}
                        onChange={(e) => setEditing((prev) => ({ ...(prev as any), category_name: e.target.value }))}
                        size="lg"
                      >
                        {competitions.map((c, idx) => (
                          <option key={(c.code || c.name) + '_' + idx} value={(c.code && aliasesMap[c.code]) ? aliasesMap[c.code] : c.name}>
                            {(c.code && aliasesMap[c.code]) ? aliasesMap[c.code] : c.name}
                          </option>
                        ))}
                      </Select>
                      <FormHelperText>Kategorie určuje, ve které sekci se článek zobrazí</FormHelperText>
                      {!(editing as any)?.category_name && (
                        <Text color="orange.500" fontSize="sm" mt={1}>⚠️ Kategorie je povinná</Text>
                      )}
                    </FormControl>
                    
                    {/* Featured toggle - prominent display */}
                    <Box 
                      borderWidth="2px" 
                      borderRadius="lg" 
                      p={4} 
                      bg={useColorModeValue('orange.50', 'orange.900')} 
                      borderColor={useColorModeValue('orange.300', 'orange.600')}
                    >
                      <FormControl display="flex" alignItems="center" justifyContent="space-between">
                        <Box>
                          <FormLabel mb="1" fontSize="lg" fontWeight="bold">⭐ Primární na úvodní stránce</FormLabel>
                          <Text fontSize="sm" color={useColorModeValue('gray.600', 'gray.400')}>Zvýrazní článek jako hlavní příspěvek na domovské stránce</Text>
                        </Box>
                        <Switch
                          size="lg"
                          isChecked={!!(editing as any)?.featured}
                          isDisabled={featSwitchLoading}
                          onChange={(e) => handleFeaturedToggle(e.target.checked)}
                        />
                      </FormControl>
                    </Box>

                    {/* Propojení se zápasem (vylepšený visual picker) */}
                    <Box borderWidth="1px" borderRadius="lg" p={4} bg={useColorModeValue('blue.50', 'blue.900')} borderColor="blue.200">
                      <HStack justify="space-between" mb={3}>
                        <Heading as="h3" size="sm">⚽ Propojit se zápasem (volitelné)</Heading>
                        {linkedMatchId && <Badge colorScheme="green">Propojeno</Badge>}
                      </HStack>
                      <VStack align="stretch" spacing={3}>
                        {!(editing as any)?.category_name && (
                          <Text fontSize="sm" color="orange.600" fontWeight="bold">
                            ⚠️ Nejprve vyberte kategorii výše pro zobrazení relevantních zápasů
                          </Text>
                        )}
                        <FormControl isDisabled={!((editing as any)?.category_name)}>
                          <FormLabel fontSize="sm">Rychlé vyhledávání</FormLabel>
                          <HStack spacing={2}>
                            <Input 
                              placeholder="Hledat zápas (tým, soupeř...)" 
                              value={matchSearch} 
                              onChange={(e)=> setMatchSearch(e.target.value)}
                              bg={inputBg}
                              size="sm"
                            />
                            <Input 
                              type="date" 
                              value={matchDateFilter}
                              onChange={(e)=> setMatchDateFilter(e.target.value)}
                              bg={inputBg}
                              size="sm"
                              w="160px"
                            />
                          </HStack>
                        </FormControl>
                        
                        {/* Calendar-style match picker */}
                        <Box>
                          <HStack justify="space-between" mb={2}>
                            <Text fontSize="sm" fontWeight="medium" mb={0}>Vyberte zápas ({filteredMatchOptions.length})</Text>
                            {linkedMatchId && (editing as any)?.id && (
                              <Button size="xs" variant="ghost" colorScheme="red" onClick={async()=>{
                                try {
                                  await deleteArticleMatchLink((editing as any).id);
                                  setLinkedMatchId(''); 
                                  setMatchIdInput('');
                                  setTempMatchLink('');
                                  toast({ title: 'Propojení zrušeno', status: 'success' });
                                } catch(e:any) {
                                  toast({ title: 'Zrušení selhalo', description: e?.response?.data?.error || e?.message, status: 'error' });
                                }
                              }}>Zrušit propojení</Button>
                            )}
                          </HStack>
                          
                          <Box 
                            maxH="400px" 
                            overflowY="auto" 
                            bg={useColorModeValue('white', 'gray.800')}
                            borderRadius="md"
                            borderWidth="1px"
                            p={2}
                          >
                            {filteredMatchOptions.length === 0 && (
                              <Text fontSize="sm" color="gray.500" textAlign="center" py={4}>
                                Žádné zápasy pro vybranou kategorii
                              </Text>
                            )}
                            <VStack spacing={2} align="stretch">
                              {filteredMatchOptions.slice(0, 100).map((match) => {
                                const matchId = String(match.id || '');
                                const isSelected = matchIdInput === matchId || linkedMatchId === matchId;
                                const matchDate = new Date(match.date || '');
                                const isValidDate = !isNaN(matchDate.getTime());
                                const dateStr = isValidDate ? matchDate.toLocaleDateString('cs-CZ', { 
                                  day: 'numeric', 
                                  month: 'short',
                                  year: 'numeric'
                                }) : (match.date || 'N/A');
                                const timeStr = isValidDate ? matchDate.toLocaleTimeString('cs-CZ', { 
                                  hour: '2-digit', 
                                  minute: '2-digit' 
                                }) : '';
                                
                                // Use match data directly
                                const home = match.home || '';
                                const away = match.away || '';
                                const score = match.score || 'vs';
                                const hasScore = score !== 'vs';
                                const teams = `${home} ${score} ${away}`.trim();
                                
                                return (
                                  <Box
                                    key={match.id}
                                    p={3}
                                    borderWidth="2px"
                                    borderRadius="md"
                                    borderColor={isSelected ? 'blue.500' : 'gray.200'}
                                    bg={isSelected ? useColorModeValue('blue.50', 'blue.900') : useColorModeValue('white', 'gray.700')}
                                    cursor="pointer"
                                    _hover={{ borderColor: 'blue.300', bg: useColorModeValue('blue.50', 'gray.600') }}
                                    transition="all 0.2s"
                                    onClick={async () => {
                                      const val = matchId;
                                      setMatchIdInput(val);
                                      setTempMatchLink(val);
                                      // Save immediately when an article already exists
                                      if (val && (editing as any)?.id) {
                                        try {
                                          const resp = await putArticleMatchLink((editing as any).id, { external_match_id: String(val).trim(), title: (editing as any)?.title || '' });
                                          setLinkedMatchId(resp.external_match_id || String(val).trim());
                                          toast({ title: 'Propojeno se zápasem', status: 'success', duration: 2000 });
                                        } catch (err: any) {
                                          toast({ title: 'Propojení selhalo', description: err?.response?.data?.error || err?.message, status: 'error' });
                                        }
                                      } else if (val && !(editing as any)?.id) {
                                        toast({ title: 'Propojení bude uloženo po vytvoření článku', status: 'info', duration: 2000 });
                                      }
                                    }}
                                  >
                                    <HStack justify="space-between" spacing={3}>
                                      <VStack align="start" spacing={1} flex={1}>
                                        <HStack spacing={2}>
                                          <Badge colorScheme={hasScore ? 'green' : 'gray'} fontSize="xs">
                                            {dateStr}
                                          </Badge>
                                          <Badge colorScheme="blue" fontSize="xs">
                                            {timeStr}
                                          </Badge>
                                        </HStack>
                                        <Text fontSize="sm" fontWeight="bold" noOfLines={1}>
                                          {teams}
                                        </Text>
                                        {match.competition && (
                                          <Text fontSize="xs" color="gray.500" noOfLines={1}>
                                            {match.competition}
                                          </Text>
                                        )}
                                      </VStack>
                                      {isSelected && (
                                        <Badge colorScheme="blue" fontSize="sm" p={2}>
                                          ✓
                                        </Badge>
                                      )}
                                    </HStack>
                                  </Box>
                                );
                              })}
                            </VStack>
                          </Box>
                          {filteredMatchOptions.length > 100 && (
                            <Text fontSize="xs" color="gray.500" mt={2}>
                              Zobrazeno prvních 100 zápasů. Použijte vyhledávání pro zúžení výsledků.
                            </Text>
                          )}
                        </Box>
                      </VStack>
                    </Box>
                  </VStack>
                </TabPanel>

                {/* Obsah third */}
                <TabPanel>
                  <FormControl>
                    <FormLabel>Obsah</FormLabel>
                    <HStack justify="space-between" mb={2}>
                      <Button 
                        size="sm" 
                        colorScheme="purple" 
                        leftIcon={<FiPlus />}
                        onClick={onAlbumPickerOpen}
                      >
                        Vložit fotografie z alba
                      </Button>
                    </HStack>
                    <RichTextEditor
                      value={editing?.content || ''}
                      onChange={(val: string) => setEditing((prev) => ({ ...(prev as any), content: val }))}
                      placeholder="Začněte psát obsah článku..."
                      height="60vh"
                      onImageUpload={uploadFile}
                      toolbar="full"
                    />
                  </FormControl>
                </TabPanel>

                {/* Média fourth */}
                <TabPanel>
                  <VStack align="stretch" spacing={4}>
                    {/* Zonerama picker - Album link only */}
                    <Box borderWidth="1px" borderRadius="md" p={3} bg="gray.50">
                      <Heading as="h3" size="sm" mb={2}>Zonerama výběr</Heading>
                      <VStack align="stretch" spacing={2}>
                        <FormControl>
                          <FormLabel>Odkaz na album Zonerama</FormLabel>
                          <InputGroup>
                            <InputLeftElement pointerEvents="none">
                              <Icon as={FiSearch} color="gray.400" />
                            </InputLeftElement>
                            <Input 
                              placeholder="https://eu.zonerama.com/…" 
                              value={zAlbumLink} 
                              onChange={(e) => setZAlbumLink(e.target.value)}
                              bg={zAlbumPhotos.length > 0 ? useColorModeValue('green.50', 'green.900') : undefined}
                            />
                          </InputGroup>
                          <FormHelperText fontSize="xs">
                            {zAlbumPhotos.length > 0 
                              ? `✓ Album načteno (${zAlbumPhotos.length} fotografií). Můžete vložit jiné album nebo vybrat fotky níže.`
                              : 'Vložte odkaz na album, nebo album se automaticky načte při výběru fotografií v sekci Obsah.'}
                          </FormHelperText>
                          {(editing as any)?.gallery_album_url && zAlbumLink && (editing as any).gallery_album_url === zAlbumLink && (
                            <Text fontSize="xs" color="blue.600" fontWeight="bold" mt={1}>
                              🔗 Album propojeno s článkem (zobrazeno v sekci Obsah)
                            </Text>
                          )}
                        </FormControl>
                        <HStack>
                          <Button size="sm" onClick={fetchAlbumByLink} isLoading={zLoading}>Načíst album</Button>
                          <Button size="sm" colorScheme="purple" onClick={onGalleryPickerOpen}>Vybrat z galerie</Button>
                          {zAlbumLink ? (
                            <Button size="sm" as="a" href={zAlbumLink} target="_blank" rel="noopener noreferrer" rightIcon={<FiExternalLink />}>Otevřít album</Button>
                          ) : null}
                        </HStack>
                        {zLoading && zAlbumPhotos.length === 0 && (
                          <HStack spacing={2} color="gray.600" mt={2}>
                            <Spinner size="sm" />
                            <Text>Album se načítá…</Text>
                          </HStack>
                        )}
                        {!zLoading && zAlbumPhotos.length === 0 && zAlbumLink && (
                          <Text fontSize="sm" color="gray.500" mt={2}>Zadejte odkaz na Zonerama album a klikněte na "Načíst album"</Text>
                        )}
                        {zAlbumPhotos.length > 0 && (
                          <SimpleGrid columns={{ base: 3, md: 6 }} spacing={2} mt={2}>
                            {zAlbumPhotos.map((p) => (
                              <Box key={p.id} borderWidth="1px" borderRadius="md" overflow="hidden" _hover={{ boxShadow: 'md' }} cursor="pointer"
                                onClick={() => pickZoneramaImage({ id: p.id, album_id: '', album_url: zAlbumLink, page_url: p.page_url, image_url: p.image_1500 || '', title: p.title })}
                              >
                                <Image src={p.image_1500 || ''} alt={p.id} w="100%" h="100px" objectFit="cover" />
                              </Box>
                            ))}
                          </SimpleGrid>
                        )}
                      </VStack>
                    </Box>

                    {/* Titulní obrázek - Cover Image */}
                    <FormControl>
                      <FormLabel fontWeight="bold">Titulní obrázek</FormLabel>
                      <FormHelperText mb={2}>
                        Vyberte obrázek ze Zonerama výše nebo nahrajte vlastní soubor.
                      </FormHelperText>
                      <HStack>
                        <Image src={assetUrl(editing?.image_url) || '/dist/img/logo-club-empty.svg'} alt="cover" boxSize="80px" objectFit="cover" borderRadius="md" />
                        <Button as="label" leftIcon={<FiUpload />} colorScheme="blue" variant="outline">
                          Nahrát soubor
                          <Input type="file" display="none" accept="image/*" onChange={(e) => onUpload(e.target.files?.[0])} />
                        </Button>
                      </HStack>
                    </FormControl>

                    {/* YouTube video attachment */}
                    <Box borderWidth="1px" borderRadius="md" p={3} bg="gray.50">
                      <HStack justify="space-between" align="center" mb={2}>
                        <Heading as="h3" size="sm" display="flex" alignItems="center" gap={2}>
                          <Icon as={FiVideo} />
                          YouTube video k článku
                        </Heading>
                        <Button size="sm" variant="outline" leftIcon={<FiVideo />} onClick={onYouTubeModalOpen}>
                          Vybrat z kanálu
                        </Button>
                      </HStack>

                      <VStack align="stretch" spacing={3}>
                        <FormControl>
                          <FormLabel fontSize="sm">Přidat ručně (ID nebo odkaz)</FormLabel>
                          <HStack>
                            <Input
                              placeholder="https://www.youtube.com/watch?v=..."
                              value={youtubeManualInput}
                              onChange={(e) => setYoutubeManualInput(e.target.value)}
                              bg={inputBg}
                            />
                            <Button size="sm" colorScheme="blue" onClick={handleManualYoutubeSubmit}>
                              Přidat
                            </Button>
                          </HStack>
                          <FormHelperText fontSize="xs">Podporujeme plné URL, zkrácené odkazy i ID videa.</FormHelperText>
                        </FormControl>

                        {(editing as any)?.youtube_video_id ? (
                          <Box borderWidth="1px" borderRadius="md" p={3} bg={inputBg}>
                            <HStack align="start" spacing={3}>
                              <AspectRatio ratio={16 / 9} w="160px">
                                <Image
                                  src={(editing as any)?.youtube_video_thumbnail || `https://i.ytimg.com/vi/${(editing as any)?.youtube_video_id}/hqdefault.jpg`}
                                  alt={(editing as any)?.youtube_video_title || 'YouTube thumbnail'}
                                  objectFit="cover"
                                  borderRadius="md"
                                />
                              </AspectRatio>
                              <VStack align="stretch" spacing={1} flex={1}>
                                <Text fontWeight="semibold">{(editing as any)?.youtube_video_title || 'YouTube video'}</Text>
                                <Link href={(editing as any)?.youtube_video_url} isExternal color="blue.500">
                                  {(editing as any)?.youtube_video_url}
                                </Link>
                                <HStack spacing={2}>
                                  <Badge colorScheme="red">ID: {(editing as any)?.youtube_video_id}</Badge>
                                </HStack>
                              </VStack>
                              <IconButton
                                aria-label="Odebrat video"
                                icon={<FiX />}
                                size="sm"
                                onClick={handleClearYoutubeVideo}
                              />
                            </HStack>
                          </Box>
                        ) : (
                          <Text fontSize="sm" color="gray.600">Žádné video není připojeno. Vyberte video z kanálu nebo vložte odkaz.</Text>
                        )}
                      </VStack>
                    </Box>

                    {/* OG Image for Social Sharing */}
                    <FormControl>
                      <FormLabel>OG obrázek pro sdílení (volitelné)</FormLabel>
                      <FormHelperText mb={2}>
                        Speciální obrázek pro sdílení na sociálních sítích. Pokud není nastaveno, použije se titulní obrázek.
                      </FormHelperText>
                      <HStack>
                        <Image src={assetUrl((editing as any)?.og_image_url) || assetUrl(editing?.image_url) || '/dist/img/logo-club-empty.svg'} alt="og" boxSize="80px" objectFit="cover" borderRadius="md" />
                        <Button as="label" leftIcon={<FiUpload />} variant="outline">
                          Nahrát OG obrázek
                          <Input type="file" display="none" accept="image/*" onChange={(e) => onUploadOg(e.target.files?.[0])} />
                        </Button>
                      </HStack>
                    </FormControl>

                    {/* File Attachments */}
                    <FormControl>
                      <FormLabel fontWeight="bold">Přílohy</FormLabel>
                      <FormHelperText mb={2}>
                        Přidejte dokumenty, obrázky nebo jiné soubory k článku (PDF, Word, Excel, PowerPoint, obrázky, ZIP)
                      </FormHelperText>
                      <HStack>
                        <Button as="label" leftIcon={<FiUpload />} colorScheme="teal" variant="outline">
                          Nahrát soubory
                          <Input 
                            type="file" 
                            display="none" 
                            multiple
                            accept=".pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.jpg,.jpeg,.png,.gif,.webp,.txt,.zip,.rar"
                            onChange={async (e) => {
                              const files = Array.from(e.target.files || []);
                              if (files.length === 0) return;
                              
                              const allowedTypes = [
                                'application/pdf',
                                'application/msword',
                                'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
                                'application/vnd.ms-excel',
                                'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
                                'application/vnd.ms-powerpoint',
                                'application/vnd.openxmlformats-officedocument.presentationml.presentation',
                                'image/jpeg',
                                'image/png',
                                'image/gif',
                                'image/webp',
                                'text/plain',
                                'application/zip',
                                'application/x-zip-compressed',
                                'application/x-rar-compressed',
                                'application/vnd.rar',
                              ];
                              
                              for (const f of files) {
                                if (!allowedTypes.includes(f.type) && !f.name.match(/\.(pdf|docx?|xlsx?|pptx?|jpe?g|png|gif|webp|txt|zip|rar)$/i)) {
                                  toast({ 
                                    title: 'Nepodporovaný formát souboru', 
                                    description: `Soubor "${f.name}" nelze nahrát.`, 
                                    status: 'warning', 
                                    duration: 4000 
                                  });
                                  continue;
                                }
                                try {
                                  const res = await uploadFile(f);
                                  setEditing(prev => ({ 
                                    ...(prev || {}), 
                                    attachments: [
                                      ...((prev as any)?.attachments || []), 
                                      { 
                                        name: f.name, 
                                        url: (res as any).url, 
                                        mime_type: f.type, 
                                        size: f.size 
                                      }
                                    ] 
                                  } as any));
                                  toast({ 
                                    title: 'Soubor nahrán', 
                                    description: f.name,
                                    status: 'success', 
                                    duration: 2000 
                                  });
                                } catch (err: any) {
                                  toast({ 
                                    title: 'Chyba při nahrávání', 
                                    description: `Soubor "${f.name}": ${err?.message || 'Neznámá chyba'}`, 
                                    status: 'error', 
                                    duration: 4000 
                                  });
                                }
                              }
                              // Reset input
                              (e.target as HTMLInputElement).value = '';
                            }} 
                          />
                        </Button>
                      </HStack>
                      <Box mt={2}>
                        {Array.isArray((editing as any)?.attachments) && (editing as any).attachments.length > 0 ? (
                          <Table size="sm" variant="simple">
                            <Thead>
                              <Tr>
                                <Th>Název</Th>
                                <Th>Velikost</Th>
                                <Th>Akce</Th>
                              </Tr>
                            </Thead>
                            <Tbody>
                              {((editing as any).attachments as any[]).map((att: any, idx: number) => (
                                <Tr key={idx}>
                                  <Td colSpan={3} p={2}>
                                    <HStack justify="space-between" w="full">
                                      <Box flex={1}>
                                        <FilePreview 
                                          url={att.url}
                                          name={att.name}
                                          mimeType={att.mime_type}
                                          size={att.size}
                                        />
                                      </Box>
                                      <Button 
                                        size="xs" 
                                        variant="outline" 
                                        colorScheme="red"
                                        flexShrink={0}
                                        ml={2}
                                        onClick={() => setEditing(prev => ({ 
                                          ...(prev as any), 
                                          attachments: ((prev as any).attachments || []).filter((_: any, i: number) => i !== idx) 
                                        }))}
                                      >
                                        Odebrat
                                      </Button>
                                    </HStack>
                                  </Td>
                                </Tr>
                              ))}
                            </Tbody>
                          </Table>
                        ) : (
                          <Box color="gray.500" fontSize="sm">Žádné přílohy</Box>
                        )}
                      </Box>
                    </FormControl>

                  </VStack>
                </TabPanel>

                {/* SEO last - minimized */}
                <TabPanel>
                  <Text fontSize="sm" color="gray.600" mb={4}>
                    SEO metadata jsou automaticky generována z názvu a obsahu článku. Upravujte pouze pokud potřebujete specifické hodnoty.
                  </Text>
                  <Accordion allowToggle>
                    <AccordionItem borderWidth="1px" borderRadius="md">
                      <h2>
                        <AccordionButton>
                          <Box flex="1" textAlign="left" fontWeight="semibold">
                            📊 Pokročilá SEO metadata (volitelné)
                          </Box>
                          <AccordionIcon />
                        </AccordionButton>
                      </h2>
                      <AccordionPanel pb={4}>
                        <VStack align="stretch" spacing={4}>
                          <FormControl>
                            <FormLabel fontSize="sm">SEO titulek</FormLabel>
                            <Input 
                              placeholder="SEO titulek" 
                              value={(editing as any)?.seo_title || ''} 
                              onChange={(e) => setEditing((prev) => ({ ...(prev as any), seo_title: e.target.value }))} 
                              size="sm"
                            />
                            <FormHelperText fontSize="xs">Automaticky generováno z názvu článku</FormHelperText>
                          </FormControl>
                          <FormControl>
                            <FormLabel fontSize="sm">SEO popis</FormLabel>
                            <Textarea 
                              placeholder="SEO popis" 
                              value={(editing as any)?.seo_description || ''} 
                              onChange={(e) => setEditing((prev) => ({ ...(prev as any), seo_description: e.target.value }))} 
                              rows={3}
                              size="sm"
                            />
                            <FormHelperText fontSize="xs">Automaticky generováno z obsahu článku</FormHelperText>
                          </FormControl>
                        </VStack>
                      </AccordionPanel>
                    </AccordionItem>
                  </Accordion>
                </TabPanel>

                {/* Anketa (Poll) Tab */}
                <TabPanel>
                  <VStack align="stretch" spacing={4}>
                    <Box borderWidth="1px" borderRadius="md" p={4} bg={useColorModeValue('purple.50', 'purple.900')}>
                      <Heading as="h3" size="sm" mb={2}>📊 Ankety k článku</Heading>
                      <Text fontSize="sm" color="gray.700" mb={3}>
                        Vytvořte nebo připojte ankety přímo k tomuto článku. Ankety se zobrazí automaticky na konci článku a čtenáři mohou hlasovat.
                      </Text>
                    </Box>

                    {editing?.id ? (
                      <PollLinker articleId={editing.id} onPollsChanged={() => {
                        // Invalidate queries to refresh polls
                        qc.invalidateQueries({ queryKey: ['linked-polls'] });
                      }} />
                    ) : (
                      <Alert status="info" borderRadius="md">
                        <AlertIcon />
                        <VStack align="start" spacing={2}>
                          <Text fontWeight="semibold">
                            {saveStatus === 'saving' ? 'Ukládání článku...' : 'Článek se ukládá automaticky'}
                          </Text>
                          <Text fontSize="sm">
                            Začněte psát článek na záložkách výše. Systém automaticky ukládá každou změnu jako koncept. Jakmile bude článek uložen (v záhlaví se zobrazí "Uloženo"), budete moci přidat ankety.
                          </Text>
                          {saveStatus === 'saving' && <Spinner size="sm" color="blue.500" />}
                          {saveStatus === 'idle' && (
                            <Text fontSize="xs" color="gray.600">
                              💡 Vyplňte název článku pro aktivaci automatického ukládání
                            </Text>
                          )}
                          <Button
                            size="sm"
                            colorScheme="blue"
                            onClick={async () => {
                              // Force save if needed
                              try {
                                await forceSave();
                                // Switch to poll tab after save
                                setActiveTabIndex(5); // Poll tab is index 5
                              } catch (error) {
                                // Error is handled by onSubmit
                              }
                            }}
                            isLoading={createMut.isLoading}
                          >
                            Uložit jako koncept a přidat ankety
                          </Button>
                        </VStack>
                      </Alert>
                    )}
                  </VStack>
                </TabPanel>
              </TabPanels>
            </Tabs>
          </ModalBody>
          <ModalFooter>
            <Button variant="ghost" mr={3} onClick={closeModal}>Zrušit</Button>
            <Button colorScheme="blue" onClick={() => onSubmit()} isLoading={createMut.isLoading || updateMut.isLoading}>Uložit</Button>
          </ModalFooter>
        </ModalContent>
      </Modal>

      {/* Album Photo Picker Modal */}
      <AlbumPhotoPicker
        isOpen={isAlbumPickerOpen}
        onClose={onAlbumPickerClose}
        onPhotosSelected={handleAlbumPhotosSelected}
      />

      {/* YouTube Video Picker Modal */}
      <Modal isOpen={isYouTubeModalOpen} onClose={onYouTubeModalClose} size="6xl">
        <ModalOverlay />
        <ModalContent maxH="90vh">
          <ModalHeader>Vybrat video z YouTube kanálu</ModalHeader>
          <ModalCloseButton />
          <ModalBody overflowY="auto">
            <VStack align="stretch" spacing={4}>
              {/* Search Input */}
              <FormControl>
                <FormLabel>Vyhledat video</FormLabel>
                <InputGroup>
                  <InputLeftElement pointerEvents="none">
                    <Icon as={FiSearch} color="gray.400" />
                  </InputLeftElement>
                  <Input
                    placeholder="Název videa nebo ID..."
                    value={youtubeSearch}
                    onChange={(e) => setYoutubeSearch(e.target.value)}
                  />
                </InputGroup>
              </FormControl>

              {/* Loading State */}
              {youtubeLoading && (
                <HStack spacing={2} justify="center" py={8}>
                  <Spinner size="lg" color="blue.500" />
                  <Text color="gray.600">Načítám videa z kanálu...</Text>
                </HStack>
              )}

              {/* Videos Grid */}
              {!youtubeLoading && filteredYoutubeVideos.length > 0 && (
                <SimpleGrid columns={{ base: 1, md: 2, lg: 3 }} spacing={4}>
                  {filteredYoutubeVideos.map((video) => (
                    <Box
                      key={video.video_id}
                      borderWidth="1px"
                      borderRadius="md"
                      overflow="hidden"
                      cursor="pointer"
                      transition="all 0.2s"
                      _hover={{ boxShadow: 'lg', transform: 'scale(1.02)' }}
                      onClick={() => handleSelectYoutubeVideo(video)}
                    >
                      <AspectRatio ratio={16 / 9}>
                        <Image
                          src={video.thumbnail_url}
                          alt={video.title}
                          objectFit="cover"
                        />
                      </AspectRatio>
                      <Box p={3}>
                        <Text fontWeight="semibold" fontSize="sm" noOfLines={2}>
                          {video.title}
                        </Text>
                        {video.published_date && (
                          <Text fontSize="xs" color="gray.500" mt={1}>
                            {new Date(video.published_date).toLocaleDateString('cs-CZ')}
                          </Text>
                        )}
                      </Box>
                    </Box>
                  ))}
                </SimpleGrid>
              )}

              {/* Empty State */}
              {!youtubeLoading && filteredYoutubeVideos.length === 0 && youtubeVideos.length === 0 && (
                <VStack py={8} spacing={3}>
                  <Icon as={FiVideo} boxSize={12} color="gray.400" />
                  <Text color="gray.600" textAlign="center">
                    Žádná videa nebyla nalezena.
                  </Text>
                  <Text fontSize="sm" color="gray.500" textAlign="center">
                    Zkontrolujte nastavení YouTube kanálu v administraci.
                  </Text>
                  <Button size="sm" onClick={fetchYouTubeVideos} leftIcon={<FiRefreshCcw />}>
                    Obnovit seznam
                  </Button>
                </VStack>
              )}

              {/* No Results for Search */}
              {!youtubeLoading && filteredYoutubeVideos.length === 0 && youtubeVideos.length > 0 && (
                <VStack py={8}>
                  <Text color="gray.600">Žádná videa neodpovídají vašemu hledání.</Text>
                  <Button size="sm" variant="link" onClick={() => setYoutubeSearch('')}>
                    Zobrazit všechna videa
                  </Button>
                </VStack>
              )}
            </VStack>
          </ModalBody>
          <ModalFooter>
            <Button variant="ghost" onClick={onYouTubeModalClose}>
              Zavřít
            </Button>
          </ModalFooter>
        </ModalContent>
      </Modal>

      {/* Zonerama Gallery Picker Modal */}
      <Modal isOpen={isGalleryPickerOpen} onClose={onGalleryPickerClose} size="6xl">
        <ModalOverlay />
        <ModalContent maxH="90vh">
          <ModalHeader>Vybrat fotku z galerie</ModalHeader>
          <ModalCloseButton />
          <ModalBody overflowY="auto">
            <VStack align="stretch" spacing={4}>
              {/* Loading State */}
              {galleryLoading && (
                <HStack spacing={2} justify="center" py={8}>
                  <Spinner size="lg" color="purple.500" />
                  <Text color="gray.600">Načítám alba z galerie...</Text>
                </HStack>
              )}

              {/* Albums Grid */}
              {!galleryLoading && cachedAlbums.length > 0 && (
                <VStack align="stretch" spacing={6}>
                  {cachedAlbums.map((album) => (
                    <Box key={album.id} borderWidth="1px" borderRadius="md" p={4} bg={useColorModeValue('white', 'gray.700')}>
                      <HStack justify="space-between" mb={3}>
                        <VStack align="start" spacing={0}>
                          <Text fontWeight="bold" fontSize="lg">{album.title || 'Album bez názvu'}</Text>
                          <Text fontSize="sm" color="gray.500">{album.date} • {album.photos.length} fotografií</Text>
                        </VStack>
                      </HStack>
                      <SimpleGrid columns={{ base: 3, md: 4, lg: 6 }} spacing={2}>
                        {album.photos.map((photo) => (
                          <Box
                            key={photo.id}
                            borderWidth="1px"
                            borderRadius="md"
                            overflow="hidden"
                            cursor="pointer"
                            transition="all 0.2s"
                            _hover={{ boxShadow: 'lg', transform: 'scale(1.05)' }}
                            onClick={() => {
                              pickZoneramaImage({
                                id: photo.id,
                                album_id: album.id,
                                album_url: `https://eu.zonerama.com/FKKofolaKrnov/Album/${album.id}`,
                                page_url: photo.page_url,
                                image_url: photo.image_1500,
                                title: album.title
                              });
                              onGalleryPickerClose();
                            }}
                          >
                            <AspectRatio ratio={1}>
                              <Image
                                src={photo.image_1500}
                                alt={photo.id}
                                objectFit="cover"
                              />
                            </AspectRatio>
                          </Box>
                        ))}
                      </SimpleGrid>
                    </Box>
                  ))}
                </VStack>
              )}

              {/* Empty State */}
              {!galleryLoading && cachedAlbums.length === 0 && (
                <VStack py={8} spacing={3}>
                  <Icon as={FiSearch} boxSize={12} color="gray.400" />
                  <Text color="gray.600" textAlign="center">
                    Žádná alba nebyla nalezena v cache.
                  </Text>
                  <Text fontSize="sm" color="gray.500" textAlign="center">
                    Zkontrolujte nastavení Zonerama nebo obnovte cache.
                  </Text>
                  <Button size="sm" onClick={fetchCachedGallery} leftIcon={<FiRefreshCcw />}>
                    Obnovit seznam
                  </Button>
                </VStack>
              )}
            </VStack>
          </ModalBody>
          <ModalFooter>
            <Button variant="ghost" onClick={onGalleryPickerClose}>
              Zavřít
            </Button>
          </ModalFooter>
        </ModalContent>
      </Modal>

      {/* Zonerama Gallery Picker Modal */}
      <Modal isOpen={isGalleryPickerOpen} onClose={onGalleryPickerClose} size="6xl">
        <ModalOverlay />
        <ModalContent maxH="90vh">
          <ModalHeader>Vybrat fotku z galerie</ModalHeader>
          <ModalCloseButton />
          <ModalBody overflowY="auto">
            <VStack align="stretch" spacing={4}>
              {/* Loading State */}
              {galleryLoading && (
                <HStack spacing={2} justify="center" py={8}>
                  <Spinner size="lg" color="purple.500" />
                  <Text color="gray.600">Načítám alba z galerie...</Text>
                </HStack>
              )}

              {/* Albums Grid */}
              {!galleryLoading && cachedAlbums.length > 0 && (
                <VStack align="stretch" spacing={6}>
                  {cachedAlbums.map((album) => (
                    <Box key={album.id} borderWidth="1px" borderRadius="md" p={4} bg={useColorModeValue('white', 'gray.700')}>
                      <HStack justify="space-between" mb={3}>
                        <VStack align="start" spacing={0}>
                          <Text fontWeight="bold" fontSize="lg">{album.title || 'Album bez názvu'}</Text>
                          <Text fontSize="sm" color="gray.500">{album.date} • {album.photos.length} fotografií</Text>
                        </VStack>
                      </HStack>
                      <SimpleGrid columns={{ base: 3, md: 4, lg: 6 }} spacing={2}>
                        {album.photos.map((photo) => (
                          <Box
                            key={photo.id}
                            borderWidth="1px"
                            borderRadius="md"
                            overflow="hidden"
                            cursor="pointer"
                            transition="all 0.2s"
                            _hover={{ boxShadow: 'lg', transform: 'scale(1.05)' }}
                            onClick={() => {
                              pickZoneramaImage({
                                id: photo.id,
                                album_id: album.id,
                                album_url: `https://eu.zonerama.com/FKKofolaKrnov/Album/${album.id}`,
                                page_url: photo.page_url,
                                image_url: photo.image_1500,
                                title: album.title
                              });
                              onGalleryPickerClose();
                            }}
                          >
                            <AspectRatio ratio={1}>
                              <Image
                                src={photo.image_1500}
                                alt={photo.id}
                                objectFit="cover"
                              />
                            </AspectRatio>
                          </Box>
                        ))}
                      </SimpleGrid>
                    </Box>
                  ))}
                </VStack>
              )}

              {/* Empty State */}
              {!galleryLoading && cachedAlbums.length === 0 && (
                <VStack py={8} spacing={3}>
                  <Icon as={FiSearch} boxSize={12} color="gray.400" />
                  <Text color="gray.600" textAlign="center">
                    Žádná alba nebyla nalezena v cache.
                  </Text>
                  <Text fontSize="sm" color="gray.500" textAlign="center">
                    Zkontrolujte nastavení Zonerama nebo obnovte cache.
                  </Text>
                  <Button size="sm" onClick={fetchCachedGallery} leftIcon={<FiRefreshCcw />}>
                    Obnovit seznam
                  </Button>
                </VStack>
              )}
            </VStack>
          </ModalBody>
          <ModalFooter>
            <Button variant="ghost" onClick={onGalleryPickerClose}>
              Zavřít
            </Button>
          </ModalFooter>
        </ModalContent>
      </Modal>

      {/* Draft Recovery Modal */}
      <DraftRecoveryModal
        isOpen={showDraftRecovery}
        onClose={() => setShowDraftRecovery(false)}
        onRecover={handleRecoverDraft}
        onDiscard={handleDiscardDraft}
        onDeleteOnly={handleDeleteOnly}
        draftAge={getDraftMetadata(draftKey)?.age || null}
        entityType="článek"
      />
    </AdminLayout>
  );
};

export default ArticlesAdminPage;
