﻿import React from 'react';
import { Link } from 'react-router-dom';
import AppearanceToggleDropdown from '@/components/appearance-dropdown';
import {
  User,
  Heart,
  Users,
  PartyPopper,
  Camera,
  Bell,
  ArrowUpRight,
  MessageSquare,
  Sparkles,
  LifeBuoy,
  UploadCloud,
  AlertCircle,
  Check,
  X,
  RefreshCw,
} from 'lucide-react';
import { useEventData } from '../hooks/useEventData';
import { useOptionalEventStats } from '../context/EventStatsContext';
import { useOptionalGuestIdentity } from '../context/GuestIdentityContext';
import { SettingsSheet } from './settings-sheet';
import { useTranslation, type TranslateFn } from '../i18n/useTranslation';
import { DEFAULT_EVENT_BRANDING, useOptionalEventBranding } from '../context/EventBrandingContext';
import { useOptionalNotificationCenter, type NotificationCenterValue } from '../context/NotificationCenterContext';
import { useGuestTaskProgress, TASK_BADGE_TARGET } from '../hooks/useGuestTaskProgress';

const EVENT_ICON_COMPONENTS: Record<string, React.ComponentType<{ className?: string }>> = {
  heart: Heart,
  guests: Users,
  party: PartyPopper,
  camera: Camera,
};

const NOTIFICATION_ICON_MAP: Record<string, React.ComponentType<{ className?: string }>> = {
  broadcast: MessageSquare,
  feedback_request: MessageSquare,
  achievement_major: Sparkles,
  support_tip: LifeBuoy,
  upload_alert: UploadCloud,
  photo_activity: Camera,
};

function isLikelyEmoji(value: string): boolean {
  if (!value) {
    return false;
  }
  const characters = Array.from(value.trim());
  if (characters.length === 0 || characters.length > 2) {
    return false;
  }
  return characters.some((char) => {
    const codePoint = char.codePointAt(0) ?? 0;
    return codePoint > 0x2600;
  });
}

function getInitials(name: string): string {
  const words = name.split(' ').filter(Boolean);
  if (words.length >= 2) {
    return `${words[0][0]}${words[1][0]}`.toUpperCase();
  }
  return name.substring(0, 2).toUpperCase();
}

function renderEventAvatar(name: string, icon: unknown, accentColor: string, textColor: string) {
  if (typeof icon === 'string') {
    const trimmed = icon.trim();
    if (trimmed) {
      const normalized = trimmed.toLowerCase();
      const IconComponent = EVENT_ICON_COMPONENTS[normalized];
      if (IconComponent) {
        return (
          <div
            className="flex h-10 w-10 items-center justify-center rounded-full shadow-sm"
            style={{ backgroundColor: accentColor, color: textColor }}
          >
            <IconComponent className="h-5 w-5" aria-hidden />
          </div>
        );
      }

      if (isLikelyEmoji(trimmed)) {
        return (
          <div
            className="flex h-10 w-10 items-center justify-center rounded-full text-xl shadow-sm"
            style={{ backgroundColor: accentColor, color: textColor }}
          >
            <span aria-hidden>{trimmed}</span>
            <span className="sr-only">{name}</span>
          </div>
        );
      }
    }
  }

  return (
    <div
      className="flex h-10 w-10 items-center justify-center rounded-full font-semibold text-sm shadow-sm"
      style={{ backgroundColor: accentColor, color: textColor }}
    >
      {getInitials(name)}
    </div>
  );
}

export default function Header({ eventToken, title = '' }: { eventToken?: string; title?: string }) {
  const statsContext = useOptionalEventStats();
  const identity = useOptionalGuestIdentity();
  const { t } = useTranslation();
  const brandingContext = useOptionalEventBranding();
  const branding = brandingContext?.branding ?? DEFAULT_EVENT_BRANDING;
  const primaryForeground = '#ffffff';
  const { event, status } = useEventData();
  const notificationCenter = useOptionalNotificationCenter();
  const [notificationsOpen, setNotificationsOpen] = React.useState(false);
  const taskProgress = useGuestTaskProgress(eventToken);
  const panelRef = React.useRef<HTMLDivElement | null>(null);
  const checklistItems = React.useMemo(
    () => [
      t('home.checklist.steps.first'),
      t('home.checklist.steps.second'),
      t('home.checklist.steps.third'),
    ],
    [t],
  );

  React.useEffect(() => {
    if (!notificationsOpen) {
      return;
    }
    const handler = (event: MouseEvent) => {
      if (!panelRef.current) return;
      if (panelRef.current.contains(event.target as Node)) return;
      setNotificationsOpen(false);
    };
    document.addEventListener('mousedown', handler);
    return () => document.removeEventListener('mousedown', handler);
  }, [notificationsOpen]);

  if (!eventToken) {
    const guestName = identity?.name && identity?.hydrated ? identity.name : null;
    return (
      <div
        className="sticky top-0 z-20 flex items-center justify-between border-b bg-white/70 px-4 py-2 backdrop-blur dark:bg-black/40"
        style={branding.fontFamily ? { fontFamily: branding.fontFamily } : undefined}
      >
        <div className="flex flex-col">
          <div className="font-semibold">{title}</div>
          {guestName && (
            <span className="text-xs text-muted-foreground">
              {`${t('common.hi')} ${guestName}`}
            </span>
          )}
        </div>
        <div className="flex items-center gap-2">
          <AppearanceToggleDropdown />
          <SettingsSheet />
        </div>
      </div>
    );
  }

  const guestName =
    identity && identity.eventKey === eventToken && identity.hydrated && identity.name ? identity.name : null;

  const headerStyle: React.CSSProperties = {
    background: `linear-gradient(135deg, ${branding.primaryColor}, ${branding.secondaryColor})`,
    color: primaryForeground,
    fontFamily: branding.fontFamily ?? undefined,
  };

  const accentColor = branding.secondaryColor;

  if (status === 'loading') {
    return (
      <div className="sticky top-0 z-20 flex items-center justify-between border-b border-white/10 px-4 py-2 text-white shadow-sm backdrop-blur" style={headerStyle}>
        <div className="font-semibold" style={branding.fontFamily ? { fontFamily: branding.fontFamily } : undefined}>{t('header.loading')}</div>
        <div className="flex items-center gap-2">
          <AppearanceToggleDropdown />
          <SettingsSheet />
        </div>
      </div>
    );
  }

  if (status !== 'ready' || !event) {
    return null;
  }

  const stats =
    statsContext && statsContext.eventKey === eventToken ? statsContext : undefined;
  return (
    <div
      className="sticky top-0 z-20 flex items-center justify-between border-b border-white/10 px-4 py-3 text-white shadow-sm backdrop-blur"
      style={headerStyle}
    >
      <div className="flex items-center gap-3">
        {renderEventAvatar(event.name, event.type?.icon, accentColor, primaryForeground)}
        <div className="flex flex-col" style={branding.fontFamily ? { fontFamily: branding.fontFamily } : undefined}>
          <div className="font-semibold text-base">{event.name}</div>
          {guestName && (
            <span className="text-xs text-white/80">
              {`${t('common.hi')} ${guestName}`}
            </span>
          )}
          <div className="flex items-center gap-2 text-xs text-white/70">
            {stats && (
              <>
                <span className="flex items-center gap-1">
                  <User className="h-3 w-3" />
                  <span>{`${stats.onlineGuests} ${t('header.stats.online')}`}</span>
                </span>
                <span className="text-muted-foreground">|</span>
                <span className="flex items-center gap-1">
                  <span className="font-medium">{stats.tasksSolved}</span>{' '}
                  {t('header.stats.tasksSolved')}
                </span>
              </>
            )}
          </div>
        </div>
      </div>
      <div className="flex items-center gap-2">
        {notificationCenter && (
          <NotificationButton
            eventToken={eventToken}
            center={notificationCenter}
            open={notificationsOpen}
            onToggle={() => setNotificationsOpen((prev) => !prev)}
            panelRef={panelRef}
            checklistItems={checklistItems}
            taskProgress={taskProgress?.hydrated ? taskProgress : undefined}
            t={t}
          />
        )}
        <AppearanceToggleDropdown />
        <SettingsSheet />
      </div>
    </div>
  );
}

type NotificationButtonProps = {
  center: NotificationCenterValue;
  eventToken: string;
  open: boolean;
  onToggle: () => void;
  panelRef: React.RefObject<HTMLDivElement>;
  checklistItems: string[];
  taskProgress?: ReturnType<typeof useGuestTaskProgress>;
  t: TranslateFn;
};

function NotificationButton({ center, eventToken, open, onToggle, panelRef, checklistItems, taskProgress, t }: NotificationButtonProps) {
  const badgeCount = center.totalCount;
  const progressRatio = taskProgress
    ? Math.min(1, taskProgress.completedCount / TASK_BADGE_TARGET)
    : 0;
  const [activeTab, setActiveTab] = React.useState<'unread' | 'all' | 'status'>(center.unreadCount > 0 ? 'unread' : 'all');

  React.useEffect(() => {
    if (!open) {
      setActiveTab(center.unreadCount > 0 ? 'unread' : 'all');
    }
  }, [open, center.unreadCount]);

  const uploadNotifications = React.useMemo(
    () => center.notifications.filter((item) => item.type === 'upload_alert'),
    [center.notifications]
  );
  const unreadNotifications = React.useMemo(
    () => center.notifications.filter((item) => item.status === 'new'),
    [center.notifications]
  );

  const filteredNotifications = React.useMemo(() => {
    switch (activeTab) {
      case 'unread':
        return unreadNotifications;
      case 'status':
        return uploadNotifications;
      default:
        return center.notifications;
    }
  }, [activeTab, center.notifications, unreadNotifications, uploadNotifications]);

  return (
    <div className="relative">
      <button
        type="button"
        onClick={onToggle}
        className="relative rounded-full bg-white/15 p-2 text-white transition hover:bg-white/30"
        aria-label={t('header.notifications.open', 'Benachrichtigungen anzeigen')}
      >
        <Bell className="h-5 w-5" aria-hidden />
        {badgeCount > 0 && (
          <span className="absolute -right-1 -top-1 rounded-full bg-white px-1.5 text-[10px] font-semibold text-pink-600">
            {badgeCount > 9 ? '9+' : badgeCount}
          </span>
        )}
      </button>
      {open && (
        <div
          ref={panelRef}
          className="absolute right-0 mt-2 w-80 rounded-2xl border border-white/30 bg-white/95 p-4 text-slate-900 shadow-2xl"
        >
          <div className="flex items-start justify-between gap-3">
            <div>
              <p className="text-sm font-semibold text-slate-900">{t('header.notifications.title', 'Benachrichtigungen')}</p>
              <p className="text-xs text-slate-500">
                {center.unreadCount > 0
                  ? t('header.notifications.unread', '{{count}} neu', { count: center.unreadCount })
                  : t('header.notifications.allRead', 'Alles gelesen')}
              </p>
            </div>
            <button
              type="button"
              onClick={() => center.refresh()}
              disabled={center.loading}
              className="flex items-center gap-1 rounded-full border border-slate-200 px-2 py-1 text-xs font-semibold text-slate-600 transition hover:border-pink-300 disabled:cursor-not-allowed"
            >
              <RefreshCw className={`h-3.5 w-3.5 ${center.loading ? 'animate-spin' : ''}`} aria-hidden />
              {t('header.notifications.refresh', 'Aktualisieren')}
            </button>
          </div>
          <NotificationTabs
            tabs={[
              { key: 'unread', label: t('header.notifications.tabUnread', 'Neu'), badge: unreadNotifications.length },
              { key: 'status', label: t('header.notifications.tabStatus', 'Uploads/Status'), badge: uploadNotifications.length },
              { key: 'all', label: t('header.notifications.tabAll', 'Alle'), badge: center.notifications.length },
            ]}
            activeTab={activeTab}
            onTabChange={(next) => setActiveTab(next as typeof activeTab)}
          />
          <NotificationStatusBar
            lastFetchedAt={center.lastFetchedAt}
            isOffline={center.isOffline}
            t={t}
          />
          <div className="mt-3 max-h-80 space-y-2 overflow-y-auto pr-1">
            {center.loading ? (
              <NotificationSkeleton />
            ) : filteredNotifications.length === 0 ? (
              <NotificationEmptyState
                t={t}
                message={
                  activeTab === 'unread'
                    ? t('header.notifications.emptyUnread', 'Du bist auf dem neuesten Stand!')
                    : activeTab === 'status'
                      ? t('header.notifications.emptyStatus', 'Keine Upload-Hinweise oder Wartungen aktiv.')
                      : undefined
                }
              />
            ) : (
              filteredNotifications.map((item) => (
                <NotificationListItem
                  key={item.id}
                  item={item}
                  onMarkRead={() => center.markAsRead(item.id)}
                  onDismiss={() => center.dismiss(item.id)}
                  t={t}
                />
              ))
            )}
          </div>
          <div className="mt-4 rounded-2xl border border-slate-200 bg-slate-50/80 p-3">
            <div className="flex items-center justify-between text-sm">
              <span className="text-slate-600">
                {t('header.notifications.queueLabel', 'Uploads in Warteschlange')}
              </span>
              <span className="font-semibold text-slate-900">{center.queueCount}</span>
            </div>
            <Link
              to={`/e/${encodeURIComponent(eventToken)}/queue`}
              className="mt-2 inline-flex items-center gap-1 text-sm font-semibold text-pink-600"
              onClick={() => {
                if (center.unreadCount > 0) {
                  void center.refresh();
                }
              }}
            >
              {t('header.notifications.queueCta', 'Upload-Verlauf öffnen')}
              <ArrowUpRight className="h-4 w-4" aria-hidden />
            </Link>
          </div>
          {taskProgress && (
            <div className="mt-3 rounded-2xl border border-slate-200 bg-slate-50/90 p-3">
              <div className="flex items-center justify-between">
                <div>
                  <p className="text-xs uppercase tracking-[0.3em] text-slate-400">{t('header.notifications.badgeLabel', 'Badge-Fortschritt')}</p>
                  <p className="text-lg font-semibold text-slate-900">
                    {taskProgress.completedCount}/{TASK_BADGE_TARGET}
                  </p>
                </div>
                <Link
                  to={`/e/${encodeURIComponent(eventToken)}/tasks`}
                  className="rounded-full border border-slate-200 px-3 py-1 text-xs font-semibold text-pink-600 transition hover:border-pink-300"
                >
                  {t('header.notifications.tasksCta', 'Weiter')}
                </Link>
              </div>
              <div className="mt-3 h-1.5 w-full rounded-full bg-slate-100">
                <div
                  className="h-full rounded-full bg-pink-500"
                  style={{ width: `${progressRatio * 100}%` }}
                />
              </div>
            </div>
          )}
          <div className="my-3 h-px w-full bg-slate-100" />
          <p className="text-[11px] uppercase tracking-[0.3em] text-slate-400">{t('header.notifications.checklistTitle', 'So funktioniert’s')}</p>
          <ul className="mt-2 space-y-2 text-sm text-slate-600">
            {checklistItems.map((item) => (
              <li key={item} className="flex gap-2">
                <span className="mt-0.5 h-1.5 w-1.5 rounded-full bg-pink-500" />
                <span>{item}</span>
              </li>
            ))}
          </ul>
        </div>
      )}
    </div>
  );
}

function NotificationListItem({
  item,
  onMarkRead,
  onDismiss,
  t,
}: {
  item: NotificationCenterValue['notifications'][number];
  onMarkRead: () => void;
  onDismiss: () => void;
  t: TranslateFn;
}) {
  const IconComponent = NOTIFICATION_ICON_MAP[item.type] ?? Bell;
  const isNew = item.status === 'new';
  const createdLabel = item.createdAt ? formatRelativeTime(item.createdAt) : '';

  return (
    <div
      className={`rounded-2xl border px-3 py-2.5 transition ${isNew ? 'border-pink-200 bg-pink-50/70' : 'border-slate-200 bg-white/90'}`}
      onClick={() => {
        if (isNew) {
          onMarkRead();
        }
      }}
    >
      <div className="flex items-start gap-3">
        <div className={`rounded-full p-1.5 ${isNew ? 'bg-white text-pink-600' : 'bg-slate-100 text-slate-500'}`}>
          <IconComponent className="h-4 w-4" aria-hidden />
        </div>
        <div className="flex-1 space-y-1">
          <div className="flex items-start justify-between gap-2">
            <div>
              <p className="text-sm font-semibold text-slate-900">{item.title}</p>
              {item.body && <p className="text-xs text-slate-600">{item.body}</p>}
            </div>
            <button
              type="button"
              onClick={(event) => {
                event.stopPropagation();
                onDismiss();
              }}
              className="rounded-full p-1 text-slate-400 transition hover:text-slate-700"
              aria-label={t('header.notifications.dismiss', 'Ausblenden')}
            >
              <X className="h-3.5 w-3.5" aria-hidden />
            </button>
          </div>
          <div className="flex items-center gap-2 text-[11px] text-slate-400">
            {createdLabel && <span>{createdLabel}</span>}
            {isNew && (
              <span className="inline-flex items-center gap-1 rounded-full bg-pink-100 px-1.5 py-0.5 text-[10px] font-semibold text-pink-600">
                <Sparkles className="h-3 w-3" aria-hidden />
                {t('header.notifications.badge.new', 'Neu')}
              </span>
            )}
          </div>
          {item.cta && (
            <NotificationCta cta={item.cta} onFollow={onMarkRead} />
          )}
          {!isNew && item.status !== 'dismissed' && (
            <button
              type="button"
              onClick={(event) => {
                event.stopPropagation();
                onMarkRead();
              }}
              className="inline-flex items-center gap-1 text-[11px] font-semibold text-pink-600"
            >
              <Check className="h-3 w-3" aria-hidden />
              {t('header.notifications.markRead', 'Als gelesen markieren')}
            </button>
          )}
        </div>
      </div>
    </div>
  );
}

function NotificationCta({ cta, onFollow }: { cta: { label?: string; href?: string }; onFollow: () => void }) {
  const href = cta.href ?? '#';
  const label = cta.label ?? '';
  const isInternal = /^\//.test(href);
  const content = (
    <span className="inline-flex items-center gap-1">
      {label}
      <ArrowUpRight className="h-3.5 w-3.5" aria-hidden />
    </span>
  );

  if (isInternal) {
    return (
      <Link
        to={href}
        className="inline-flex items-center gap-1 text-sm font-semibold text-pink-600"
        onClick={onFollow}
      >
        {content}
      </Link>
    );
  }

  return (
    <a
      href={cta.href}
      href={href}
      target="_blank"
      rel="noopener noreferrer"
      className="inline-flex items-center gap-1 text-sm font-semibold text-pink-600"
      onClick={onFollow}
    >
      {content}
    </a>
  );
}

function NotificationEmptyState({ t, message }: { t: TranslateFn; message?: string }) {
  return (
    <div className="rounded-2xl border border-dashed border-slate-200 bg-white/70 p-4 text-center text-sm text-slate-500">
      <AlertCircle className="mx-auto mb-2 h-5 w-5 text-slate-400" aria-hidden />
      <p>{message ?? t('header.notifications.empty', 'Gerade gibt es keine neuen Hinweise.')}</p>
    </div>
  );
}

function NotificationSkeleton() {
  return (
    <div className="space-y-2">
      {[0, 1, 2].map((index) => (
        <div key={index} className="animate-pulse rounded-2xl border border-slate-200 bg-slate-100/60 p-3">
          <div className="flex items-center gap-3">
            <div className="h-8 w-8 rounded-full bg-slate-200" />
            <div className="flex-1 space-y-2">
              <div className="h-3 w-3/4 rounded bg-slate-200" />
              <div className="h-3 w-1/2 rounded bg-slate-200" />
            </div>
          </div>
        </div>
      ))}
    </div>
  );
}

function formatRelativeTime(value: string): string {
  const date = new Date(value);
  if (Number.isNaN(date.getTime())) {
    return '';
  }

  const diffMs = Date.now() - date.getTime();
  const diffMinutes = Math.max(0, Math.round(diffMs / 60000));

  if (diffMinutes < 1) {
    return 'Gerade eben';
  }

  if (diffMinutes < 60) {
    return `${diffMinutes} min`;
  }

  const diffHours = Math.round(diffMinutes / 60);
  if (diffHours < 24) {
    return `${diffHours} h`;
  }

  const diffDays = Math.round(diffHours / 24);
  return `${diffDays} d`;
}

function NotificationTabs({
  tabs,
  activeTab,
  onTabChange,
}: {
  tabs: Array<{ key: string; label: string; badge?: number }>;
  activeTab: string;
  onTabChange: (key: string) => void;
}) {
  return (
    <div className="mt-3 flex gap-2 rounded-full bg-slate-100/80 p-1 text-xs font-semibold text-slate-600">
      {tabs.map((tab) => (
        <button
          key={tab.key}
          type="button"
          className={`flex flex-1 items-center justify-center gap-1 rounded-full px-3 py-1 transition ${
            activeTab === tab.key ? 'bg-white text-pink-600 shadow' : 'text-slate-500'
          }`}
          onClick={() => onTabChange(tab.key)}
        >
          {tab.label}
          {typeof tab.badge === 'number' && tab.badge > 0 && (
            <span className="rounded-full bg-pink-100 px-2 text-[11px] text-pink-600">{tab.badge}</span>
          )}
        </button>
      ))}
    </div>
  );
}

function NotificationStatusBar({ lastFetchedAt, isOffline, t }: { lastFetchedAt: Date | null; isOffline: boolean; t: TranslateFn }) {
  const label = lastFetchedAt ? formatRelativeTime(lastFetchedAt.toISOString()) : t('header.notifications.never', 'Noch keine Aktualisierung');

  return (
    <div className="mt-2 flex items-center justify-between text-[11px] text-slate-500">
      <span>
        {t('header.notifications.lastSync', 'Zuletzt aktualisiert')}: {label}
      </span>
      {isOffline && (
        <span className="inline-flex items-center gap-1 rounded-full bg-amber-100 px-2 py-0.5 font-semibold text-amber-700">
          <AlertCircle className="h-3 w-3" aria-hidden />
          {t('header.notifications.offline', 'Offline')}
        </span>
      )}
    </div>
  );
}
