import React from 'react';
import { useNavigate, useNavigationType, useParams, useSearchParams } from 'react-router-dom';
import { Button } from '@/components/ui/button';
import { Alert, AlertDescription } from '@/components/ui/alert';
import { Sparkles, RefreshCw, Smile, Camera, Timer as TimerIcon, Heart, ChevronRight, CheckCircle2 } from 'lucide-react';
import type { LucideIcon } from 'lucide-react';
import { useGuestTaskProgress } from '../hooks/useGuestTaskProgress';
import { ToggleGroup, ToggleGroupItem } from '@/components/ui/toggle-group';
import { cn } from '@/lib/utils';
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { useEventBranding } from '../context/EventBrandingContext';
import { useTranslation, type TranslateFn } from '../i18n/useTranslation';
import { motion } from 'framer-motion';
import {
  getEmotionIcon,
  getEmotionTheme,
  type EmotionIdentity,
  type EmotionTheme,
} from '../lib/emotionTheme';
import { getDeviceId } from '../lib/device';
import { FADE_SCALE, FADE_UP, STAGGER_FAST, getMotionContainerPropsForNavigation, getMotionItemProps, prefersReducedMotion } from '../lib/motion';
import PullToRefresh from '../components/PullToRefresh';
import { triggerHaptic } from '../lib/haptics';
import { dedupeTasksById } from '../lib/taskUtils';

interface Task {
  id: number;
  title: string;
  description: string;
  instructions: string;
  duration: number; // minutes
  emotion?: {
    slug: string;
    name: string;
  };
  is_completed: boolean;
}

type EmotionOption = {
  slug: string;
  name: string;
};

type EventPhoto = {
  id: number;
  thumbnail_path?: string | null;
  file_path?: string | null;
  likes_count?: number | null;
  task_id?: number | null;
};

const SWIPE_THRESHOLD_PX = 40;
const SIMILAR_PHOTO_LIMIT = 6;

export default function TaskPickerPage() {
  const { token } = useParams<{ token: string }>();
  const eventKey = token ?? '';
  const navigate = useNavigate();
  const navigationType = useNavigationType();
  const [searchParams, setSearchParams] = useSearchParams();
  const { branding } = useEventBranding();
  const { t, locale } = useTranslation();
  const radius = branding.buttons?.radius ?? 12;
  const buttonStyle = branding.buttons?.style ?? 'filled';
  const linkColor = branding.buttons?.linkColor ?? branding.secondaryColor;
  const bodyFont = branding.typography?.body ?? branding.fontFamily ?? undefined;
  const headingFont = branding.typography?.heading ?? branding.fontFamily ?? undefined;

  const { isCompleted } = useGuestTaskProgress(eventKey);

  const [tasks, setTasks] = React.useState<Task[]>([]);
  const [currentTask, setCurrentTask] = React.useState<Task | null>(null);
  const [loading, setLoading] = React.useState(true);
  const [error, setError] = React.useState<string | null>(null);
  const [selectedEmotion, setSelectedEmotion] = React.useState<string>('all');
  const [isFetching, setIsFetching] = React.useState(false);
  const [photoPool, setPhotoPool] = React.useState<EventPhoto[]>([]);
  const [photoPoolLoading, setPhotoPoolLoading] = React.useState(false);
  const [photoPoolError, setPhotoPoolError] = React.useState<string | null>(null);
  const [hasSwiped, setHasSwiped] = React.useState(false);
  const [emotionPickerOpen, setEmotionPickerOpen] = React.useState(false);
  const [recentEmotionSlug, setRecentEmotionSlug] = React.useState<string | null>(null);

  const heroCardRef = React.useRef<HTMLDivElement | null>(null);

  const cameraButtonStyle = React.useMemo(() => ({
    background: `radial-gradient(circle at 20% 20%, ${branding.secondaryColor}, ${branding.primaryColor})`,
    boxShadow: `0 18px 30px ${branding.primaryColor}44`,
    color: '#ffffff',
  }), [branding.primaryColor, branding.secondaryColor]);

  const recentTaskIdsRef = React.useRef<number[]>([]);
  const tasksCacheRef = React.useRef<Map<string, { data: Task[]; etag?: string | null }>>(new Map());
  const initialEmotionRef = React.useRef(false);

  const fetchTasks = React.useCallback(async () => {
    if (!eventKey) return;
    const cacheKey = `${eventKey}:${locale}`;
    const cached = tasksCacheRef.current.get(cacheKey);
    setIsFetching(true);
    setLoading(!cached);
    setError(null);

    if (cached) {
      setTasks(cached.data);
    }

    try {
      const headers: HeadersInit = {
        Accept: 'application/json',
        'X-Locale': locale,
        'X-Device-Id': getDeviceId(),
      };

      if (cached?.etag) {
        headers['If-None-Match'] = cached.etag;
      }

      const response = await fetch(
        `/api/v1/events/${encodeURIComponent(eventKey)}/tasks?locale=${encodeURIComponent(locale)}`,
        { headers }
      );

      if (response.status === 304 && cached) {
        return;
      }

      if (!response.ok) throw new Error('Aufgaben konnten nicht geladen werden.');
      const payload = await response.json();
      const taskList = Array.isArray(payload)
        ? payload
        : Array.isArray(payload?.data)
          ? payload.data
          : Array.isArray(payload?.tasks)
            ? payload.tasks
            : [];

      const uniqueTasks = dedupeTasksById(taskList);
      const entry = { data: uniqueTasks, etag: response.headers.get('ETag') };
      tasksCacheRef.current.set(cacheKey, entry);
      setTasks(uniqueTasks);
    } catch (err) {
      console.error('Failed to load tasks', err);
      setError(err instanceof Error ? err.message : 'Unbekannter Fehler');
      if (!cached) {
        setTasks([]);
      }
    } finally {
      setIsFetching(false);
      setLoading(false);
    }
  }, [eventKey, locale]);

  React.useEffect(() => {
    fetchTasks();
  }, [fetchTasks]);

  React.useEffect(() => {
    if (initialEmotionRef.current) return;
    const queryEmotion = searchParams.get('emotion');
    if (queryEmotion) {
      setSelectedEmotion(queryEmotion);
    }
    initialEmotionRef.current = true;
  }, [searchParams]);

  const emotionOptions = React.useMemo<EmotionOption[]>(() => {
    const map = new Map<string, string>();
    tasks.forEach((task) => {
      if (task.emotion?.slug) {
        map.set(task.emotion.slug, task.emotion.name);
      }
    });
    return Array.from(map.entries()).map(([slugValue, name]) => ({ slug: slugValue, name }));
  }, [tasks]);

  const emotionCounts = React.useMemo(() => {
    const map = new Map<string, number>();
    tasks.forEach((task) => {
      const slugValue = task.emotion?.slug;
      if (!slugValue) return;
      map.set(slugValue, (map.get(slugValue) ?? 0) + 1);
    });
    return map;
  }, [tasks]);

  const filteredTasks = React.useMemo(() => {
    if (selectedEmotion === 'all') return tasks;
    return tasks.filter((task) => task.emotion?.slug === selectedEmotion);
  }, [tasks, selectedEmotion]);

  const alternativeTasks = React.useMemo(() => {
    return filteredTasks.filter((task) => task.id !== currentTask?.id).slice(0, 6);
  }, [filteredTasks, currentTask]);

  const selectRandomTask = React.useCallback(
    (list: Task[]) => {
      if (!list.length) {
        setCurrentTask(null);
        return;
      }
      const avoidIds = recentTaskIdsRef.current;
      const available = list.filter((task) => !isCompleted(task.id));
      const base = available.length ? available : list;
      let candidates = base.filter((task) => !avoidIds.includes(task.id));
      if (!candidates.length) {
        candidates = base;
      }
      const chosen = candidates[Math.floor(Math.random() * candidates.length)];
      setCurrentTask(chosen);
      recentTaskIdsRef.current = [...avoidIds.filter((id) => id !== chosen.id), chosen.id].slice(-3);
    },
    [isCompleted]
  );

  const handleSelectEmotion = React.useCallback(
    (slugValue: string) => {
      setSelectedEmotion(slugValue);
      const next = new URLSearchParams(searchParams.toString());
      if (slugValue === 'all') {
        next.delete('emotion');
      } else {
        next.set('emotion', slugValue);
        setRecentEmotionSlug(slugValue);
      }
      setSearchParams(next, { replace: true });
    },
    [searchParams, setSearchParams]
  );

  const handleNewTask = React.useCallback(() => {
    selectRandomTask(filteredTasks);
    triggerHaptic('selection');
  }, [filteredTasks, selectRandomTask]);

  const handleStartUpload = () => {
    if (!currentTask || !eventKey) return;
    triggerHaptic('light');
    navigate(`/e/${encodeURIComponent(eventKey)}/upload?task=${currentTask.id}&emotion=${currentTask.emotion?.slug || ''}`);
  };

  const handleViewSimilar = React.useCallback(() => {
    if (!currentTask || !eventKey) return;
    navigate(`/e/${encodeURIComponent(eventKey)}/gallery?task=${currentTask.id}`);
  }, [currentTask, eventKey, navigate]);

  const handleSelectTask = React.useCallback((task: Task) => {
    setCurrentTask(task);
    triggerHaptic('selection');
  }, []);

  const handleRetryFetch = () => {
    fetchTasks();
  };

  const handleRefresh = React.useCallback(async () => {
    tasksCacheRef.current.clear();
    await fetchTasks();
    setPhotoPool([]);
    setPhotoPoolError(null);
  }, [fetchTasks]);

  const handlePhotoPreview = React.useCallback(
    (photoId: number) => {
      if (!eventKey) return;
      navigate(`/e/${encodeURIComponent(eventKey)}/gallery?photoId=${photoId}&task=${currentTask?.id ?? ''}`);
    },
    [eventKey, navigate, currentTask?.id]
  );

  React.useEffect(() => {
    if (!filteredTasks.length) {
      setCurrentTask(null);
      return;
    }
    if (!currentTask || !filteredTasks.some((task) => task.id === currentTask.id)) {
      selectRandomTask(filteredTasks);
    }
  }, [filteredTasks, currentTask, selectRandomTask]);

  React.useEffect(() => {
    if (currentTask?.emotion?.slug) {
      setRecentEmotionSlug(currentTask.emotion.slug);
    }
  }, [currentTask?.emotion?.slug]);

  React.useEffect(() => {
    if (!eventKey || photoPool.length) return;
    const controller = new AbortController();
    setPhotoPoolLoading(true);
    setPhotoPoolError(null);
    fetch(`/api/v1/events/${encodeURIComponent(eventKey)}/photos?locale=${encodeURIComponent(locale)}`, {
      signal: controller.signal,
      headers: {
        Accept: 'application/json',
        'X-Locale': locale,
      },
    })
      .then((res) => {
        if (!res.ok) {
          throw new Error(t('tasks.page.inspirationError'));
        }
        return res.json();
      })
      .then((payload) => {
        const data = Array.isArray(payload?.data) ? (payload.data as EventPhoto[]) : [];
        setPhotoPool(data);
      })
      .catch((err) => {
        if (controller.signal.aborted) return;
        console.error('Failed to load photos', err);
        setPhotoPoolError(t('tasks.page.inspirationError'));
      })
      .finally(() => {
        if (!controller.signal.aborted) {
          setPhotoPoolLoading(false);
        }
      });

    return () => controller.abort();
  }, [eventKey, photoPool.length, t, locale]);

  const similarPhotos = React.useMemo(() => {
    if (!currentTask) return [];
    const matches = photoPool.filter((photo) => photo.task_id === currentTask.id);
    return matches.slice(0, SIMILAR_PHOTO_LIMIT);
  }, [photoPool, currentTask]);

  React.useEffect(() => {
    const card = heroCardRef.current;
    if (!card) return;
    let startX: number | null = null;
    let startY: number | null = null;

    const onTouchStart = (event: TouchEvent) => {
      const touch = event.touches[0];
      startX = touch.clientX;
      startY = touch.clientY;
    };

    const onTouchEnd = (event: TouchEvent) => {
      if (startX === null || startY === null) return;
      const touch = event.changedTouches[0];
      const deltaX = touch.clientX - startX;
      const deltaY = touch.clientY - startY;
      if (Math.abs(deltaX) > SWIPE_THRESHOLD_PX && Math.abs(deltaY) < 60) {
        if (deltaX < 0) {
          handleNewTask();
        } else {
          handleViewSimilar();
        }
        setHasSwiped(true);
      }
      startX = null;
      startY = null;
    };

    card.addEventListener('touchstart', onTouchStart, { passive: true });
    card.addEventListener('touchend', onTouchEnd);
    return () => {
      card.removeEventListener('touchstart', onTouchStart);
      card.removeEventListener('touchend', onTouchEnd);
    };
  }, [handleNewTask, handleViewSimilar]);

  const emptyState = !loading && (!filteredTasks.length || !currentTask);
  const heroTheme = React.useMemo(() => getEmotionTheme(currentTask?.emotion ?? null), [currentTask?.emotion]);
  const heroEmotionIcon = getEmotionIcon(currentTask?.emotion ?? null);
  const recentEmotionOption = React.useMemo(
    () => emotionOptions.find((option) => option.slug === recentEmotionSlug) ?? null,
    [emotionOptions, recentEmotionSlug]
  );
  const toggleValue = selectedEmotion === 'all' ? 'none' : 'recent';
  const motionEnabled = !prefersReducedMotion();
  const containerMotion = getMotionContainerPropsForNavigation(motionEnabled, STAGGER_FAST, navigationType);
  const fadeUpMotion = getMotionItemProps(motionEnabled, FADE_UP);
  const fadeScaleMotion = getMotionItemProps(motionEnabled, FADE_SCALE);

  const handleToggleChange = React.useCallback(
    (value: string) => {
      if (!value) return;
      if (value === 'picker') {
        setEmotionPickerOpen(true);
        return;
      }
      if (value === 'none') {
        handleSelectEmotion('all');
        return;
      }
      if (value === 'recent') {
        if (recentEmotionSlug) {
          handleSelectEmotion(recentEmotionSlug);
        } else {
          setEmotionPickerOpen(true);
        }
      }
    },
    [handleSelectEmotion, recentEmotionSlug]
  );

  return (
    <>
      <PullToRefresh
        onRefresh={handleRefresh}
        pullLabel={t('common.pullToRefresh')}
        releaseLabel={t('common.releaseToRefresh')}
        refreshingLabel={t('common.refreshing')}
      >
        <motion.div className="space-y-6" {...containerMotion}>
        <motion.header className="space-y-4" {...fadeUpMotion}>
          <div className="space-y-1">
            <p className="text-[11px] uppercase tracking-[0.4em] text-muted-foreground">{t('tasks.page.eyebrow')}</p>
            <h1 className="text-2xl font-semibold text-foreground">{t('tasks.page.title')}</h1>
            <p className="text-sm text-muted-foreground">{t('tasks.page.subtitle')}</p>
          </div>
          {emotionOptions.length > 0 && (
            <motion.div className="overflow-x-auto pb-1 [-ms-overflow-style:none] [scrollbar-width:none]" {...fadeUpMotion}>
              <ToggleGroup
                type="single"
                aria-label="Stimmung filtern"
                value={toggleValue}
                onValueChange={handleToggleChange}
                className="inline-flex gap-1 rounded-full bg-muted/60 p-1"
                variant="outline"
                size="sm"
              >
                <ToggleGroupItem
                  value="none"
                  className="rounded-full !rounded-full px-4 py-2 text-sm font-medium first:!rounded-full last:!rounded-full"
                >
                  <span className="mr-2">🎲</span>
                  {t('tasks.page.filters.none')}
                </ToggleGroupItem>
                <ToggleGroupItem
                  value="recent"
                  disabled={!recentEmotionOption}
                  className="rounded-full !rounded-full px-4 py-2 text-sm font-medium first:!rounded-full last:!rounded-full"
                >
                  <span className="mr-2">{getEmotionIcon(recentEmotionOption)}</span>
                  {recentEmotionOption?.name ?? t('tasks.page.filters.recentFallback')}
                </ToggleGroupItem>
                <ToggleGroupItem
                  value="picker"
                  className="rounded-full !rounded-full px-4 py-2 text-sm font-medium first:!rounded-full last:!rounded-full"
                >
                  <span className="mr-2">🗂️</span>
                  {t('tasks.page.filters.showAll')}
                </ToggleGroupItem>
              </ToggleGroup>
            </motion.div>
          )}
        </motion.header>

        {loading && (
          <motion.div className="space-y-4" {...fadeUpMotion}>
            <SkeletonBlock />
            <SkeletonBlock />
          </motion.div>
        )}

        {error && !loading && (
          <motion.div {...fadeUpMotion}>
            <Alert variant="destructive">
              <AlertDescription className="flex items-center justify-between gap-3">
                <span>{error}</span>
                <Button variant="outline" size="sm" onClick={handleRetryFetch} disabled={isFetching}>
                  Erneut versuchen
                </Button>
              </AlertDescription>
            </Alert>
          </motion.div>
        )}

        {emptyState && (
          <motion.div {...fadeUpMotion}>
            <EmptyState
              hasTasks={Boolean(tasks.length)}
              onRetry={handleRetryFetch}
              emotionOptions={emotionOptions}
              onEmotionSelect={handleSelectEmotion}
              t={t}
            />
          </motion.div>
        )}

        {!emptyState && currentTask && (
          <motion.div className="space-y-8" {...fadeUpMotion}>
            <motion.section
              ref={heroCardRef}
              className={cn(
                'relative overflow-hidden rounded-3xl p-5 text-white shadow-lg transition-[background] duration-700',
                'bg-gradient-to-br',
                heroTheme.gradientClass
              )}
              style={{ background: heroTheme.gradientBackground }}
              {...fadeScaleMotion}
            >
              <div className="relative space-y-5">
                <div className="flex flex-wrap items-center justify-between gap-3 text-xs font-semibold uppercase tracking-[0.25em] text-white/70">
                  <span className="flex items-center gap-2 tracking-[0.3em]">
                    <Sparkles className="h-4 w-4" />
                    {heroEmotionIcon} {currentTask.emotion?.name ?? 'Neue Mission'}
                  </span>
                  <span className="flex items-center gap-1 text-white tracking-normal">
                    <TimerIcon className="h-4 w-4" />
                    {currentTask.duration} Min
                  </span>
                </div>

                <div className="space-y-3">
                  <h2 className="text-3xl font-semibold leading-tight drop-shadow-sm">{currentTask.title}</h2>
                  <p className="text-sm leading-relaxed text-white/80">{currentTask.description}</p>
                </div>

                {!hasSwiped && (
                  <p className="text-[11px] uppercase tracking-[0.4em] text-white/70">
                    {t('tasks.page.swipeHint')}
                  </p>
                )}

                {currentTask.instructions && (
                  <div className="rounded-2xl bg-white/15 p-3 text-sm font-medium text-white/90">
                    {currentTask.instructions}
                  </div>
                )}

                <div className="flex flex-wrap gap-2 text-sm text-white/80">
                  {isCompleted(currentTask.id) && (
                    <span className="rounded-full border border-white/30 px-3 py-1">
                      <CheckCircle2 className="mr-1 inline h-4 w-4" />
                      {t('tasks.page.completedLabel')}
                    </span>
                  )}
                </div>

                <div className="grid grid-cols-3 gap-3">
                  <Button
                    onClick={handleStartUpload}
                    className="col-span-2 flex h-14 items-center justify-center gap-2 rounded-2xl text-base font-semibold text-white shadow-lg shadow-black/10 transition hover:scale-[1.01]"
                    style={cameraButtonStyle}
                  >
                    <Camera className="h-6 w-6" />
                    {t('tasks.page.ctaStart')}
                  </Button>
                  <HeroActionButton
                    icon={RefreshCw}
                    label={t('tasks.page.shuffleCta')}
                    onClick={handleNewTask}
                    className="h-12 justify-center px-3 py-2"
                  />
                </div>

                {(photoPoolLoading || photoPoolError || similarPhotos.length > 0) && (
                  <div className="space-y-2 rounded-2xl border border-white/25 bg-white/10 p-3">
                    <div className="flex items-center justify-between text-xs font-semibold uppercase tracking-[0.3em] text-white/70">
                      <span>{t('tasks.page.inspirationTitle')}</span>
                      {photoPoolLoading && <span className="text-[10px] text-white/70">{t('tasks.page.inspirationLoading')}</span>}
                    </div>
                    {photoPoolError && similarPhotos.length === 0 ? (
                      <p className="text-xs text-white/80">{photoPoolError}</p>
                    ) : similarPhotos.length > 0 ? (
                      <div className="flex gap-3 overflow-x-auto pb-2 [-ms-overflow-style:none] [scrollbar-width:none]">
                        {similarPhotos.map((photo) => (
                          <SimilarPhotoChip key={photo.id} photo={photo} onOpen={handlePhotoPreview} />
                        ))}
                        <button
                          type="button"
                          onClick={handleViewSimilar}
                          className="flex h-16 min-w-[64px] flex-col items-center justify-center rounded-2xl border border-dashed border-white/40 px-3 text-center text-[11px] font-semibold uppercase tracking-[0.3em] text-white/80"
                        >
                          {t('tasks.page.inspirationMore')}
                        </button>
                      </div>
                    ) : (
                      <button
                        type="button"
                        onClick={handleStartUpload}
                        className="flex items-center justify-between rounded-2xl border border-white/30 bg-white/10 px-4 py-3 text-sm text-white/80 transition hover:bg-white/20"
                      >
                        <div className="text-left">
                          <p className="font-semibold">{t('tasks.page.inspirationEmptyTitle')}</p>
                          <p className="text-xs text-white/70">{t('tasks.page.inspirationEmptyDescription')}</p>
                        </div>
                        <Camera className="h-4 w-4" />
                      </button>
                    )}
                  </div>
                )}
              </div>
            </motion.section>

            {alternativeTasks.length > 0 && (
              <motion.section className="space-y-3" {...fadeUpMotion}>
                <div className="flex items-center justify-between">
                  <div>
                    <p className="text-sm uppercase tracking-[0.2em] text-muted-foreground">{t('tasks.page.suggestionsEyebrow')}</p>
                    <h2 className="text-lg font-semibold text-foreground">{t('tasks.page.suggestionsTitle')}</h2>
                  </div>
                  <Button variant="outline" size="sm" onClick={handleNewTask} className="shrink-0">
                    {t('tasks.page.shuffleButton')}
                  </Button>
                </div>
                <div className="flex gap-3 overflow-x-auto pb-2 [-ms-overflow-style:none] [scrollbar-width:none]">
                  {alternativeTasks.map((task) => (
                    <TaskSuggestionCard key={task.id} task={task} onSelect={handleSelectTask} />
                  ))}
                </div>
              </motion.section>
            )}
          </motion.div>
        )}

        {!loading && !tasks.length && !error && (
          <motion.div {...fadeUpMotion}>
            <Alert>
              <AlertDescription>{t('tasks.page.noTasksAlert')}</AlertDescription>
            </Alert>
          </motion.div>
        )}
        </motion.div>
      </PullToRefresh>
      <Dialog open={emotionPickerOpen} onOpenChange={setEmotionPickerOpen}>
        <DialogContent className="max-h-[90vh] overflow-y-auto" hideClose>
          <DialogHeader>
            <DialogTitle>{t('tasks.page.filters.dialogTitle')}</DialogTitle>
          </DialogHeader>
          {emotionOptions.length ? (
            <div className="grid gap-3 sm:grid-cols-2">
              {emotionOptions.map((emotion) => {
                const count = emotionCounts.get(emotion.slug) ?? 0;
                return (
                  <button
                    key={emotion.slug}
                    type="button"
                    onClick={() => {
                      handleSelectEmotion(emotion.slug);
                      setEmotionPickerOpen(false);
                    }}
                    className="flex items-center gap-3 rounded-2xl border border-muted/50 px-4 py-3 text-left transition hover:border-pink-300"
                  >
                    <span className="text-2xl" aria-hidden>
                      {getEmotionIcon(emotion)}
                    </span>
                    <div>
                      <p className="font-semibold text-foreground">{emotion.name}</p>
                      <p className="text-xs text-muted-foreground">
                        {count === 1
                          ? t('tasks.page.filters.countOne', { count })
                          : t('tasks.page.filters.countMany', { count })}
                      </p>
                    </div>
                  </button>
                );
              })}
            </div>
          ) : (
            <p className="text-sm text-muted-foreground">{t('tasks.page.filters.empty')}</p>
          )}
        </DialogContent>
      </Dialog>
    </>
  );
}

function SkeletonBlock() {
  return <div className="h-24 animate-pulse rounded-xl bg-muted/60" />;
}

function EmptyState({
  hasTasks,
  onRetry,
  emotionOptions,
  onEmotionSelect,
  t,
}: {
  hasTasks: boolean;
  onRetry: () => void;
  emotionOptions: EmotionOption[];
  onEmotionSelect: (slug: string) => void;
  t: TranslateFn;
}) {
  return (
    <div className="flex flex-col items-center justify-center gap-4 rounded-2xl border border-dashed border-muted-foreground/30 bg-muted/20 p-8 text-center">
      <Smile className="h-12 w-12 text-pink-500" aria-hidden />
      <div className="space-y-2">
        <h2 className="text-xl font-semibold">{t('tasks.page.emptyTitle')}</h2>
        <p className="text-sm text-muted-foreground">
          {hasTasks ? t('tasks.page.emptyDescriptionWithTasks') : t('tasks.page.emptyDescriptionNoTasks')}
        </p>
      </div>
      {hasTasks && emotionOptions.length > 0 && (
        <div className="grid w-full max-w-md grid-cols-2 gap-2 sm:grid-cols-3">
          {emotionOptions.map((emotion) => (
            <button
              key={emotion.slug}
              type="button"
              onClick={() => onEmotionSelect(emotion.slug)}
              className="rounded-full border border-border px-4 py-1 text-sm text-muted-foreground transition hover:border-pink-400 hover:text-foreground"
            >
              {emotion.name}
            </button>
          ))}
        </div>
      )}
      <Button onClick={onRetry} variant="outline" className="mt-2">
        {t('tasks.page.reloadButton')}
      </Button>
    </div>
  );
}

function HeroActionButton({
  icon: Icon,
  label,
  detail,
  onClick,
  className,
}: {
  icon: LucideIcon;
  label: string;
  detail?: string;
  onClick: () => void;
  className?: string;
}) {
  return (
    <button
      type="button"
      onClick={onClick}
      className={cn('flex flex-col rounded-2xl border border-white/30 bg-white/10 px-4 py-3 text-left text-sm font-medium text-white transition hover:bg-white/20', className)}
    >
      <span className="flex items-center gap-2 text-base font-semibold">
        <Icon className="h-4 w-4" />
        {label}
      </span>
      {detail && <span className="mt-1 text-xs text-white/80">{detail}</span>}
    </button>
  );
}

function SimilarPhotoChip({ photo, onOpen }: { photo: EventPhoto; onOpen: (photoId: number) => void }) {
  const cover = photo.thumbnail_path || photo.file_path || '';
  return (
    <button
      type="button"
      onClick={() => onOpen(photo.id)}
      className="relative h-16 w-16 overflow-hidden rounded-2xl border border-white/30 bg-white/10"
    >
      {cover ? (
        <img
          src={cover}
          alt="Eventfoto"
          className="h-full w-full object-cover"
          loading="lazy"
          decoding="async"
        />
      ) : (
        <div className="flex h-full w-full items-center justify-center text-[10px] font-semibold uppercase tracking-[0.3em] text-white/70">
          Foto
        </div>
      )}
      <div className="absolute bottom-1 left-1 flex items-center gap-1 rounded-full bg-black/60 px-1.5 py-0.5 text-[10px] font-semibold text-white">
        <Heart className="h-3 w-3" />
        <span>{photo.likes_count ?? 0}</span>
      </div>
    </button>
  );
}

function TaskSuggestionCard({ task, onSelect }: { task: Task; onSelect: (task: Task) => void }) {
  const theme = getEmotionTheme(task.emotion ?? null);
  const emotionIcon = getEmotionIcon(task.emotion ?? null);
  return (
    <button
      type="button"
      onClick={() => onSelect(task)}
      className={cn(
        'group flex min-w-[220px] flex-col justify-between rounded-2xl border p-4 text-left shadow-sm transition hover:-translate-y-0.5 hover:shadow-md',
        'bg-gradient-to-br text-gray-900 dark:text-white',
        theme.suggestionGradient,
        theme.suggestionBorder
      )}
    >
      <div className="space-y-2">
        <p className="text-xs uppercase tracking-[0.3em] text-gray-500 group-hover:text-gray-700 dark:text-gray-300">
          {emotionIcon} {task.emotion?.name ?? 'Aufgabe'}
        </p>
        <h3 className="text-base font-semibold leading-tight line-clamp-2">{task.title}</h3>
        <p className="text-xs text-gray-600 line-clamp-2 dark:text-gray-200">{task.description}</p>
      </div>
      <div className="mt-3 flex items-center justify-between text-xs font-semibold">
        <span>{task.duration} Min</span>
        <span className="flex items-center gap-1 text-pink-600 dark:text-pink-200">
          Starten
          <ChevronRight className="h-3.5 w-3.5" />
        </span>
      </div>
    </button>
  );
}
