import React, { useEffect, useMemo, useState } from 'react';
import { Link, useNavigationType, useParams } from 'react-router-dom';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import { cn } from '@/lib/utils';
import { Button } from '@/components/ui/button';
import { Skeleton } from '@/components/ui/skeleton';
import { Alert, AlertDescription } from '@/components/ui/alert';
import { Separator } from '@/components/ui/separator';
import { AnimatePresence, motion } from 'framer-motion';
import {
  AchievementBadge,
  AchievementsPayload,
  FeedEntry,
  LeaderboardEntry,
  TimelinePoint,
  TopPhotoHighlight,
  TrendingEmotionHighlight,
  fetchAchievements,
} from '../services/achievementApi';
import { useGuestIdentity } from '../context/GuestIdentityContext';
import { Sparkles, Award, Trophy, Camera, Users, BarChart2, Flame } from 'lucide-react';
import { useTranslation, type TranslateFn } from '../i18n/useTranslation';
import type { LocaleCode } from '../i18n/messages';
import { localizeTaskLabel } from '../lib/localizeTaskLabel';
import { useEventData } from '../hooks/useEventData';
import { isTaskModeEnabled } from '../lib/engagement';
import { FADE_SCALE, FADE_UP, STAGGER_FAST, getMotionContainerPropsForNavigation, getMotionItemProps, prefersReducedMotion } from '../lib/motion';
import PullToRefresh from '../components/PullToRefresh';

const GENERIC_ERROR = 'GENERIC_ERROR';

function formatRelativeTimestamp(input: string, formatter: Intl.RelativeTimeFormat): string {
  const date = new Date(input);
  if (Number.isNaN(date.getTime())) return '';
  const diff = date.getTime() - Date.now();
  const minute = 60_000;
  const hour = 60 * minute;
  const day = 24 * hour;
  const abs = Math.abs(diff);
  if (abs < minute) return formatter.format(0, 'second');
  if (abs < hour) return formatter.format(Math.round(diff / minute), 'minute');
  if (abs < day) return formatter.format(Math.round(diff / hour), 'hour');
  return formatter.format(Math.round(diff / day), 'day');
}

type LeaderboardProps = {
  title: string;
  description: string;
  icon: React.ElementType;
  entries: LeaderboardEntry[];
  emptyCopy: string;
  formatNumber: (value: number) => string;
  t: TranslateFn;
};

function Leaderboard({ title, description, icon: Icon, entries, emptyCopy, formatNumber, t }: LeaderboardProps) {
  return (
    <Card>
      <CardHeader className="flex flex-row items-center gap-2 pb-4">
        <div className="flex h-10 w-10 items-center justify-center rounded-full bg-pink-500/10 text-pink-500">
          <Icon className="h-5 w-5" />
        </div>
        <div>
          <CardTitle className="text-base font-semibold">{title}</CardTitle>
          <CardDescription className="text-xs">{description}</CardDescription>
        </div>
      </CardHeader>
      <CardContent className="space-y-2">
        {entries.length === 0 ? (
          <p className="text-sm text-muted-foreground">{emptyCopy}</p>
        ) : (
          <ol className="space-y-2 text-sm">
            {entries.map((entry, index) => (
              <li key={`${entry.guest}-${index}`} className="flex items-center justify-between rounded-lg border border-border/50 bg-muted/30 px-3 py-2">
                <div className="flex items-center gap-3">
                  <span className="text-xs font-semibold text-muted-foreground">#{index + 1}</span>
                  <span className="font-medium text-foreground">{entry.guest || t('achievements.leaderboard.guestFallback')}</span>
                </div>
                <div className="flex items-center gap-4 text-xs text-muted-foreground">
                  <span>{t('achievements.leaderboard.item.photos', { count: formatNumber(entry.photos) })}</span>
                  <span>{t('achievements.leaderboard.item.likes', { count: formatNumber(entry.likes) })}</span>
                </div>
              </li>
            ))}
          </ol>
        )}
      </CardContent>
    </Card>
  );
}

type BadgesGridProps = {
  badges: AchievementBadge[];
  t: TranslateFn;
};

export function BadgesGrid({ badges, t }: BadgesGridProps) {
  if (badges.length === 0) {
    return (
      <Card>
        <CardHeader>
          <CardTitle>{t('achievements.badges.title')}</CardTitle>
          <CardDescription>{t('achievements.badges.description')}</CardDescription>
        </CardHeader>
        <CardContent>
          <p className="text-sm text-muted-foreground">{t('achievements.badges.empty')}</p>
        </CardContent>
      </Card>
    );
  }

  return (
    <Card>
      <CardHeader>
        <CardTitle>{t('achievements.badges.title')}</CardTitle>
        <CardDescription>{t('achievements.badges.description')}</CardDescription>
      </CardHeader>
      <CardContent className="grid grid-cols-2 gap-3 sm:grid-cols-3">
        {badges.map((badge) => {
          const target = badge.target ?? 0;
          const progress = badge.progress ?? 0;
          const ratio = target > 0 ? Math.min(1, progress / target) : 0;
          const percentage = Math.round((badge.earned ? 1 : ratio) * 100);
          return (
            <div
              key={badge.id}
              data-testid={`badge-card-${badge.id}`}
              className={cn(
                'relative overflow-hidden rounded-2xl border px-4 py-3 shadow-sm transition',
                badge.earned
                  ? 'border-emerald-400/40 bg-gradient-to-br from-emerald-500/20 via-emerald-500/5 to-white text-emerald-900 dark:border-emerald-400/30 dark:from-emerald-400/20 dark:via-emerald-400/10 dark:to-slate-950/70 dark:text-emerald-50'
                  : 'border-border/60 bg-white/80 dark:border-slate-800/70 dark:bg-slate-950/60',
              )}
            >
              <div className="flex items-start justify-between gap-2">
                <div>
                  <p className="text-sm font-semibold text-foreground">{badge.title}</p>
                  <p className="text-xs text-muted-foreground">{badge.description}</p>
                </div>
                <span className="text-xs font-semibold text-muted-foreground">{percentage}%</span>
              </div>
              <div className="mt-3 h-2 rounded-full bg-muted">
                <div className="h-2 rounded-full bg-gradient-to-r from-pink-500 to-purple-500" style={{ width: `${percentage}%` }} />
              </div>
            </div>
          );
        })}
      </CardContent>
    </Card>
  );
}

type TimelineProps = {
  points: TimelinePoint[];
  t: TranslateFn;
  formatNumber: (value: number) => string;
};

function Timeline({ points, t, formatNumber }: TimelineProps) {
  return (
    <Card>
      <CardHeader>
        <CardTitle>{t('achievements.timeline.title')}</CardTitle>
        <CardDescription>{t('achievements.timeline.description')}</CardDescription>
      </CardHeader>
      <CardContent className="space-y-2 text-sm">
        {points.map((point) => (
          <div key={point.date} className="flex items-center justify-between rounded-lg border border-border/40 bg-muted/20 px-3 py-2">
            <span className="font-medium text-foreground">{point.date}</span>
            <span className="text-muted-foreground">
              {t('achievements.timeline.row', { photos: formatNumber(point.photos), guests: formatNumber(point.guests) })}
            </span>
          </div>
        ))}
      </CardContent>
    </Card>
  );
}

type FeedProps = {
  feed: FeedEntry[];
  t: TranslateFn;
  formatRelativeTime: (value: string) => string;
  locale: LocaleCode;
  formatNumber: (value: number) => string;
};

function Feed({ feed, t, formatRelativeTime, locale, formatNumber }: FeedProps) {
  if (feed.length === 0) {
    return (
      <Card>
        <CardHeader>
          <CardTitle>{t('achievements.feed.title')}</CardTitle>
          <CardDescription>{t('achievements.feed.description')}</CardDescription>
        </CardHeader>
        <CardContent>
          <p className="text-sm text-muted-foreground">{t('achievements.feed.empty')}</p>
        </CardContent>
      </Card>
    );
  }

  return (
    <Card>
      <CardHeader>
        <CardTitle>{t('achievements.feed.title')}</CardTitle>
        <CardDescription>{t('achievements.feed.description')}</CardDescription>
      </CardHeader>
      <CardContent className="space-y-3">
        {feed.map((item) => {
          const taskLabel = localizeTaskLabel(item.task ?? null, locale);
          return (
            <div key={item.photoId} className="flex items-center gap-3 rounded-lg border border-border/40 bg-muted/20 p-3">
              {item.thumbnail ? (
                <img src={item.thumbnail} alt={t('achievements.feed.thumbnailAlt')} className="h-16 w-16 rounded-md object-cover" />
              ) : (
                <div className="flex h-16 w-16 items-center justify-center rounded-md bg-muted text-muted-foreground">
                  <Camera className="h-6 w-6" aria-hidden />
                </div>
              )}
              <div className="flex-1 text-sm">
                <p className="font-semibold text-foreground">{item.guest || t('achievements.leaderboard.guestFallback')}</p>
                {taskLabel && <p className="text-xs text-muted-foreground">{t('achievements.feed.taskLabel', { task: taskLabel })}</p>}
                <div className="mt-1 flex items-center gap-4 text-xs text-muted-foreground">
                  <span>{formatRelativeTime(item.createdAt)}</span>
                  <span>{t('achievements.feed.likesLabel', { count: formatNumber(item.likes) })}</span>
                </div>
              </div>
            </div>
          );
        })}
      </CardContent>
    </Card>
  );
}

type HighlightsProps = {
  topPhoto: TopPhotoHighlight | null;
  trendingEmotion: TrendingEmotionHighlight | null;
  t: TranslateFn;
  formatRelativeTime: (value: string) => string;
  locale: LocaleCode;
  formatNumber: (value: number) => string;
};

function Highlights({ topPhoto, trendingEmotion, t, formatRelativeTime, locale, formatNumber }: HighlightsProps) {
  if (!topPhoto && !trendingEmotion) {
    return null;
  }

  const renderTopPhoto = () => {
    if (!topPhoto) return null;
    const localizedTask = localizeTaskLabel(topPhoto.task ?? null, locale);
    return (
      <Card>
          <CardHeader className="flex flex-row items-center justify-between">
            <div>
              <CardTitle>{t('achievements.highlights.topTitle')}</CardTitle>
              <CardDescription>{t('achievements.highlights.topDescription')}</CardDescription>
            </div>
            <Trophy className="h-6 w-6 text-amber-400" aria-hidden />
          </CardHeader>
          <CardContent className="space-y-2 text-sm">
            <div className="overflow-hidden rounded-xl border border-border/40">
              {topPhoto.thumbnail ? (
                <img src={topPhoto.thumbnail} alt={t('achievements.highlights.topTitle')} className="h-48 w-full object-cover" />
              ) : (
                <div className="flex h-48 w-full items-center justify-center bg-muted text-muted-foreground">
                  {t('achievements.highlights.noPreview')}
                </div>
              )}
            </div>
            <p>
              <span className="font-semibold text-foreground">{topPhoto.guest || t('achievements.leaderboard.guestFallback')}</span>
              {` – ${t('achievements.highlights.likesAmount', { count: formatNumber(topPhoto.likes) })}`}
            </p>
            {localizedTask && (
              <p className="text-muted-foreground">
                {t('achievements.highlights.taskLabel', { task: localizedTask })}
              </p>
            )}
            <p className="text-xs text-muted-foreground">{formatRelativeTime(topPhoto.createdAt)}</p>
          </CardContent>
        </Card>
    );
  };

  const renderTrendingEmotion = () => {
    if (!trendingEmotion) return null;
    return (
      <Card>
          <CardHeader className="flex flex-row items-center justify-between">
            <div>
              <CardTitle>{t('achievements.highlights.trendingTitle')}</CardTitle>
              <CardDescription>{t('achievements.highlights.trendingDescription')}</CardDescription>
            </div>
            <Flame className="h-6 w-6 text-pink-500" aria-hidden />
          </CardHeader>
          <CardContent>
            <p className="text-lg font-semibold text-foreground">{trendingEmotion.name}</p>
            <p className="text-sm text-muted-foreground">
              {t('achievements.highlights.trendingCount', { count: formatNumber(trendingEmotion.count) })}
            </p>
          </CardContent>
        </Card>
    );
  };

  return (
    <div className="grid gap-4 md:grid-cols-2">
      {renderTopPhoto()}
      {renderTrendingEmotion()}
    </div>
  );
}

type PersonalActionsProps = {
  token: string;
  t: TranslateFn;
  tasksEnabled: boolean;
};

function PersonalActions({ token, t, tasksEnabled }: PersonalActionsProps) {
  return (
    <div className="flex flex-wrap gap-3">
      <Button asChild>
        <Link to={`/e/${encodeURIComponent(token)}/upload`} className="flex items-center gap-2">
          <Camera className="h-4 w-4" aria-hidden />
          {t('achievements.personal.actions.upload')}
        </Link>
      </Button>
      {tasksEnabled ? (
        <Button variant="outline" asChild>
          <Link to={`/e/${encodeURIComponent(token)}/tasks`} className="flex items-center gap-2">
            <Sparkles className="h-4 w-4" aria-hidden />
            {t('achievements.personal.actions.tasks')}
          </Link>
        </Button>
      ) : null}
    </div>
  );
}

export default function AchievementsPage() {
  const { token } = useParams<{ token: string }>();
  const navigationType = useNavigationType();
  const identity = useGuestIdentity();
  const { t, locale } = useTranslation();
  const { event } = useEventData();
  const tasksEnabled = isTaskModeEnabled(event);
  const [data, setData] = useState<AchievementsPayload | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
  const [activeTab, setActiveTab] = useState<'personal' | 'event' | 'feed'>('personal');

  const numberFormatter = useMemo(() => new Intl.NumberFormat(locale), [locale]);
  const formatNumber = (value: number) => numberFormatter.format(value);
  const relativeFormatter = useMemo(() => new Intl.RelativeTimeFormat(locale, { numeric: 'auto' }), [locale]);
  const formatRelative = (value: string) => formatRelativeTimestamp(value, relativeFormatter);

  const personalName = identity.hydrated && identity.name ? identity.name : undefined;

  const loadAchievements = React.useCallback(async (signal?: AbortSignal) => {
    if (!token) return;
    setLoading(true);
    setError(null);

    try {
      const payload = await fetchAchievements(token, {
        guestName: personalName,
        locale,
        signal,
      });
      setData(payload);
      if (!payload.personal) {
        setActiveTab('event');
      }
    } catch (err) {
      if (err instanceof DOMException && err.name === 'AbortError') return;
      console.error('Failed to load achievements', err);
      setError(err instanceof Error ? err.message : GENERIC_ERROR);
    } finally {
      if (!signal?.aborted) {
        setLoading(false);
      }
    }
  }, [locale, personalName, token]);

  useEffect(() => {
    const controller = new AbortController();
    void loadAchievements(controller.signal);
    return () => controller.abort();
  }, [loadAchievements]);

  const hasPersonal = Boolean(data?.personal);
  const motionEnabled = !prefersReducedMotion();
  const containerMotion = getMotionContainerPropsForNavigation(motionEnabled, STAGGER_FAST, navigationType);
  const fadeUpMotion = getMotionItemProps(motionEnabled, FADE_UP);
  const fadeScaleMotion = getMotionItemProps(motionEnabled, FADE_SCALE);
  const tabMotion = motionEnabled
    ? { variants: FADE_UP, initial: 'hidden', animate: 'show', exit: 'hidden' as const }
    : {};
  const handleRefresh = React.useCallback(async () => {
    await loadAchievements();
  }, [loadAchievements]);

  if (!token) {
    return null;
  }

  const tabContent = (
    <>
      {activeTab === 'personal' && hasPersonal && data?.personal && (
        <div className="space-y-5">
          <Card>
            <CardHeader className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
              <div>
                <CardTitle className="text-lg font-semibold">
                  {t('achievements.personal.greeting', { name: data.personal.guestName || identity.name || t('achievements.leaderboard.guestFallback') })}
                </CardTitle>
                <CardDescription>
                  {t('achievements.personal.stats', {
                    photos: formatNumber(data.personal.photos),
                    tasks: formatNumber(data.personal.tasks),
                    likes: formatNumber(data.personal.likes),
                  })}
                </CardDescription>
              </div>
              <PersonalActions token={token} t={t} tasksEnabled={tasksEnabled} />
            </CardHeader>
          </Card>

          <BadgesGrid badges={data.personal.badges} t={t} />
        </div>
      )}

      {activeTab === 'event' && data && (
        <div className="space-y-5">
          <Highlights
            topPhoto={data.highlights.topPhoto}
            trendingEmotion={data.highlights.trendingEmotion}
            t={t}
            formatRelativeTime={formatRelative}
            locale={locale}
            formatNumber={formatNumber}
          />
          <Timeline points={data.highlights.timeline} t={t} formatNumber={formatNumber} />
          <div className="grid gap-4 lg:grid-cols-2">
            <Leaderboard
              title={t('achievements.leaderboard.uploadsTitle')}
              description={t('achievements.leaderboard.description')}
              icon={Users}
              entries={data.leaderboards.uploads}
              emptyCopy={t('achievements.leaderboard.uploadsEmpty')}
              t={t}
              formatNumber={formatNumber}
            />
            <Leaderboard
              title={t('achievements.leaderboard.likesTitle')}
              description={t('achievements.leaderboard.description')}
              icon={Trophy}
              entries={data.leaderboards.likes}
              emptyCopy={t('achievements.leaderboard.likesEmpty')}
              t={t}
              formatNumber={formatNumber}
            />
          </div>
        </div>
      )}

      {activeTab === 'feed' && data && (
        <Feed
          feed={data.feed}
          t={t}
          formatRelativeTime={formatRelative}
          locale={locale}
          formatNumber={formatNumber}
        />
      )}
    </>
  );

  return (
    <PullToRefresh
      onRefresh={handleRefresh}
      pullLabel={t('common.pullToRefresh')}
      releaseLabel={t('common.releaseToRefresh')}
      refreshingLabel={t('common.refreshing')}
    >
      <motion.div className="space-y-6 pb-24" {...containerMotion}>
        <motion.div className="space-y-2" {...fadeUpMotion}>
          <div className="flex items-center gap-3">
            <div className="flex h-10 w-10 items-center justify-center rounded-full bg-pink-500/10 text-pink-500">
              <Award className="h-5 w-5" aria-hidden />
            </div>
            <div>
              <h1 className="text-2xl font-semibold text-foreground">{t('achievements.page.title')}</h1>
              <p className="text-sm text-muted-foreground">{t('achievements.page.subtitle')}</p>
            </div>
          </div>
        </motion.div>

        {loading && (
          <motion.div className="space-y-4" {...fadeUpMotion}>
            <Skeleton className="h-24 w-full" />
            <Skeleton className="h-32 w-full" />
            <Skeleton className="h-48 w-full" />
          </motion.div>
        )}

        {!loading && error && (
          <motion.div {...fadeUpMotion}>
            <Alert variant="destructive">
              <AlertDescription className="flex items-center justify-between gap-3">
                <span>{error === GENERIC_ERROR ? t('achievements.page.loadError') : error}</span>
                <Button variant="outline" size="sm" onClick={() => setActiveTab(hasPersonal ? 'personal' : 'event')}>
                  {t('achievements.page.retry')}
                </Button>
              </AlertDescription>
            </Alert>
          </motion.div>
        )}

        {!loading && !error && data && (
          <>
            <motion.div className="flex flex-wrap items-center gap-2" {...fadeUpMotion}>
              <Button
                variant={activeTab === 'personal' ? 'default' : 'outline'}
                onClick={() => setActiveTab('personal')}
                disabled={!hasPersonal}
                className="flex items-center gap-2"
              >
                <Sparkles className="h-4 w-4" aria-hidden />
                {t('achievements.page.buttons.personal')}
              </Button>
              <Button
                variant={activeTab === 'event' ? 'default' : 'outline'}
                onClick={() => setActiveTab('event')}
                className="flex items-center gap-2"
              >
                <Users className="h-4 w-4" aria-hidden />
                {t('achievements.page.buttons.event')}
              </Button>
              <Button
                variant={activeTab === 'feed' ? 'default' : 'outline'}
                onClick={() => setActiveTab('feed')}
                className="flex items-center gap-2"
              >
                <BarChart2 className="h-4 w-4" aria-hidden />
                {t('achievements.page.buttons.feed')}
              </Button>
            </motion.div>

            <motion.div {...fadeUpMotion}>
              <Separator />
            </motion.div>

            {motionEnabled ? (
              <AnimatePresence mode="wait" initial={false}>
                <motion.div key={activeTab} {...tabMotion}>
                  {tabContent}
                </motion.div>
              </AnimatePresence>
            ) : (
              <motion.div {...fadeScaleMotion}>{tabContent}</motion.div>
            )}
          </>
        )}
      </motion.div>
    </PullToRefresh>
  );
}
