// @ts-nocheck
import React from 'react';
import { useNavigate, useParams, useSearchParams } from 'react-router-dom';
import {
  AlertTriangle,
  Camera,
  Check,
  Copy,
  Eye,
  EyeOff,
  Filter,
  Loader2,
  Search,
  ShoppingCart,
  Star,
  Trash2,
  X,
} from 'lucide-react';

import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert';
import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import { Input } from '@/components/ui/input';
import { Checkbox } from '@/components/ui/checkbox';
import { Label } from '@/components/ui/label';
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import toast from 'react-hot-toast';
import { AddonsPicker } from '../components/Addons/AddonsPicker';
import { AddonSummaryList } from '../components/Addons/AddonSummaryList';
import { getAddonCatalog, type EventAddonCatalogItem, type EventAddonSummary } from '../api';

import { AdminLayout } from '../components/AdminLayout';
import { createEventAddonCheckout, deletePhoto, featurePhoto, getEvent, getEventPhotos, TenantEvent, TenantPhoto, unfeaturePhoto, updatePhotoVisibility, type PaginationMeta } from '../api';
import { isAuthError } from '../auth/tokens';
import { getApiErrorMessage } from '../lib/apiError';
import { buildLimitWarnings, type EventLimitSummary } from '../lib/limitWarnings';
import { useTranslation } from 'react-i18next';
import { ADMIN_EVENTS_PATH, ADMIN_EVENT_VIEW_PATH, ADMIN_EVENT_PHOTOBOOTH_PATH } from '../constants';
import { buildEventTabs } from '../lib/eventTabs';

export default function EventPhotosPage() {
  const PAGE_SIZE = 40;
  const params = useParams<{ slug?: string }>();
  const [searchParams, setSearchParams] = useSearchParams();
  const slug = params.slug ?? searchParams.get('slug') ?? null;
  const navigate = useNavigate();
  const { t } = useTranslation('management');
  const { t: tCommon } = useTranslation('common');
  const translateLimits = React.useCallback(
    (key: string, options?: Record<string, unknown>) => tCommon(`limits.${key}`, options),
    [tCommon]
  );

  const [photos, setPhotos] = React.useState<TenantPhoto[]>([]);
  const [loading, setLoading] = React.useState(true);
  const [error, setError] = React.useState<string | undefined>(undefined);
  const [busyId, setBusyId] = React.useState<number | null>(null);
  const [limits, setLimits] = React.useState<EventLimitSummary | null>(null);
  const [addons, setAddons] = React.useState<EventAddonCatalogItem[]>([]);
  const [eventAddons, setEventAddons] = React.useState<EventAddonSummary[]>([]);
  const [event, setEvent] = React.useState<TenantEvent | null>(null);
  const [search, setSearch] = React.useState('');
  const [statusFilter, setStatusFilter] = React.useState<'all' | 'featured' | 'hidden' | 'photobooth'>('all');
  const [selectedIds, setSelectedIds] = React.useState<number[]>([]);
  const [bulkBusy, setBulkBusy] = React.useState(false);
  const [showSearch, setShowSearch] = React.useState(false);
  const [sortOrder, setSortOrder] = React.useState<'desc' | 'asc'>('desc');
  const [page, setPage] = React.useState(1);
  const [pagination, setPagination] = React.useState<PaginationMeta | null>(null);
  const [pendingDelete, setPendingDelete] = React.useState<TenantPhoto | null>(null);
  const [skipDeleteConfirm, setSkipDeleteConfirm] = React.useState(() =>
    typeof window !== 'undefined' ? window.sessionStorage.getItem(DELETE_CONFIRM_SKIP_KEY) === '1' : false,
  );
  const updateSkipDeleteConfirm = React.useCallback((value: boolean) => {
    setSkipDeleteConfirm(value);
    if (typeof window === 'undefined') {
      return;
    }
    if (value) {
      window.sessionStorage.setItem(DELETE_CONFIRM_SKIP_KEY, '1');
    } else {
      window.sessionStorage.removeItem(DELETE_CONFIRM_SKIP_KEY);
    }
  }, []);
  const photoboothUploads = React.useMemo(
    () => photos.filter((photo) => photo.ingest_source === 'photobooth').length,
    [photos],
  );

  const eventTabs = React.useMemo(() => {
    if (!event || !slug) {
      return [];
    }
    const translateMenu = (key: string, fallback: string) => t(key, { defaultValue: fallback });
    const photoBadge = !loading ? event.photo_count ?? pagination?.total : undefined;
    return buildEventTabs(event, translateMenu, {
      photos: photoBadge,
      tasks: event.tasks_count ?? undefined,
    });
  }, [event, slug, t, loading, pagination?.total]);

  const load = React.useCallback(async () => {
    if (!slug) {
      setLoading(false);
      return;
    }
    setLoading(true);
    setError(undefined);
    try {
      const visibility = statusFilter === 'hidden' ? 'hidden' : 'visible';
      const [photoResult, eventData, catalog] = await Promise.all([
        getEventPhotos(slug, {
          page,
          perPage: PAGE_SIZE,
          sort: sortOrder,
          search: search.trim() || undefined,
          status: statusFilter === 'hidden' ? 'hidden' : undefined,
          featured: statusFilter === 'featured',
          ingestSource: statusFilter === 'photobooth' ? 'photobooth' : undefined,
          visibility,
        }),
        getEvent(slug),
        getAddonCatalog(),
      ]);
      setPhotos(photoResult.photos);
      setLimits(photoResult.limits ?? null);
      setPagination(photoResult.meta ?? null);
      setEventAddons(eventData.addons ?? []);
      setEvent({
        ...eventData,
        photo_count: photoResult.meta?.total ?? eventData.photo_count,
      });
      setAddons(catalog);
    } catch (err) {
      if (!isAuthError(err)) {
        setError(getApiErrorMessage(err, 'Fotos konnten nicht geladen werden.'));
      }
    } finally {
      setLoading(false);
    }
  }, [slug, page, sortOrder, search, statusFilter]);

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

  React.useEffect(() => {
    const success = searchParams.get('addon_success');
    if (success && slug) {
      toast(translateLimits('addonApplied', { defaultValue: 'Add-on angewendet. Limits aktualisieren sich in Kürze.' }));
      void load();
      const params = new URLSearchParams(searchParams);
      params.delete('addon_success');
      setSearchParams(params);
      navigate(window.location.pathname, { replace: true });
    }
  }, [searchParams, slug, load, navigate, translateLimits, setSearchParams]);

  async function handleToggleFeature(photo: TenantPhoto) {
    if (!slug) return;
    setBusyId(photo.id);
    try {
      const updated = photo.is_featured
        ? await unfeaturePhoto(slug, photo.id)
        : await featurePhoto(slug, photo.id);
      setPhotos((prev) => prev.map((entry) => (entry.id === photo.id ? updated : entry)));
    } catch (err) {
      if (!isAuthError(err)) {
        setError(getApiErrorMessage(err, 'Feature-Aktion fehlgeschlagen.'));
      }
    } finally {
      setBusyId(null);
    }
  }

  async function handleDelete(photo: TenantPhoto) {
    if (!slug) return;
    setBusyId(photo.id);
    try {
      await deletePhoto(slug, photo.id);
      setPhotos((prev) => prev.filter((entry) => entry.id !== photo.id));
      toast.success(t('photos.actions.deleteSuccess', 'Foto gelöscht'));
    } catch (err) {
      if (!isAuthError(err)) {
        setError(getApiErrorMessage(err, 'Foto konnte nicht entfernt werden.'));
        toast.error(t('photos.actions.deleteFailed', 'Foto konnte nicht entfernt werden.'));
      }
    } finally {
      setBusyId(null);
    }
  }

  const requestDelete = React.useCallback(
    (photo: TenantPhoto) => {
      if (skipDeleteConfirm) {
        void handleDelete(photo);
        return;
      }
      setPendingDelete(photo);
    },
    [skipDeleteConfirm, handleDelete],
  );

  const confirmDelete = React.useCallback(() => {
    if (!pendingDelete) return;
    void handleDelete(pendingDelete);
    setPendingDelete(null);
  }, [pendingDelete, handleDelete]);

  const cancelDelete = React.useCallback(() => {
    setPendingDelete(null);
  }, []);

  async function handleToggleVisibility(photo: TenantPhoto, visible: boolean) {
    if (!slug) return;
    const shouldRemove = (!visible && statusFilter !== 'hidden') || (visible && statusFilter === 'hidden');
    if (shouldRemove) {
      setPhotos((prev) => prev.filter((entry) => entry.id !== photo.id));
    }
    setBusyId(photo.id);
    try {
      const updated = await updatePhotoVisibility(slug, photo.id, visible);
      if (!shouldRemove) {
        setPhotos((prev) => prev.map((entry) => (entry.id === photo.id ? updated : entry)));
      }
      setSelectedIds((prev) => prev.filter((id) => id !== photo.id));
      toast.success(
        visible
          ? t('photos.actions.showSuccess', 'Foto eingeblendet')
          : t('photos.actions.hideSuccess', 'Foto versteckt')
      );
      void load();
    } catch (err) {
      if (!isAuthError(err)) {
        setError(getApiErrorMessage(err, 'Sichtbarkeit konnte nicht geändert werden.'));
        toast.error(t('photos.actions.hideFailed', 'Sichtbarkeit konnte nicht geändert werden.'));
      }
    } finally {
      setBusyId(null);
    }
  }

  React.useEffect(() => {
    setPage(1);
  }, [search, statusFilter, sortOrder]);

  const pageCount = pagination?.last_page ?? 1;
  const currentPage = Math.min(page, pageCount || 1);
  const paginatedPhotos = photos;
  const totalCount = pagination?.total ?? photos.length;

  const toggleSelect = React.useCallback((photoId: number) => {
    setSelectedIds((prev) => (prev.includes(photoId) ? prev.filter((id) => id !== photoId) : [...prev, photoId]));
  }, []);

  const selectAllVisible = React.useCallback(() => {
    setSelectedIds(paginatedPhotos.map((photo) => photo.id));
  }, [paginatedPhotos]);

  const clearSelection = React.useCallback(() => {
    setSelectedIds([]);
  }, []);

  const selectedPhotos = React.useMemo(
    () => photos.filter((photo) => selectedIds.includes(photo.id)),
    [photos, selectedIds],
  );

  const handleBulkVisibility = React.useCallback(
    async (visible: boolean) => {
      if (!slug || !selectedPhotos.length) return;
      setBulkBusy(true);
      const shouldRemove = (!visible && statusFilter !== 'hidden') || (visible && statusFilter === 'hidden');
      if (shouldRemove) {
        setPhotos((prev) => prev.filter((entry) => !selectedPhotos.find((item) => item.id === entry.id)));
      }
      try {
        const updates = await Promise.all(
          selectedPhotos.map(async (photo) => updatePhotoVisibility(slug, photo.id, visible)),
        );
        if (!shouldRemove) {
          setPhotos((prev) => prev.map((entry) => updates.find((item) => item.id === entry.id) ?? entry));
        }
        setSelectedIds([]);
        toast.success(
          visible
            ? t('photos.actions.bulkShowSuccess', 'Ausgewählte Fotos eingeblendet')
            : t('photos.actions.bulkHideSuccess', 'Ausgewählte Fotos versteckt')
        );
        void load();
      } catch (err) {
        if (!isAuthError(err)) {
          setError(getApiErrorMessage(err, 'Sichtbarkeit konnte nicht geändert werden.'));
          toast.error(t('photos.actions.hideFailed', 'Sichtbarkeit konnte nicht geändert werden.'));
        }
      } finally {
        setBulkBusy(false);
      }
    },
    [selectedPhotos, slug],
  );

  const handleBulkFeature = React.useCallback(
    async (featured: boolean) => {
      if (!slug || !selectedPhotos.length) return;
      setBulkBusy(true);
      try {
        for (const photo of selectedPhotos) {
          setBusyId(photo.id);
          try {
            const updated = featured
              ? await featurePhoto(slug, photo.id)
              : await unfeaturePhoto(slug, photo.id);
            setPhotos((prev) => prev.map((entry) => (entry.id === photo.id ? updated : entry)));
          } catch (err) {
            if (!isAuthError(err)) {
              setError(getApiErrorMessage(err, 'Feature-Aktion fehlgeschlagen.'));
            }
          } finally {
            setBusyId(null);
          }
        }
        setSelectedIds([]);
      } finally {
        setBulkBusy(false);
      }
    },
    [selectedPhotos, slug],
  );

  if (!slug) {
    return (
      <AdminLayout title="Fotos moderieren" subtitle="Bitte wähle ein Event aus der Übersicht." actions={null}>
        <Card className="border-0 bg-white/85 shadow-xl shadow-pink-100/60">
          <CardContent className="p-6 text-sm text-slate-600">
            Kein Slug in der URL gefunden. Kehre zur Event-Liste zurück und wähle dort ein Event aus.
            <Button className="mt-4" onClick={() => navigate(ADMIN_EVENTS_PATH)}>
              Zurück zur Liste
            </Button>
          </CardContent>
        </Card>
      </AdminLayout>
    );
  }

  const actions = (
    <Button
      variant="outline"
      onClick={() => slug && navigate(ADMIN_EVENT_VIEW_PATH(slug))}
      className="border-pink-200 text-pink-600 hover:bg-pink-50"
    >
      Zurück zum Event
    </Button>
  );

  return (
    <AdminLayout
      title={t('photos.moderation.title', 'Fotos moderieren')}
      subtitle={t('photos.moderation.subtitle', 'Setze Highlights oder entferne unpassende Uploads.')}
      actions={actions}
      tabs={eventTabs}
      currentTabKey="photos"
    >
      {error && (
        <Alert variant="destructive">
          <AlertTitle>{t('photos.alerts.errorTitle', 'Aktion fehlgeschlagen')}</AlertTitle>
          <AlertDescription>{error}</AlertDescription>
        </Alert>
      )}

      <LimitWarningsBanner limits={limits} translate={translateLimits} eventSlug={slug} addons={addons} />

      <Card className="border-0 bg-white/85 shadow-xl shadow-sky-100/60">
        <CardHeader className="flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between">
          <div>
            <CardTitle className="flex items-center gap-2 text-xl text-slate-900">
              <Camera className="h-5 w-5 text-sky-500" /> {t('photos.gallery.title', 'Galerie')}
            </CardTitle>
            <CardDescription className="text-sm text-slate-600">
              {t('photos.gallery.description', 'Klick auf ein Foto, um es hervorzuheben oder zu löschen.')}
            </CardDescription>
          </div>
          <div className="flex flex-wrap items-center gap-2">
            <Badge variant="outline" className="border-sky-200 text-sky-700">
              {t('photos.gallery.photoboothCount', '{{count}} Photobooth-Uploads', { count: photoboothUploads })}
            </Badge>
            <Button
              variant="ghost"
              size="sm"
              onClick={() => slug && navigate(ADMIN_EVENT_PHOTOBOOTH_PATH(slug))}
              disabled={!slug}
              className="text-rose-600 hover:bg-rose-50"
            >
              {t('photos.gallery.photoboothCta', 'Photobooth-Zugang öffnen')}
            </Button>
          </div>
        </CardHeader>
        <CardContent>
          <GalleryToolbar
            search={search}
            onSearch={setSearch}
            statusFilter={statusFilter}
            onStatusFilterChange={setStatusFilter}
            totalCount={totalCount}
            page={currentPage}
            pageCount={pageCount}
            onPageChange={setPage}
            selectionCount={selectedIds.length}
            onSelectAll={selectAllVisible}
            onClearSelection={clearSelection}
            onBulkHide={() => { void handleBulkVisibility(false); }}
            onBulkShow={() => { void handleBulkVisibility(true); }}
            onBulkFeature={() => { void handleBulkFeature(true); }}
            onBulkUnfeature={() => { void handleBulkFeature(false); }}
            busy={bulkBusy}
            sortOrder={sortOrder}
            onSortOrderChange={setSortOrder}
            showSearch={showSearch}
            onToggleSearch={() => setShowSearch((prev) => !prev)}
          />
          {loading ? (
            <GallerySkeleton />
          ) : totalCount === 0 ? (
            <EmptyGallery
              title={t('photos.gallery.emptyTitle', 'Noch keine Fotos vorhanden')}
              description={t('photos.gallery.emptyDescription', 'Motiviere deine Gäste zum Hochladen - hier erscheint anschließend die Galerie.')}
            />
          ) : (
            <PhotoGrid
              photos={paginatedPhotos}
              selectedIds={selectedIds}
              onToggleSelect={toggleSelect}
              onToggleFeature={(photo) => { void handleToggleFeature(photo); }}
              onToggleVisibility={(photo, visible) => { void handleToggleVisibility(photo, visible); }}
              onRequestDelete={(photo) => { requestDelete(photo); }}
              busyId={busyId}
            />
          )}
        </CardContent>
      </Card>

      {eventAddons.length > 0 && (
        <Card className="mt-6 border-0 bg-white/85 shadow-lg shadow-slate-100/50">
          <CardHeader>
            <CardTitle className="text-base font-semibold text-slate-900">
              {t('events.sections.addons.title', 'Add-ons & Upgrades')}
            </CardTitle>
            <CardDescription>
              {t('events.sections.addons.description', 'Zusätzliche Kontingente für dieses Event.')}
            </CardDescription>
          </CardHeader>
          <CardContent>
            <AddonSummaryList addons={eventAddons} t={(key, fallback) => t(key, fallback)} />
          </CardContent>
        </Card>
      )}

      <DeletePhotoDialog
        open={Boolean(pendingDelete)}
        photo={pendingDelete}
        onCancel={cancelDelete}
        onConfirm={confirmDelete}
        skipConfirm={skipDeleteConfirm}
        onSkipChange={updateSkipDeleteConfirm}
      />
    </AdminLayout>
  );
}

const LIMIT_WARNING_DISMISS_KEY = 'tenant-admin:dismissed-limit-warnings';
const DELETE_CONFIRM_SKIP_KEY = 'tenant-admin:skip-photo-delete-confirm';

function readDismissedLimitWarnings(): Set<string> {
  if (typeof window === 'undefined') {
    return new Set();
  }
  try {
    const raw = window.localStorage.getItem(LIMIT_WARNING_DISMISS_KEY);
    if (!raw) {
      return new Set();
    }
    const parsed = JSON.parse(raw) as string[];
    return new Set(parsed);
  } catch (error) {
    console.warn('[LimitWarnings] Failed to parse dismissed warnings', error);
    return new Set();
  }
}

function persistDismissedLimitWarnings(ids: Set<string>) {
  if (typeof window === 'undefined') {
    return;
  }
  try {
    window.localStorage.setItem(LIMIT_WARNING_DISMISS_KEY, JSON.stringify(Array.from(ids)));
  } catch (error) {
    console.warn('[LimitWarnings] Failed to persist dismissed warnings', error);
  }
}

function LimitWarningsBanner({
  limits,
  translate,
  eventSlug,
  addons,
}: {
  limits: EventLimitSummary | null;
  translate: (key: string, options?: Record<string, unknown>) => string;
  eventSlug: string | null;
  addons: EventAddonCatalogItem[];
}) {
  const warnings = React.useMemo(() => buildLimitWarnings(limits, translate), [limits, translate]);
  const [busyScope, setBusyScope] = React.useState<string | null>(null);
  const [dismissedIds, setDismissedIds] = React.useState<Set<string>>(() => readDismissedLimitWarnings());
  const { t: tCommon } = useTranslation('common');
  const dismissLabel = tCommon('actions.dismiss', { defaultValue: 'Hinweis ausblenden' });

  const handleCheckout = React.useCallback(
    async (scopeOrKey: 'photos' | 'gallery' | string) => {
      if (!eventSlug) return;
      const scope = scopeOrKey === 'gallery' || scopeOrKey === 'photos' ? scopeOrKey : (scopeOrKey.includes('gallery') ? 'gallery' : 'photos');
      setBusyScope(scope);
      const addonKey = scopeOrKey === 'photos' || scopeOrKey === 'gallery'
        ? (() => {
            const fallbackKey = scope === 'photos' ? 'extra_photos_500' : 'extend_gallery_30d';
            const candidates = addons.filter((addon) => addon.price_id && addon.key.includes(scope === 'photos' ? 'photos' : 'gallery'));
            return candidates[0]?.key ?? fallbackKey;
          })()
        : scopeOrKey;
      try {
        const currentUrl = window.location.origin + window.location.pathname;
        const successUrl = `${currentUrl}?addon_success=1`;
        const checkout = await createEventAddonCheckout(eventSlug, {
          addon_key: addonKey,
          quantity: 1,
          success_url: successUrl,
          cancel_url: currentUrl,
        });
        if (checkout.checkout_url) {
          window.location.href = checkout.checkout_url;
        }
      } catch (err) {
        toast(getApiErrorMessage(err, 'Checkout fehlgeschlagen.'));
      } finally {
        setBusyScope(null);
      }
    },
    [eventSlug, addons],
  );

  const handleDismiss = React.useCallback((warningId: string) => {
    setDismissedIds((prev) => {
      const next = new Set(prev);
      next.add(warningId);
      persistDismissedLimitWarnings(next);
      return next;
    });
  }, []);

  const visibleWarnings = warnings.filter((warning) => !dismissedIds.has(warning.id));

  if (!visibleWarnings.length) {
    return null;
  }

  return (
    <div className="mb-6 space-y-2">
      {visibleWarnings.map((warning) => (
        <Alert
          key={warning.id}
          variant={warning.tone === 'danger' ? 'destructive' : 'default'}
          className={warning.tone === 'warning' ? 'border-amber-400/40 bg-amber-50 text-amber-900' : undefined}
        >
          <div className="flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between">
            <div className="flex flex-1 items-center gap-2 text-sm">
              <AlertTriangle className="h-4 w-4" />
              <AlertDescription className="flex-1 text-sm">
                {warning.message}
              </AlertDescription>
            </div>
            <div className="flex flex-col gap-2 sm:flex-row sm:items-center sm:gap-3">
              {warning.scope === 'photos' || warning.scope === 'gallery' ? (
                <div className="flex flex-col gap-2 sm:flex-row sm:items-center sm:gap-3">
                  <Button
                    variant="outline"
                    size="sm"
                    onClick={() => { void handleCheckout(warning.scope as 'photos' | 'gallery'); }}
                    disabled={busyScope === warning.scope}
                  >
                    <ShoppingCart className="mr-2 h-4 w-4" />
                    {warning.scope === 'photos'
                      ? translate('buyMorePhotos', { defaultValue: 'Mehr Fotos freischalten' })
                      : translate('extendGallery', { defaultValue: 'Galerie verlängern' })}
                  </Button>
                  {warning.scope !== 'guests' ? (
                    <AddonsPicker
                      addons={addons}
                      scope={warning.scope as 'photos' | 'gallery'}
                      onCheckout={(key) => { void handleCheckout(key); }}
                      busy={busyScope === warning.scope}
                      t={(key, fallback) => translate(key, { defaultValue: fallback })}
                    />
                  ) : null}
                </div>
              ) : null}
              <Button
                variant="ghost"
                size="icon"
                aria-label={dismissLabel}
                className="text-slate-500 hover:text-slate-800"
                onClick={() => handleDismiss(warning.id)}
              >
                <X className="h-4 w-4" />
              </Button>
            </div>
          </div>
        </Alert>
      ))}
    </div>
  );
}

function GallerySkeleton() {
  return (
    <div className="grid grid-cols-1 gap-4 sm:grid-cols-2 md:grid-cols-3">
      {Array.from({ length: 6 }).map((_, index) => (
        <div key={index} className="aspect-square animate-pulse rounded-2xl bg-gradient-to-r from-white/40 via-white/60 to-white/40" />
      ))}
    </div>
  );
}

function EmptyGallery({ title, description }: { title: string; description: string }) {
  return (
    <div className="flex flex-col items-center justify-center gap-3 rounded-2xl border border-dashed border-sky-200 bg-white/70 p-10 text-center">
      <div className="rounded-full bg-sky-100 p-3 text-sky-600 shadow-inner shadow-sky-200/80">
        <Camera className="h-5 w-5" />
      </div>
      <h3 className="text-lg font-semibold text-slate-900">{title}</h3>
      <p className="text-sm text-slate-600">{description}</p>
    </div>
  );
}

function GalleryToolbar({
  search,
  onSearch,
  showSearch,
  onToggleSearch,
  statusFilter,
  onStatusFilterChange,
  totalCount,
  page,
  pageCount,
  onPageChange,
  selectionCount,
  onSelectAll,
  onClearSelection,
  onBulkHide,
  onBulkShow,
  onBulkFeature,
  onBulkUnfeature,
  sortOrder,
  onSortOrderChange,
  busy,
}: {
  search: string;
  onSearch: (value: string) => void;
  showSearch: boolean;
  onToggleSearch: () => void;
  statusFilter: 'all' | 'featured' | 'hidden' | 'photobooth';
  onStatusFilterChange: (value: 'all' | 'featured' | 'hidden' | 'photobooth') => void;
  totalCount: number;
  page: number;
  pageCount: number;
  onPageChange: (page: number) => void;
  selectionCount: number;
  onSelectAll: () => void;
  onClearSelection: () => void;
  onBulkHide: () => void;
  onBulkShow: () => void;
  onBulkFeature: () => void;
  onBulkUnfeature: () => void;
  sortOrder: 'desc' | 'asc';
  onSortOrderChange: (value: 'desc' | 'asc') => void;
  busy: boolean;
}) {
  const { t } = useTranslation('management');
  const filters = [
    { key: 'all', label: t('photos.filters.all', 'Alle') },
    { key: 'featured', label: t('photos.filters.featured', 'Highlights') },
    { key: 'hidden', label: t('photos.filters.hidden', 'Versteckt') },
    { key: 'photobooth', label: t('photos.filters.photobooth', 'Photobooth') },
  ] as const;

  return (
    <div className="mb-4 space-y-4">
      <div className="flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between">
        <div className="flex flex-1 flex-wrap items-center gap-2">
          {showSearch ? (
            <div className="flex min-w-[240px] flex-1 items-center gap-2 rounded-full border border-slate-200 px-3 py-1">
              <Search className="h-4 w-4 text-slate-500" />
              <Input
                autoFocus
                value={search}
                onChange={(event) => onSearch(event.target.value)}
                placeholder={t('photos.filters.search', 'Uploads durchsuchen …')}
                className="h-8 border-0 bg-transparent text-sm focus-visible:ring-0"
              />
              <Button variant="ghost" size="icon" className="text-slate-500" onClick={onToggleSearch}>
                <X className="h-4 w-4" />
              </Button>
            </div>
          ) : (
            <Button variant="outline" size="sm" className="rounded-full" onClick={onToggleSearch}>
              <Search className="mr-2 h-4 w-4" />
              {t('photos.filters.searchOpen', 'Suche öffnen')}
            </Button>
          )}
          <div className="flex flex-wrap gap-2">
            {filters.map((filter) => (
              <Button
                key={filter.key}
                variant={statusFilter === filter.key ? 'secondary' : 'outline'}
                className="rounded-full"
                onClick={() => onStatusFilterChange(filter.key)}
                size="sm"
              >
                {filter.label}
              </Button>
            ))}
          </div>
        </div>
        <div className="flex items-center gap-2 text-sm text-slate-600">
          <span className="hidden lg:inline">{t('photos.filters.sort', 'Sortierung')}</span>
          <Button
            variant="outline"
            size="sm"
            className="rounded-full"
            onClick={() => onSortOrderChange(sortOrder === 'desc' ? 'asc' : 'desc')}
          >
            {sortOrder === 'desc'
              ? t('photos.filters.sortDesc', 'Neueste zuerst')
              : t('photos.filters.sortAsc', 'Älteste zuerst')}
          </Button>
        </div>
      </div>
      <div className="flex flex-wrap items-center gap-3 text-xs text-slate-500">
        <Filter className="h-4 w-4" />
        <span>{t('photos.filters.count', '{{count}} Uploads', { count: totalCount })}</span>
        {selectionCount > 0 ? (
          <>
            <Badge variant="outline" className="border-slate-200 text-slate-700">
              {t('photos.filters.selected', '{{count}} ausgewählt', { count: selectionCount })}
            </Badge>
            <Button variant="outline" size="sm" onClick={onClearSelection}>
              {t('photos.filters.clearSelection', 'Auswahl aufheben')}
            </Button>
            <div className="flex flex-wrap gap-2">
              <Button size="sm" onClick={onBulkHide} disabled={busy}>
                <EyeOff className="mr-2 h-4 w-4" />
                {t('photos.actions.hide', 'Verstecken')}
              </Button>
              <Button size="sm" onClick={onBulkShow} disabled={busy}>
                <Eye className="mr-2 h-4 w-4" />
                {t('photos.actions.show', 'Einblenden')}
              </Button>
              <Button size="sm" onClick={onBulkFeature} disabled={busy}>
                <Star className="mr-2 h-4 w-4" />
                {t('photos.actions.feature', 'Highlight')}
              </Button>
              <Button size="sm" variant="outline" onClick={onBulkUnfeature} disabled={busy}>
                <Star className="mr-2 h-4 w-4" />
                {t('photos.actions.unfeature', 'Highlight entfernen')}
              </Button>
            </div>
          </>
        ) : (
          <Button variant="ghost" size="sm" onClick={onSelectAll}>
            {t('photos.filters.selectAll', 'Alle auswählen')}
          </Button>
        )}
        <div className="ml-auto flex items-center gap-2">
          <Button
            variant="outline"
            size="sm"
            disabled={page <= 1}
            onClick={() => onPageChange(Math.max(1, page - 1))}
          >
            {t('photos.filters.prev', 'Zurück')}
          </Button>
          <span className="text-slate-600">
            {page} / {pageCount}
          </span>
          <Button
            variant="outline"
            size="sm"
            disabled={page >= pageCount}
            onClick={() => onPageChange(Math.min(pageCount, page + 1))}
          >
            {t('photos.filters.next', 'Weiter')}
          </Button>
        </div>
      </div>
    </div>
  );
}

function PhotoGrid({
  photos,
  selectedIds,
  onToggleSelect,
  onToggleFeature,
  onToggleVisibility,
  onRequestDelete,
  busyId,
}: {
  photos: TenantPhoto[];
  selectedIds: number[];
  onToggleSelect: (id: number) => void;
  onToggleFeature: (photo: TenantPhoto) => void;
  onToggleVisibility: (photo: TenantPhoto, visible: boolean) => void;
  onRequestDelete: (photo: TenantPhoto) => void;
  busyId: number | null;
}) {
  return (
    <div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
      {photos.map((photo) => (
        <PhotoCard
          key={photo.id}
          photo={photo}
          selected={selectedIds.includes(photo.id)}
          onToggleSelect={() => onToggleSelect(photo.id)}
          onToggleFeature={() => onToggleFeature(photo)}
          onToggleVisibility={(visible) => onToggleVisibility(photo, visible)}
          onRequestDelete={() => onRequestDelete(photo)}
          busy={busyId === photo.id}
        />
      ))}
    </div>
  );
}

function PhotoCard({
  photo,
  selected,
  onToggleSelect,
  onToggleFeature,
  onToggleVisibility,
  onRequestDelete,
  busy,
}: {
  photo: TenantPhoto;
  selected: boolean;
  onToggleSelect: () => void;
  onToggleFeature: () => void;
  onToggleVisibility: (visible: boolean) => void;
  onRequestDelete: () => void;
  busy: boolean;
}) {
  const { t } = useTranslation('management');
  const hidden = photo.status === 'hidden';
  const [copied, setCopied] = React.useState(false);

  React.useEffect(() => {
    if (!copied) {
      return;
    }
    const timeout = setTimeout(() => setCopied(false), 2000);
    return () => clearTimeout(timeout);
  }, [copied]);

  return (
    <div className="rounded-2xl border border-slate-200 bg-white/90 p-4 shadow-sm">
      <div className="relative mb-3">
        <button
          type="button"
          className={`absolute left-3 top-3 z-10 rounded-full border border-white bg-white/90 px-3 py-1 text-xs font-semibold transition ${
            selected ? 'text-sky-600' : 'text-slate-500'
          }`}
          onClick={onToggleSelect}
        >
          {selected ? t('photos.gallery.selected', 'Ausgewählt') : t('photos.gallery.select', 'Markieren')}
        </button>
        <img
          src={photo.thumbnail_url ?? photo.url ?? undefined}
          alt={photo.original_name ?? 'Foto'}
          className={`h-56 w-full rounded-2xl object-cover ${hidden ? 'opacity-60' : ''}`}
        />
        {photo.is_featured && (
          <span className="absolute right-3 top-3 rounded-full bg-pink-500/90 px-3 py-1 text-xs font-semibold text-white shadow">
            Highlight
          </span>
        )}
      </div>
      <div className="space-y-2 text-sm text-slate-700">
        <div className="flex items-center justify-between text-xs text-slate-500">
          <span>{t('photos.gallery.likes', 'Likes: {{count}}', { count: photo.likes_count })}</span>
          <span>{t('photos.gallery.uploader', 'Uploader: {{name}}', { name: photo.uploader_name ?? 'Unbekannt' })}</span>
        </div>
        <div className="flex flex-wrap gap-2">
          <Button variant="outline" size="sm" disabled={busy} onClick={() => onToggleVisibility(hidden ? true : false)}>
            {busy ? (
              <Loader2 className="h-4 w-4 animate-spin" />
            ) : hidden ? (
              <>
                <Eye className="h-4 w-4" /> {t('photos.actions.show', 'Einblenden')}
              </>
            ) : (
              <>
                <EyeOff className="h-4 w-4" /> {t('photos.actions.hide', 'Verstecken')}
              </>
            )}
          </Button>
          <Button
            variant={photo.is_featured ? 'secondary' : 'outline'}
            size="sm"
            disabled={busy}
            onClick={onToggleFeature}
          >
            {busy ? (
              <Loader2 className="h-4 w-4 animate-spin" />
            ) : photo.is_featured ? (
              <>
                <Star className="h-4 w-4" /> {t('photos.actions.unfeature', 'Highlight entfernen')}
              </>
            ) : (
              <>
                <Star className="h-4 w-4" /> {t('photos.actions.feature', 'Als Highlight setzen')}
              </>
            )}
          </Button>
          <Button variant="destructive" size="sm" onClick={onRequestDelete} disabled={busy}>
            {busy ? <Loader2 className="h-4 w-4 animate-spin" /> : <Trash2 className="h-4 w-4" />}
            {t('photos.actions.delete', 'Löschen')}
          </Button>
          <Button
            variant="ghost"
            size="sm"
            onClick={async () => {
              if (!photo.url) {
                toast.error(t('photos.actions.copyMissing', 'Kein Link verfügbar'));
                return;
              }
              const successMessage = t('photos.actions.copySuccess', 'Link kopiert');
              try {
                if (!navigator.clipboard || !navigator.clipboard.writeText) {
                  throw new Error('clipboard_unavailable');
                }
                await navigator.clipboard.writeText(photo.url);
                toast.success(successMessage);
                setCopied(true);
              } catch (err) {
                // Fallback for unsichere Kontexte: zeige den Link zum manuellen Kopieren.
                const promptValue = window.prompt(t('photos.actions.copyPrompt', 'Link zum Kopieren'), photo.url);
                if (promptValue !== null) {
                  toast.success(successMessage);
                  setCopied(true);
                } else {
                  toast.error(t('photos.actions.copyFailed', 'Kopieren nicht möglich. Bitte manuell kopieren.'));
                }
              }
            }}
          >
            {copied ? (
              <span className="flex items-center gap-1 text-emerald-600">
                <Check className="h-4 w-4" /> {t('photos.actions.copyDone', 'Kopiert!')}
              </span>
            ) : (
              <>
                <Copy className="h-4 w-4" /> {t('photos.actions.copy', 'Link kopieren')}
              </>
            )}
          </Button>
        </div>
      </div>
    </div>
  );
}

function DeletePhotoDialog({
  open,
  photo,
  onCancel,
  onConfirm,
  skipConfirm,
  onSkipChange,
}: {
  open: boolean;
  photo: TenantPhoto | null;
  onCancel: () => void;
  onConfirm: () => void;
  skipConfirm: boolean;
  onSkipChange: (value: boolean) => void;
}) {
  const { t } = useTranslation('management');

  return (
    <Dialog open={open} onOpenChange={(nextOpen) => { if (!nextOpen) onCancel(); }}>
      <DialogContent>
        <DialogHeader>
          <DialogTitle>{t('photos.deleteDialog.title', 'Foto löschen?')}</DialogTitle>
          <DialogDescription>
            {t('photos.deleteDialog.description', 'Dieses Foto wird dauerhaft entfernt. Diese Aktion kann nicht rückgängig gemacht werden.')}
          </DialogDescription>
        </DialogHeader>
        {photo ? (
          <div className="rounded-lg border border-slate-200 bg-slate-50 p-3 text-sm text-slate-700">
            {photo.original_name ?? t('photos.deleteDialog.fallbackName', 'Unbenanntes Foto')}
          </div>
        ) : null}
        <div className="flex items-center gap-2 rounded-lg bg-slate-50/70 p-3 text-sm">
          <Checkbox
            id="skip-delete-confirm"
            checked={skipConfirm}
            onCheckedChange={(checked) => onSkipChange(Boolean(checked))}
          />
          <Label htmlFor="skip-delete-confirm" className="text-slate-700">
            {t('photos.deleteDialog.skip', 'Nicht erneut in dieser Sitzung nachfragen')}
          </Label>
        </div>
        <DialogFooter>
          <Button variant="outline" onClick={onCancel}>
            {t('photos.actions.cancel', 'Abbrechen')}
          </Button>
          <Button variant="destructive" onClick={onConfirm}>
            {t('photos.actions.delete', 'Löschen')}
          </Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
}
