import React, { useState, useRef, useEffect, useMemo } from 'react';
import {
  Box,
  Button,
  FormControl,
  FormLabel,
  Heading,
  HStack,
  IconButton,
  Image,
  Input,
  Modal,
  ModalBody,
  ModalCloseButton,
  ModalContent,
  ModalFooter,
  ModalHeader,
  ModalOverlay,
  Select,
  Spinner,
  Switch,
  Table,
  Tbody,
  Td,
  Textarea,
  Th,
  Thead,
  Tr,
  useColorModeValue,
  useDisclosure,
  useToast,
  VStack,
  SimpleGrid,
  NumberInput,
  NumberInputField,
} from '@chakra-ui/react';
import { FiEdit2, FiTrash2, FiPlus, FiUpload } from 'react-icons/fi';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import AdminLayout from '../../layouts/AdminLayout';
import { Player, getPlayers, createPlayer, updatePlayer, deletePlayer } from '../../services/players';
import { uploadFile } from '../../services/articles';
import { translateNationality } from '../../utils/nationality';
import ThumbnailPreview from '../../components/common/ThumbnailPreview';

type Editing = Partial<Player> & { id?: number };

const PlayersAdminPage: React.FC = () => {
  const cardBg = useColorModeValue('white', 'gray.800');
  const borderColor = useColorModeValue('gray.200', 'gray.700');
  const inputBg = useColorModeValue('white', 'gray.700');
  const toast = useToast();
  const normalizeImageUrl = (url?: string) => {
    if (!url || url === '') return '/logo192.png';
    // If it's already absolute, return as-is
    if (/^https?:\/\//i.test(url)) return url;
    // If it's an uploads path, prefix with API origin
    const apiUrl = process.env.REACT_APP_API_URL || 'http://localhost:8080/api/v1';
    const origin = new URL(apiUrl).origin;
    if (url.startsWith('/uploads/')) return `${origin}${url}`;
    // Fallback: treat as relative to origin
    return `${origin}${url.startsWith('/') ? '' : '/'}${url}`;
  };

  // Hoisted helper: convert country code to flag emoji
  function countryCodeToEmoji(cc: string) {
    if (!cc) return '';
    return cc.toUpperCase().replace(/./g, (char) => String.fromCodePoint(127397 + char.charCodeAt(0)));
  }

  // Countries for nationality dropdown
  const [countries, setCountries] = useState<Array<{ name: string; cca2: string; emoji: string }>>([]);
  // Search query for filtering nationality dropdown
  const [countryQuery, setCountryQuery] = useState<string>("");
  const countrySearchRef = useRef<HTMLInputElement | null>(null);
  const countrySelectRef = useRef<HTMLSelectElement | null>(null);
  // Simple fuzzy match scoring: higher is better
  function fuzzyScore(text: string, query: string): number {
    if (!query) return 0;
    const t = text.toLowerCase();
    const q = query.toLowerCase();
    // Exact and prefix bonuses
    if (t === q) return 1000;
    if (t.startsWith(q)) return 800 - (t.length - q.length);
    // Subsequence score
    let ti = 0, qi = 0, score = 0, streak = 0;
    while (ti < t.length && qi < q.length) {
      if (t[ti] === q[qi]) {
        streak += 1;
        score += 10 + streak; // reward consecutive matches
        qi++;
      } else {
        streak = 0;
      }
      ti++;
    }
    // Small penalty for distance
    if (qi === q.length) {
      return score - Math.abs(t.length - q.length);
    }
    return -Infinity; // not all chars matched in order
  }

  const filteredCountries = useMemo(() => {
    const q = countryQuery.trim();
    if (!q) return countries;
    // Score by name and cca2 and take the better score
    const scored = countries
      .map((c) => ({
        c,
        s: Math.max(
          fuzzyScore(c.name, q),
          fuzzyScore(c.cca2, q)
        ),
      }))
      .filter((x) => x.s > -Infinity)
      .sort((a, b) => b.s - a.s || a.c.name.localeCompare(b.c.name, 'cs', { sensitivity: 'base' }))
      .map((x) => x.c);
    return scored;
  }, [countries, countryQuery]);
  useEffect(() => {
    let mounted = true;
    (async () => {
      try {
        // Try v3.1 API first
        let json: any[] | null = null;
        const tryUrls = [
          'https://restcountries.com/v3.1/all?fields=name,cca2',
          // fallback: v2 API
          'https://restcountries.com/v2/all?fields=name,alpha2Code',
          // minimal fallback without fields (may be heavier, but used only if above fail)
          'https://restcountries.com/v3.1/all',
        ];
        let lastErr: any = null;
        for (const url of tryUrls) {
          try {
            const res = await fetch(url);
            if (!res.ok) throw new Error(`countries ${res.status}`);
            const data = await res.json();
            if (Array.isArray(data)) { json = data; break; }
          } catch (e) {
            lastErr = e;
          }
        }
        if (!mounted) return;
        if (!json) throw lastErr || new Error('countries fetch failed');
        const list = (json || []).map((c: any) => {
          const name = c?.name?.common || c?.name || '';
          const cca2 = c?.cca2 || c?.alpha2Code || '';
          return {
            name,
            cca2,
            emoji: countryCodeToEmoji(cca2),
          };
        }).filter((c: any) => c.name && c.cca2).sort((a: any, b: any) => a.name.localeCompare(b.name, 'cs', { sensitivity: 'base' }));
        setCountries(list);
      } catch (err) {
        // Hard fallback list for most common nationalities used locally
        const fallback = [
          { name: 'Czechia', cca2: 'CZ', emoji: countryCodeToEmoji('CZ') },
          { name: 'Slovakia', cca2: 'SK', emoji: countryCodeToEmoji('SK') },
          { name: 'Poland', cca2: 'PL', emoji: countryCodeToEmoji('PL') },
          { name: 'Germany', cca2: 'DE', emoji: countryCodeToEmoji('DE') },
          { name: 'Austria', cca2: 'AT', emoji: countryCodeToEmoji('AT') },
          { name: 'Ukraine', cca2: 'UA', emoji: countryCodeToEmoji('UA') },
          { name: 'France', cca2: 'FR', emoji: countryCodeToEmoji('FR') },
          { name: 'Spain', cca2: 'ES', emoji: countryCodeToEmoji('ES') },
          { name: 'Italy', cca2: 'IT', emoji: countryCodeToEmoji('IT') },
          { name: 'England', cca2: 'GB', emoji: countryCodeToEmoji('GB') },
        ];
        setCountries(fallback);
      }
    })();
    return () => { mounted = false; };
  }, []);

  // Persist countryQuery across sessions
  useEffect(() => {
    try {
      const saved = localStorage.getItem('playersAdmin.countryQuery');
      if (saved) setCountryQuery(saved);
    } catch {}
  }, []);
  useEffect(() => {
    try {
      localStorage.setItem('playersAdmin.countryQuery', countryQuery);
    } catch {}
  }, [countryQuery]);

  // Helper: compress image client-side, resize to max dimension and convert to JPEG to reduce size
  const compressAndUpload = async (file: File) => {
    const img = await readFileAsImage(file);
    const maxDim = 1400;
    let { width, height } = img;
    if (width > maxDim || height > maxDim) {
      const ratio = Math.min(maxDim / width, maxDim / height);
      width = Math.round(width * ratio);
      height = Math.round(height * ratio);
    }
    const canvas = document.createElement('canvas');
    canvas.width = width;
    canvas.height = height;
    const ctx = canvas.getContext('2d')!;
    ctx.drawImage(img, 0, 0, width, height);
    // Use JPEG for good compression; backend can accept jpeg (serving as png not mandatory)
    const blob: Blob | null = await new Promise((resolve) => canvas.toBlob(resolve as any, 'image/jpeg', 0.78));
    if (!blob) throw new Error('compression failed');
    const f = new File([blob], file.name.replace(/\.[^/.]+$/, '') + '.jpg', { type: 'image/jpeg' });
    return await uploadFile(f);
  };

  // Hoisted helper: read file into HTMLImageElement
  function readFileAsImage(file: File) {
    return new Promise<HTMLImageElement>((resolve, reject) => {
      const fr = new FileReader();
      fr.onload = () => {
        const img = new window.Image();
        img.onload = () => resolve(img);
        img.onerror = reject;
        img.src = fr.result as string;
      };
      fr.onerror = reject;
      fr.readAsDataURL(file);
    });
  }

  const qc = useQueryClient();
  const { data, isLoading } = useQuery({ queryKey: ['admin-players'], queryFn: getPlayers });

  const [editing, setEditing] = useState<Editing | null>(null);
  const { isOpen, onOpen, onClose } = useDisclosure();

  // Local state to persist partial DOB selections so the user sees what they picked
  const [dobParts, setDobParts] = useState<{ day: string; month: string; year: string }>({ day: '', month: '', year: '' });

  const openCreate = () => { setEditing({ first_name: '', last_name: '', is_active: true, email: '', phone: '' } as any); setDobFromDateStr(''); onOpen(); };
  const openEdit = (p: Player) => { setEditing({ ...p }); setDobFromDateStr(p.date_of_birth || ''); onOpen(); };
  const closeModal = () => { setEditing(null); onClose(); };

  const createMut = useMutation({
    mutationFn: (payload: any) => createPlayer(payload),
    onSuccess: (created: any) => {
      try {
        qc.setQueryData(['admin-players'], (old: any) => {
          const list = Array.isArray(old) ? old : (old?.data || []);
          const newList = [created, ...list];
          if (old && old.data) return { ...old, data: newList };
          return newList;
        });
      } catch (e) {}
      toast({ title: 'Hráč vytvořen', status: 'success' });
      qc.invalidateQueries({ queryKey: ['admin-players'] });
      closeModal();
    },
    onError: (e: any) => {
      const status = e?.response?.status;
      const msg = e?.response?.data?.chyba || e?.response?.data?.error || e?.message || 'Chyba';
      toast({ title: 'Vytvoření selhalo', description: status ? `HTTP ${status}: ${msg}` : msg, status: 'error' });
    },
  });
  const updateMut = useMutation({
    mutationFn: ({ id, payload }: { id: number | string; payload: any }) => updatePlayer(id, payload),
    onSuccess: () => { toast({ title: 'Hráč upraven', status: 'success' }); qc.invalidateQueries({ queryKey: ['admin-players'] }); closeModal(); },
    onError: (e: any) => {
      const status = e?.response?.status;
      const msg = e?.response?.data?.chyba || e?.response?.data?.error || e?.message || 'Chyba';
      toast({ title: 'Aktualizace selhala', description: status ? `HTTP ${status}: ${msg}` : msg, status: 'error' });
    },
  });
  const deleteMut = useMutation({
    mutationFn: (id: number) => deletePlayer(id),
    onSuccess: () => { toast({ title: 'Hráč smazán', status: 'success' }); qc.invalidateQueries({ queryKey: ['admin-players'] }); },
    onError: (e: any) => {
      const status = e?.response?.status;
      const msg = e?.response?.data?.chyba || e?.response?.data?.error || e?.message || 'Chyba';
      toast({ title: 'Smazání selhalo', description: status ? `HTTP ${status}: ${msg}` : msg, status: 'error' });
    },
  });

  const onSubmit = async () => {
    if (!editing) return;
    const fn = (editing.first_name || '').trim();
    const ln = (editing.last_name || '').trim();
    if (!fn || !ln) {
      toast({ title: 'Jméno a příjmení jsou povinné', status: 'warning' });
      return;
    }
    // Build payload by including only present values to satisfy backend validation
    const payload: any = {
      first_name: fn,
      last_name: ln,
    };
    if (editing.date_of_birth) payload.date_of_birth = editing.date_of_birth;
    if (editing.position) payload.position = editing.position;
    if (typeof editing.jersey_number === 'number' && Number.isFinite(editing.jersey_number) && editing.jersey_number > 0) payload.jersey_number = editing.jersey_number;
    if (editing.nationality) payload.nationality = editing.nationality;
    if (typeof editing.height === 'number' && editing.height > 0) payload.height = editing.height;
    if (typeof editing.weight === 'number' && editing.weight > 0) payload.weight = editing.weight;
    if (editing.image_url) payload.image_url = editing.image_url;
    if (typeof editing.is_active === 'boolean') payload.is_active = editing.is_active;
    const email = ((editing as any).email || '').trim();
    const phone = ((editing as any).phone || '').trim();
    if (email) payload.email = email;
    if (phone) payload.phone = phone;
    try {
      if ((editing as any).id != null) {
        await updateMut.mutateAsync({ id: (editing as any).id, payload });
      } else {
        await createMut.mutateAsync(payload);
      }
    } catch (err) {
      // handled by mutation
    }
  };

  return (
    <AdminLayout requireAdmin={false}>
      <Heading size="lg" mb={4}>Hráči</Heading>

      <HStack mb={4}>
        <Button leftIcon={<FiPlus />} colorScheme="blue" onClick={openCreate}>Nový hráč</Button>
      </HStack>

      <Box bg={cardBg} borderWidth="1px" borderRadius="md" overflowX="auto">
        <Table size="sm">
          <Thead>
            <Tr>
              <Th w="80px">Fotka</Th>
              <Th>Jméno</Th>
              <Th>Pozice</Th>
              <Th>Národnost</Th>
              <Th w="120px">Číslo</Th>
              <Th w="120px">Aktivní</Th>
              <Th w="160px">Akce</Th>
            </Tr>
          </Thead>
          <Tbody>
            {isLoading && (<Tr><Td colSpan={7}>Načítám...</Td></Tr>)}
            {!isLoading && (data || []).map((p) => (
              <Tr key={p.id}>
                <Td>
                  <ThumbnailPreview 
                    src={normalizeImageUrl(p.image_url)} 
                    alt={`${p.first_name} ${p.last_name}`} 
                    size="48px"
                    previewSize="300px"
                    borderRadius="md"
                  />
                </Td>
                <Td>{p.first_name} {p.last_name}</Td>
                <Td>{p.position || '-'}</Td>
                <Td>{p.nationality ? translateNationality(p.nationality) : '-'}</Td>
                <Td>{p.jersey_number ?? '-'}</Td>
                <Td><Switch isChecked={!!p.is_active} onChange={() => { if (p.id != null) updateMut.mutate({ id: p.id, payload: { is_active: !p.is_active } }); }} /></Td>
                <Td>
                  <HStack>
                    <IconButton aria-label="Upravit" size="sm" icon={<FiEdit2 />} onClick={() => openEdit(p)} />
                    <IconButton aria-label="Smazat" size="sm" colorScheme="red" icon={<FiTrash2 />} onClick={async () => { if (!confirm('Opravdu smazat záznam?')) return; if (p.id != null) await deleteMut.mutateAsync(p.id); }} />
                  </HStack>
                </Td>
              </Tr>
            ))}
          </Tbody>
        </Table>
      </Box>

      <Modal isOpen={isOpen} onClose={closeModal} size="lg">
        <ModalOverlay />
        <ModalContent maxW="90vw" maxH="90vh" overflowY="auto">
          <ModalHeader>{(editing as any)?.id ? 'Upravit hráče' : 'Nový hráč'}</ModalHeader>
          <ModalCloseButton />
          <ModalBody>
            <VStack align="stretch" spacing={4}>
              <SimpleGrid columns={[1, 2]} spacing={4}>
                <FormControl isRequired>
                  <FormLabel>Jméno</FormLabel>
                  <Input value={editing?.first_name || ''} onChange={(e) => setEditing((p) => ({ ...(p as any), first_name: e.target.value }))} />
                </FormControl>
                <FormControl isRequired>
                  <FormLabel>Příjmení</FormLabel>
                  <Input value={editing?.last_name || ''} onChange={(e) => setEditing((p) => ({ ...(p as any), last_name: e.target.value }))} />
                </FormControl>

                {/* Custom DOB picker: day / month / year (timezone-safe) */}
                <FormControl>
                  <FormLabel>Datum narození</FormLabel>
                  <HStack>
                    <Select value={dobParts.day} onChange={(e) => updateDobPart('day', e.target.value)}>
                      <option value="">Den</option>
                      {Array.from({ length: 31 }).map((_, i) => <option key={i+1} value={(i+1).toString()}>{i+1}</option>)}
                    </Select>
                    <Select value={dobParts.month} onChange={(e) => updateDobPart('month', e.target.value)}>
                      <option value="">Měsíc</option>
                      {Array.from({ length: 12 }).map((_, i) => <option key={i+1} value={(i+1).toString()}>{i+1}</option>)}
                    </Select>
                    <Select value={dobParts.year} onChange={(e) => updateDobPart('year', e.target.value)}>
                      <option value="">Rok</option>
                      {Array.from({ length: 80 }).map((_, i) => { const y = new Date().getFullYear() - i; return <option key={y} value={String(y)}>{y}</option>; })}
                    </Select>
                  </HStack>
                  <Box mt={2} fontSize="sm" color="gray.500">
                    {formatDobPreview(dobParts)}
                  </Box>
                </FormControl>

                <FormControl>
                  <FormLabel>Pozice</FormLabel>
                  <Select value={editing?.position || ''} onChange={(e) => setEditing((p) => ({ ...(p as any), position: e.target.value }))}>
                    <option value="">— vyberte pozici —</option>
                    <option value="Brankář">Brankář</option>
                    <option value="Obránce">Obránce</option>
                    <option value="Záložník">Záložník</option>
                    <option value="Útočník">Útočník</option>
                    <option value="Univerzál">Univerzál</option>
                  </Select>
                </FormControl>

                <FormControl>
                  <FormLabel>Číslo dresu</FormLabel>
                  <NumberInput value={editing?.jersey_number ?? 0} onChange={(_, v) => setEditing((p) => ({ ...(p as any), jersey_number: Number.isFinite(v) ? v : 0 }))}>
                    <NumberInputField />
                  </NumberInput>
                </FormControl>

                <FormControl>
                  <FormLabel>Národnost</FormLabel>
                  <VStack align="stretch" spacing={2}>
                    <Input
                      placeholder="Hledat zemi (např. cz, czechia)…"
                      value={countryQuery}
                      onChange={(e) => setCountryQuery(e.target.value)}
                      ref={countrySearchRef}
                      onKeyDown={(e) => {
                        if (e.key === 'ArrowDown') {
                          e.preventDefault();
                          countrySelectRef.current?.focus();
                        } else if (e.key === 'Escape') {
                          setCountryQuery('');
                        } else if (e.key === 'Enter') {
                          if (filteredCountries.length === 1) {
                            const only = filteredCountries[0];
                            setEditing((p) => ({ ...(p as any), nationality: only.name }));
                            countrySelectRef.current?.focus();
                          }
                        }
                      }}
                    />
                    <Select
                      placeholder="— vyberte zemi —"
                      value={editing?.nationality || ''}
                      onChange={(e) => setEditing((p) => ({ ...(p as any), nationality: e.target.value }))}
                      ref={countrySelectRef}
                      onKeyDown={(e) => {
                        if (e.key === 'ArrowUp' && (e.target as HTMLSelectElement).selectedIndex === 0) {
                          // Move back to search
                          e.preventDefault();
                          countrySearchRef.current?.focus();
                        }
                      }}
                    >
                      {filteredCountries.map((c) => (
                        <option key={c.cca2} value={c.name}>
                          {c.emoji} {translateNationality(c.name)} ({c.name})
                        </option>
                      ))}
                    </Select>
                  </VStack>
                </FormControl>

                <FormControl>
                  <FormLabel>Výška (cm)</FormLabel>
                  <NumberInput value={editing?.height ?? 0} onChange={(_, v) => setEditing((p) => ({ ...(p as any), height: Number.isFinite(v) ? v : 0 }))}>
                    <NumberInputField />
                  </NumberInput>
                </FormControl>
                <FormControl>
                  <FormLabel>Váha (kg)</FormLabel>
                  <NumberInput value={editing?.weight ?? 0} onChange={(_, v) => setEditing((p) => ({ ...(p as any), weight: Number.isFinite(v) ? v : 0 }))}>
                    <NumberInputField />
                  </NumberInput>
                </FormControl>
                {/* Optional contact info (not shown publicly) */}
                <FormControl>
                  <FormLabel>Email (nepovinné)</FormLabel>
                  <Input type="email" value={(editing as any)?.email || ''} onChange={(e) => setEditing((p) => ({ ...(p as any), email: e.target.value }))} />
                </FormControl>
                <FormControl>
                  <FormLabel>Telefon (nepovinné)</FormLabel>
                  <Input type="tel" value={(editing as any)?.phone || ''} onChange={(e) => setEditing((p) => ({ ...(p as any), phone: e.target.value }))} />
                </FormControl>
              </SimpleGrid>

              <FormControl>
                <FormLabel>Fotka</FormLabel>
                <HStack>
                  <Image src={normalizeImageUrl(editing?.image_url)} alt="photo" boxSize="56px" objectFit="cover" borderRadius="md" />
                  <Button as="label" type="button" leftIcon={<FiUpload />}>Nahrát
                    <Input
                      type="file"
                      display="none"
                      accept="image/*,image/svg+xml"
                      onChange={async (e) => {
                        e.preventDefault();
                        e.stopPropagation();
                        const f = e.target.files?.[0];
                        if (!f) return;
                        try {
                          const res = f.type === 'image/svg+xml' ? await uploadFile(f) : await compressAndUpload(f);
                          // ensure stored url is relative or absolute path expected by API
                          setEditing((p) => ({ ...(p as any), image_url: res.url }));
                          // reset the input so the same file can be selected again if needed
                          (e.target as HTMLInputElement).value = '';
                        } catch (err) {
                          toast({ title: 'Nahrání selhalo', status: 'error' });
                        }
                      }}
                    />
                  </Button>
                </HStack>
              </FormControl>

              <FormControl display="flex" alignItems="center">
                <FormLabel mb="0">Aktivní</FormLabel>
                <Switch isChecked={!!editing?.is_active} onChange={(e) => setEditing((p) => ({ ...(p as any), is_active: e.target.checked }))} />
              </FormControl>
            </VStack>
          </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>
    </AdminLayout>
  );

  // Helpers for DOB to avoid timezone shifts
  function parseYmd(s?: string | null): { y: number; m: number; d: number } | null {
    if (!s) return null;
    // Accept plain date 'YYYY-MM-DD' or ISO datetime starting with that date
    const m = String(s).match(/^(\d{4})-(\d{2})-(\d{2})(?:$|T)/);
    if (!m) return null;
    const y = Number(m[1]);
    const mm = Number(m[2]);
    const dd = Number(m[3]);
    if (!y || !mm || !dd) return null;
    return { y, m: mm, d: dd };
  }

  function setDobFromDateStr(s?: string) {
    const p = parseYmd(s || null);
    if (!p) { setDobParts({ day: '', month: '', year: '' }); return; }
    setDobParts({ day: String(p.d), month: String(p.m), year: String(p.y) });
  }

  function formatDobPreview(parts: { day: string; month: string; year: string }): string {
    const dd = parts.day ? parts.day.toString().padStart(2, '0') : '__';
    const mm = parts.month ? parts.month.toString().padStart(2, '0') : '__';
    const yyyy = parts.year || '____';
    return `${dd}.${mm}.${yyyy}`;
  }

  // Update DOB parts and, when complete, compose YYYY-MM-DD. Clamp day to month length.
  function updateDobPart(part: 'day'|'month'|'year', value: string) {
    setDobParts((prev) => {
      let next = { ...prev, [part]: value } as { day: string; month: string; year: string };
      // Clamp day if month/year present
      const y = Number(next.year || '0');
      const m = Number(next.month || '0');
      const d = Number(next.day || '0');
      if (y && m && d) {
        const maxDay = new Date(y, m, 0).getDate();
        if (d > maxDay) {
          next.day = String(maxDay);
        }
      }
      // Apply to editing only when all three are set
      const yy = Number(next.year || '0');
      const mm = Number(next.month || '0');
      const dd = Number(next.day || '0');
      if (yy && mm && dd) {
        const ymd = `${yy}-${String(mm).padStart(2, '0')}-${String(dd).padStart(2, '0')}`;
        setEditing((p) => ({ ...(p as any), date_of_birth: ymd }));
      } else {
        setEditing((p) => ({ ...(p as any), date_of_birth: '' }));
      }
      return next;
    });
  }

};

export default PlayersAdminPage;
