'use client';

import { useState, useEffect } from 'react';
import Link from 'next/link';
import Image from 'next/image';
import {
  Film,
  CheckCircle2,
  XCircle,
  AlertCircle,
  Clock,
  ChevronRight,
  ChevronDown,
  Package,
  RotateCcw,
  ArrowUpDown,
  Copy,
  Check,
  Search,
  X,
} from 'lucide-react';
import { cn } from '@/lib/utils';
import { Montserrat } from 'next/font/google';
import { ReviewPasswordGate } from '@/components/clients/ReviewPasswordGate';

const montserrat = Montserrat({
  subsets: ['latin'],
  weight: ['200', '500', '600'],
});

interface ClientVersion {
  id: string;
  versionNumber: number;
  approvalStatus: string;
  fps: number;
  duration: number | null;
  thumbnailUrl: string | null;
  notes: string | null;
  createdAt: string;
}

interface ClientTask {
  id: string;
  title: string;
  type: string;
  status: string;
  versions: ClientVersion[];
}

interface ClientShot {
  id: string;
  shotCode: string;
  episode: string | null;
  sequence: string | null;
  description: string | null;
  status: string;
  thumbnailUrl: string | null;
  tasks: ClientTask[];
}

interface AssetTask extends ClientTask {
  asset?: { id: string; assetCode: string; name: string } | null;
}

interface FlatItem {
  task: ClientTask | AssetTask;
  label: string;
  description: string | null;
  thumbnailUrl: string | null;
  episodeKey: string;
}

function formatDate(dateStr: string): string {
  return new Date(dateStr).toLocaleDateString('en-AU', {
    day: 'numeric',
    month: 'short',
    year: 'numeric',
  });
}

interface Project {
  id: string;
  name: string;
  code: string;
  description: string | null;
  status: string;
}

const APPROVAL_STYLES: Record<
  string,
  { label: string; className: string; Icon: React.ElementType }
> = {
  PENDING_REVIEW: {
    label: 'Awaiting Review',
    className: 'bg-amber-500/10 text-amber-400 border-amber-500/20',
    Icon: Clock,
  },
  APPROVED: {
    label: 'Approved',
    className: 'bg-emerald-500/10 text-emerald-400 border-emerald-500/20',
    Icon: CheckCircle2,
  },
  REJECTED: {
    label: 'Rejected',
    className: 'bg-red-500/10 text-red-400 border-red-500/20',
    Icon: XCircle,
  },
  NEEDS_CHANGES: {
    label: 'Needs Changes',
    className: 'bg-orange-500/10 text-orange-400 border-orange-500/20',
    Icon: AlertCircle,
  },
};

const TASK_TYPE_LABELS: Record<string, string> = {
  TRACK: 'Tracking',
  ROTO: 'Roto',
  KEY: 'Keying',
  COMP: 'Comp',
  FX: 'FX',
  LIGHTING: 'Lighting',
  RENDER: 'Render',
  ANIMATION: 'Animation',
  MODEL: 'Model',
  TEXTURE: 'Texture',
  RIG: 'Rig',
  LOOKDEV: 'Lookdev',
  GENERAL: 'Task',
};

const SCROLL_KEY = 'client-portal-scroll';
const QUEUE_KEY = 'client-portal-queue';
const STATE_KEY = 'client-portal-state';
const PREFS_KEY_PREFIX = 'client-portal-prefs-';

function getLatestVersion(task: ClientTask): ClientVersion | undefined {
  return task.versions[0];
}

export default function ClientPortalPage({
  params,
}: {
  params: Promise<{ token: string }>;
}) {
  const [token, setToken] = useState<string>('');
  const [project, setProject] = useState<Project | null>(null);
  const [shots, setShots] = useState<ClientShot[]>([]);
  const [assetTasks, setAssetTasks] = useState<AssetTask[]>([]);
  const [sessionLabel, setSessionLabel] = useState<string>('');
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
  const [requiresPassword, setRequiresPassword] = useState(false);
  const [collapsedEpisodes, setCollapsedEpisodes] = useState<Set<string>>(new Set());
  const [statusFilter, setStatusFilter] = useState<string | null>(null);
  const [sortMode, setSortMode] = useState<'episode' | 'recent'>('episode');
  const [searchQuery, setSearchQuery] = useState<string>('');
  const [episodeFilter, setEpisodeFilter] = useState<string | null>(null);

  const toggleEpisode = (ep: string) => {
    setCollapsedEpisodes((prev) => {
      const next = new Set(prev);
      if (next.has(ep)) next.delete(ep); else next.add(ep);
      return next;
    });
  };

  const toggleStatusFilter = (filter: string) => {
    setStatusFilter((prev) => (prev === filter ? null : filter));
  };

  const [copiedId, setCopiedId] = useState<string | null>(null);

  const copyToClipboard = (text: string, id: string) => {
    navigator.clipboard.writeText(text).then(() => {
      setCopiedId(id);
      setTimeout(() => setCopiedId(null), 1500);
    });
  };

  useEffect(() => {
    params.then(({ token: t }) => {
      setToken(t);
      loadProject(t);
    });
  }, [params]);

  useEffect(() => {
    if (!loading && token) {
      const savedState = sessionStorage.getItem(STATE_KEY);
      if (savedState) {
        sessionStorage.removeItem(STATE_KEY);
        try {
          const { statusFilter: sf, sortMode: sm, searchQuery: sq, episodeFilter: ef, collapsedEpisodes: ce } = JSON.parse(savedState);
          if (sf !== undefined) setStatusFilter(sf);
          if (sm !== undefined) setSortMode(sm);
          if (sq !== undefined) setSearchQuery(sq ?? '');
          if (ef !== undefined) setEpisodeFilter(ef);
          if (ce !== undefined) setCollapsedEpisodes(new Set(ce));
        } catch { /* ignore */ }
      } else {
        try {
          const prefs = localStorage.getItem(PREFS_KEY_PREFIX + token);
          if (prefs) {
            const { statusFilter: sf, sortMode: sm, searchQuery: sq, episodeFilter: ef, collapsedEpisodes: ce } = JSON.parse(prefs);
            if (sf !== undefined) setStatusFilter(sf);
            if (sm !== undefined) setSortMode(sm);
            if (sq !== undefined) setSearchQuery(sq ?? '');
            if (ef !== undefined) setEpisodeFilter(ef);
            if (ce !== undefined) setCollapsedEpisodes(new Set(ce));
          }
        } catch { /* ignore */ }
      }
      const saved = sessionStorage.getItem(SCROLL_KEY);
      if (saved) {
        sessionStorage.removeItem(SCROLL_KEY);
        requestAnimationFrame(() => {
          window.scrollTo(0, parseInt(saved, 10));
        });
      }
    }
  }, [loading, token]);

  useEffect(() => {
    if (!token || loading) return;
    try {
      localStorage.setItem(
        PREFS_KEY_PREFIX + token,
        JSON.stringify({
          statusFilter,
          sortMode,
          searchQuery,
          episodeFilter,
          collapsedEpisodes: Array.from(collapsedEpisodes),
        }),
      );
    } catch { /* ignore */ }
  }, [token, statusFilter, sortMode, searchQuery, episodeFilter, collapsedEpisodes, loading]);

  const loadProject = (t: string) => {
    setLoading(true);
    setError(null);
    fetch(`/api/client/${t}/project`)
      .then(async (r) => {
        if (r.status === 401) {
          const data = await r.json().catch(() => ({}));
          if (data.requiresPassword) {
            setRequiresPassword(true);
            return null;
          }
        }
        if (!r.ok) throw new Error('Invalid or expired review link');
        return r.json();
      })
      .then((data) => {
        if (!data) return;
        setProject(data.project);
        setShots(data.shots ?? []);
        setAssetTasks(data.assetTasks ?? []);
        setSessionLabel(data.sessionLabel ?? '');
        setRequiresPassword(false);
      })
      .catch((e) => setError(e.message))
      .finally(() => setLoading(false));
  };

  if (loading) {
    return (
      <div className="min-h-screen bg-zinc-950 flex items-center justify-center">
        <div className="h-8 w-8 border-2 border-amber-500 border-t-transparent rounded-full animate-spin" />
      </div>
    );
  }

  if (requiresPassword) {
    return (
      <ReviewPasswordGate
        token={token}
        onUnlocked={() => loadProject(token)}
      />
    );
  }

  if (error || !project) {
    return (
      <div className="min-h-screen bg-zinc-950 flex flex-col items-center justify-center gap-4 text-center px-4">
        <div className="w-12 h-12 rounded-xl bg-amber-500 flex items-center justify-center">
          <Film className="h-6 w-6 text-black" />
        </div>
        <h1 className="text-xl font-semibold text-white">
          Review link unavailable
        </h1>
        <p className="text-zinc-400 text-sm max-w-sm">
          {error ??
            'This review link has expired or is no longer active. Please request a new link from your studio contact.'}
        </p>
      </div>
    );
  }

  const allTasks = [...shots.flatMap((s) => s.tasks), ...assetTasks];
  const totalTasks = allTasks.length;
  const approved = allTasks.filter(
    (t) => getLatestVersion(t)?.approvalStatus === 'APPROVED',
  ).length;
  const needsChanges = allTasks.filter((t) =>
    ['REJECTED', 'NEEDS_CHANGES'].includes(
      getLatestVersion(t)?.approvalStatus ?? '',
    ),
  ).length;
  const pending = totalTasks - approved - needsChanges;

  // Group shots by episode; null episode → "Shots"
  const isEpisodic = shots.some((s) => s.episode != null);
  const shotsByEpisode = shots.reduce<Record<string, ClientShot[]>>(
    (acc, shot) => {
      const key = shot.episode ?? 'Shots';
      if (!acc[key]) acc[key] = [];
      acc[key].push(shot);
      return acc;
    },
    {},
  );

  const taskMatchesFilter = (t: ClientTask | AssetTask): boolean => {
    if (!statusFilter) return true;
    const status = getLatestVersion(t)?.approvalStatus;
    if (statusFilter === 'NEEDS_CHANGES') {
      return ['REJECTED', 'NEEDS_CHANGES'].includes(status ?? '');
    }
    if (statusFilter === 'PENDING_REVIEW') {
      return !status || status === 'PENDING_REVIEW';
    }
    return status === statusFilter;
  };

  const shotMatchesSearch = (shot: ClientShot): boolean => {
    if (!searchQuery.trim()) return true;
    const q = searchQuery.toLowerCase().trim();
    return (
      shot.shotCode.toLowerCase().includes(q) ||
      (shot.description?.toLowerCase().includes(q) ?? false) ||
      shot.tasks.some((t) => t.title.toLowerCase().includes(q))
    );
  };

  const assetTaskMatchesSearch = (task: AssetTask): boolean => {
    if (!searchQuery.trim()) return true;
    const q = searchQuery.toLowerCase().trim();
    return (
      (task.asset?.assetCode?.toLowerCase().includes(q) ?? false) ||
      task.title.toLowerCase().includes(q)
    );
  };

  const episodeKeys = Object.keys(shotsByEpisode);
  const showEpisodeFilters =
    episodeKeys.length > 1 || (episodeKeys.length >= 1 && assetTasks.length > 0);

  const filteredAssetTasks = assetTasks
    .filter(taskMatchesFilter)
    .filter(assetTaskMatchesSearch)
    .filter(() => episodeFilter === null || episodeFilter === '__assets__');

  const allFlatItems: FlatItem[] = [
    ...shots.flatMap((shot) =>
      shot.tasks.map((task) => ({
        task,
        label: shot.shotCode,
        description: shot.description,
        thumbnailUrl: shot.thumbnailUrl,
        episodeKey: shot.episode ?? 'Shots',
      })),
    ),
    ...assetTasks.map((task) => ({
      task,
      label: task.asset?.assetCode ?? TASK_TYPE_LABELS[task.type] ?? task.type,
      description: null,
      thumbnailUrl: null,
      episodeKey: '__assets__',
    })),
  ];

  const filteredFlatItems = allFlatItems
    .filter((item) => taskMatchesFilter(item.task))
    .filter((item) => episodeFilter === null || item.episodeKey === episodeFilter)
    .filter((item) => {
      if (!searchQuery.trim()) return true;
      const q = searchQuery.toLowerCase().trim();
      return (
        item.label.toLowerCase().includes(q) ||
        (item.description?.toLowerCase().includes(q) ?? false) ||
        item.task.title.toLowerCase().includes(q)
      );
    })
    .sort((a, b) => {
      const aDate = getLatestVersion(a.task)?.createdAt ?? '';
      const bDate = getLatestVersion(b.task)?.createdAt ?? '';
      return bDate.localeCompare(aDate);
    });

  const getReviewQueue = (): Array<{ versionId: string; label: string }> => {
    if (sortMode === 'recent') {
      return filteredFlatItems
        .map((item) => {
          const ver = getLatestVersion(item.task);
          return ver ? { versionId: ver.id, label: item.label } : null;
        })
        .filter((x): x is { versionId: string; label: string } => x !== null);
    }
    const queue: Array<{ versionId: string; label: string }> = [];
    Object.entries(shotsByEpisode)
      .filter(([episode]) => episodeFilter === null || episodeFilter === episode)
      .forEach(([, epShots]) => {
      epShots
        .map((shot) => ({ ...shot, tasks: shot.tasks.filter(taskMatchesFilter) }))
        .filter((shot) => shot.tasks.length > 0)
        .filter(shotMatchesSearch)
        .forEach((shot) => {
          shot.tasks.forEach((task) => {
            const ver = getLatestVersion(task);
            if (ver) queue.push({ versionId: ver.id, label: shot.shotCode });
          });
        });
    });
    filteredAssetTasks.forEach((task) => {
      const ver = getLatestVersion(task);
      if (ver) queue.push({ versionId: ver.id, label: task.asset?.assetCode ?? task.title });
    });
    return queue;
  };

  const handleReviewClick = () => {
    sessionStorage.setItem(SCROLL_KEY, String(window.scrollY));
    sessionStorage.setItem(QUEUE_KEY, JSON.stringify(getReviewQueue()));
    sessionStorage.setItem(
      STATE_KEY,
      JSON.stringify({
        statusFilter,
        sortMode,
        searchQuery,
        episodeFilter,
        collapsedEpisodes: Array.from(collapsedEpisodes),
      }),
    );
  };

  return (
    <div className="min-h-screen bg-zinc-950 text-white">
      <header className="border-b border-zinc-800 bg-zinc-900">
        <div className="max-w-5xl mx-auto px-6 py-4 flex items-center justify-between">
          {/* Logo */}
          <div className='flex items-center gap-3'>
            <div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-md bg-black">
              <Image src="/logo.svg" alt="Logo" width={32} height={32} />
            </div>

            <div className={montserrat.className}>
              <span className="block text-2xl font-light text-white leading-none">
                TWO TALES
              </span>

              <span className="block text-[11px] tracking-[0.18em]  italic text-zinc-400 leading-none -mt-0.25">
                vfx review
              </span>
            </div>
          </div>
          {sessionLabel && (
            <span className="text-sm text-zinc-400">{sessionLabel}</span>
          )}
        </div>
      </header>

      <div className="border-b border-zinc-800 bg-zinc-900/50">
        <div className="max-w-5xl mx-auto px-6 py-8">
          <p className="text-xs text-zinc-500 uppercase tracking-wider font-medium mb-1">
            {project.code}
          </p>
          <h1 className="text-3xl font-bold text-white mb-2">{project.name}</h1>
          {project.description && (
            <p className="text-zinc-400 text-sm max-w-xl">
              {project.description}
            </p>
          )}
          <div className="flex flex-wrap gap-3 mt-6">
            <button
              onClick={() => setStatusFilter(null)}
              className={cn(
                'rounded-lg px-4 py-3 text-center min-w-[80px] transition-all',
                !statusFilter
                  ? 'bg-zinc-700 ring-1 ring-zinc-500'
                  : 'bg-zinc-800 hover:bg-zinc-700/80',
              )}
            >
              <p className="text-2xl font-bold text-white">{totalTasks}</p>
              <p className="text-xs text-zinc-400 mt-0.5">Items</p>
            </button>
            <button
              onClick={() => toggleStatusFilter('APPROVED')}
              className={cn(
                'rounded-lg px-4 py-3 text-center min-w-[80px] transition-all border',
                statusFilter === 'APPROVED'
                  ? 'bg-emerald-900/50 border-emerald-700/60 ring-1 ring-emerald-600/50'
                  : 'bg-emerald-900/30 border-emerald-800/30 hover:bg-emerald-900/50',
              )}
            >
              <p className="text-2xl font-bold text-emerald-400">{approved}</p>
              <p className="text-xs text-zinc-400 mt-0.5">Approved</p>
            </button>
            <button
              onClick={() => toggleStatusFilter('PENDING_REVIEW')}
              className={cn(
                'rounded-lg px-4 py-3 text-center min-w-[80px] transition-all border',
                statusFilter === 'PENDING_REVIEW'
                  ? 'bg-amber-900/40 border-amber-700/50 ring-1 ring-amber-600/50'
                  : 'bg-amber-900/20 border-amber-800/20 hover:bg-amber-900/40',
              )}
            >
              <p className="text-2xl font-bold text-amber-400">{pending}</p>
              <p className="text-xs text-zinc-400 mt-0.5">Awaiting Review</p>
            </button>
            {needsChanges > 0 && (
              <button
                onClick={() => toggleStatusFilter('NEEDS_CHANGES')}
                className={cn(
                  'rounded-lg px-4 py-3 text-center min-w-[80px] transition-all border',
                  statusFilter === 'NEEDS_CHANGES'
                    ? 'bg-red-900/40 border-red-700/50 ring-1 ring-red-600/50'
                    : 'bg-red-900/20 border-red-800/20 hover:bg-red-900/40',
                )}
              >
                <p className="text-2xl font-bold text-red-400">{needsChanges}</p>
                <p className="text-xs text-zinc-400 mt-0.5">Needs Changes</p>
              </button>
            )}
          </div>
        </div>
      </div>

      <main className="max-w-5xl mx-auto px-6 py-8 space-y-4">
        {/* Controls bar */}
        <div className="space-y-3">
          {/* Search input */}
          <div className="relative">
            <Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-zinc-500 pointer-events-none" />
            <input
              type="text"
              placeholder="Search shots, tasks..."
              value={searchQuery}
              onChange={(e) => setSearchQuery(e.target.value)}
              className="w-full bg-zinc-900 border border-zinc-800 rounded-lg pl-9 pr-9 py-2 text-sm text-white placeholder-zinc-500 focus:outline-none focus:border-zinc-600 transition-colors"
            />
            {searchQuery && (
              <button
                onClick={() => setSearchQuery('')}
                className="absolute right-3 top-1/2 -translate-y-1/2 text-zinc-500 hover:text-zinc-300 transition-colors"
                aria-label="Clear search"
              >
                <X className="h-3.5 w-3.5" />
              </button>
            )}
          </div>

          {/* Filter / sort row */}
          <div className="flex items-center justify-between gap-3 flex-wrap">
            {/* Episode filter buttons */}
            <div className="flex items-center gap-2 flex-wrap">
              {showEpisodeFilters && (
                <>
                  <button
                    onClick={() => setEpisodeFilter(null)}
                    className={cn(
                      'inline-flex items-center px-3 py-1.5 rounded-lg text-xs font-medium border transition-all',
                      episodeFilter === null
                        ? 'bg-zinc-700 border-zinc-500 text-white'
                        : 'bg-zinc-800 border-zinc-700 text-zinc-400 hover:text-zinc-300',
                    )}
                  >
                    All
                  </button>
                  {episodeKeys.map((key) => (
                    <button
                      key={key}
                      onClick={() => setEpisodeFilter(episodeFilter === key ? null : key)}
                      className={cn(
                        'inline-flex items-center px-3 py-1.5 rounded-lg text-xs font-medium border transition-all',
                        episodeFilter === key
                          ? 'bg-zinc-700 border-zinc-500 text-white'
                          : 'bg-zinc-800 border-zinc-700 text-zinc-400 hover:text-zinc-300',
                      )}
                    >
                      {isEpisodic ? `EP ${key}` : key}
                    </button>
                  ))}
                  {assetTasks.length > 0 && (
                    <button
                      onClick={() =>
                        setEpisodeFilter(episodeFilter === '__assets__' ? null : '__assets__')
                      }
                      className={cn(
                        'inline-flex items-center px-3 py-1.5 rounded-lg text-xs font-medium border transition-all',
                        episodeFilter === '__assets__'
                          ? 'bg-zinc-700 border-zinc-500 text-white'
                          : 'bg-zinc-800 border-zinc-700 text-zinc-400 hover:text-zinc-300',
                      )}
                    >
                      Assets
                    </button>
                  )}
                </>
              )}
              {statusFilter && (
                <span className="text-xs text-zinc-500">
                  {showEpisodeFilters && '·'}{' '}
                  {statusFilter === 'APPROVED'
                    ? 'Approved'
                    : statusFilter === 'PENDING_REVIEW'
                    ? 'Awaiting Review'
                    : 'Needs Changes'}
                </span>
              )}
            </div>

            <div className="flex items-center gap-2">
              <button
                onClick={() =>
                  setSortMode((prev) => (prev === 'episode' ? 'recent' : 'episode'))
                }
                className={cn(
                  'inline-flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-xs font-medium border transition-all',
                  sortMode === 'recent'
                    ? 'bg-amber-500/10 border-amber-500/30 text-amber-400'
                    : 'bg-zinc-800 border-zinc-700 text-zinc-400 hover:text-zinc-300',
                )}
              >
                <ArrowUpDown className="h-3 w-3" />
                {sortMode === 'recent' ? 'Sorted by Recent' : 'Sort by Recent'}
              </button>
              {(statusFilter !== null ||
                sortMode !== 'episode' ||
                searchQuery !== '' ||
                episodeFilter !== null) && (
                <button
                  onClick={() => {
                    setStatusFilter(null);
                    setSortMode('episode');
                    setSearchQuery('');
                    setEpisodeFilter(null);
                  }}
                  className="inline-flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-xs font-medium border border-zinc-700 bg-zinc-800 text-zinc-400 hover:text-zinc-300 transition-all"
                >
                  <RotateCcw className="h-3 w-3" />
                  Reset
                </button>
              )}
            </div>
          </div>
        </div>

        {sortMode === 'recent' ? (
          <div className="space-y-3">
            {filteredFlatItems.length === 0 ? (
              <div className="text-center py-16 text-zinc-500">
                <Film className="h-10 w-10 mx-auto mb-3 opacity-30" />
                <p>
                  {statusFilter
                    ? 'No items match the current filter.'
                    : 'No items have been shared for review yet.'}
                </p>
              </div>
            ) : (
              filteredFlatItems.map((item) => {
                const task = item.task;
                const ver = getLatestVersion(task);
                const approvalKey = ver?.approvalStatus ?? 'PENDING_REVIEW';
                const approval =
                  APPROVAL_STYLES[approvalKey] ?? APPROVAL_STYLES.PENDING_REVIEW;
                const ApprovalIcon = approval.Icon;
                return (
                  <div key={task.id} className="space-y-1">
                    <div className="flex items-center gap-2 px-1">
                      {item.thumbnailUrl && (
                        <div className="relative w-14 aspect-[2.39] rounded overflow-hidden border border-zinc-800 shrink-0">
                          <Image
                            src={item.thumbnailUrl}
                            alt={item.label}
                            fill
                            className="object-cover"
                          />
                        </div>
                      )}
                      <div className="flex items-center gap-1.5 group/itemlabel">
                        <p className="font-mono text-xs text-zinc-500">
                          {item.label}
                          {item.description && (
                            <span className="font-sans text-zinc-600 ml-2">
                              {item.description}
                            </span>
                          )}
                        </p>
                        <button
                          onClick={() => copyToClipboard(item.label, `label-${task.id}`)}
                          className="shrink-0 p-0.5 rounded opacity-0 group-hover/itemlabel:opacity-100 text-zinc-600 hover:text-zinc-300 transition-all"
                          title="Copy name"
                        >
                          {copiedId === `label-${task.id}` ? (
                            <Check className="h-3 w-3 text-emerald-400" />
                          ) : (
                            <Copy className="h-3 w-3" />
                          )}
                        </button>
                      </div>
                      {ver?.createdAt && (
                        <p className="ml-auto text-xs text-zinc-600">
                          {formatDate(ver.createdAt)}
                        </p>
                      )}
                    </div>
                    <Link
                      href={ver ? `/client/${token}/review/${ver.id}` : '#'}
                      onClick={handleReviewClick}
                      className={cn(
                        'flex items-center gap-4 p-4 rounded-xl border transition-all group',
                        'bg-zinc-900 border-zinc-800 hover:border-zinc-600 hover:bg-zinc-800/70',
                        !ver && 'pointer-events-none opacity-40',
                      )}
                    >
                      <div className="flex-1 min-w-0">
                        <div className="flex items-center gap-1.5">
                          <p className="text-sm font-medium text-white">
                            {task.title}
                          </p>
                          <button
                            onClick={(e) => { e.preventDefault(); e.stopPropagation(); copyToClipboard(task.title, `task-${task.id}`); }}
                            className="shrink-0 p-0.5 rounded opacity-0 group-hover:opacity-100 text-zinc-600 hover:text-zinc-300 transition-all"
                            title="Copy task name"
                          >
                            {copiedId === `task-${task.id}` ? (
                              <Check className="h-3 w-3 text-emerald-400" />
                            ) : (
                              <Copy className="h-3 w-3" />
                            )}
                          </button>
                        </div>
                        <p className="text-xs text-zinc-500">
                          {TASK_TYPE_LABELS[task.type] ?? task.type}
                        </p>
                        {ver?.notes && (
                          <p className="text-xs text-zinc-500 truncate italic mt-0.5">
                            &ldquo;{ver.notes}&rdquo;
                          </p>
                        )}
                      </div>
                      {ver ? (
                        <span
                          className={cn(
                            'inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full border text-xs font-medium shrink-0',
                            approval.className,
                          )}
                        >
                          <ApprovalIcon className="h-3 w-3" />
                          {approval.label}
                        </span>
                      ) : (
                        <span className="text-xs text-zinc-600 shrink-0">
                          No versions yet
                        </span>
                      )}
                      <ChevronRight className="h-4 w-4 text-zinc-600 group-hover:text-zinc-400 shrink-0 transition-colors" />
                    </Link>
                  </div>
                );
              })
            )}
          </div>
        ) : (
          <>
            {Object.entries(shotsByEpisode)
              .filter(([episode]) => episodeFilter === null || episodeFilter === episode)
              .map(([episode, epShots]) => {
              const filteredEpShots = epShots
                .map((shot) => ({ ...shot, tasks: shot.tasks.filter(taskMatchesFilter) }))
                .filter((shot) => shot.tasks.length > 0)
                .filter(shotMatchesSearch);

              if (filteredEpShots.length === 0) return null;

              const isCollapsed = collapsedEpisodes.has(episode);
              const epTasks = filteredEpShots.flatMap((s) => s.tasks);
              const epApproved = epTasks.filter(
                (t) => getLatestVersion(t)?.approvalStatus === 'APPROVED',
              ).length;
              const epChanges = epTasks.filter((t) =>
                ['REJECTED', 'NEEDS_CHANGES'].includes(
                  getLatestVersion(t)?.approvalStatus ?? '',
                ),
              ).length;
              const epPending = epTasks.length - epApproved - epChanges;

              return (
                <div key={episode} className="rounded-xl border border-zinc-800 overflow-hidden">
                  {/* Episode header — clickable */}
                  <button
                    className="w-full flex items-center gap-3 px-5 py-4 bg-zinc-900 hover:bg-zinc-800/80 transition-colors text-left"
                    onClick={() => toggleEpisode(episode)}
                  >
                    <ChevronDown
                      className={cn(
                        'h-4 w-4 text-zinc-400 shrink-0 transition-transform duration-200',
                        isCollapsed && '-rotate-90',
                      )}
                    />
                    <div className="flex-1 min-w-0">
                      <span className="text-xs font-semibold uppercase tracking-widest text-zinc-400">
                        {isEpisodic ? `Episode ${episode}` : episode}
                      </span>
                      <span className="ml-3 text-xs text-zinc-600">
                        {filteredEpShots.length}{' '}
                        {filteredEpShots.length === 1 ? 'shot' : 'shots'}
                      </span>
                    </div>
                    {/* Per-episode progress pills */}
                    <div className="flex items-center gap-2 shrink-0">
                      {epApproved > 0 && (
                        <span className="inline-flex items-center gap-1 px-2 py-0.5 rounded-full bg-emerald-900/40 border border-emerald-800/40 text-emerald-400 text-xs">
                          <CheckCircle2 className="h-3 w-3" />
                          {epApproved}
                        </span>
                      )}
                      {epChanges > 0 && (
                        <span className="inline-flex items-center gap-1 px-2 py-0.5 rounded-full bg-red-900/30 border border-red-800/30 text-red-400 text-xs">
                          <AlertCircle className="h-3 w-3" />
                          {epChanges}
                        </span>
                      )}
                      {epPending > 0 && (
                        <span className="inline-flex items-center gap-1 px-2 py-0.5 rounded-full bg-amber-900/20 border border-amber-800/20 text-amber-400 text-xs">
                          <Clock className="h-3 w-3" />
                          {epPending}
                        </span>
                      )}
                    </div>
                  </button>

                  {/* Collapsible shot list */}
                  {!isCollapsed && (
                    <div className="divide-y divide-zinc-800/60 bg-zinc-950/40">
                      {filteredEpShots.map((shot) => (
                        <div key={shot.id} className="px-5 py-4 space-y-2">
                          <div className="flex items-center gap-3">
                            {shot.thumbnailUrl && (
                              <div className="relative flex-shrink-0 w-32 aspect-[2.39] rounded overflow-hidden border border-zinc-800">
                                <Image
                                  src={shot.thumbnailUrl}
                                  alt={shot.shotCode}
                                  fill
                                  className="object-cover"
                                />
                              </div>
                            )}
                            <div className="flex items-center gap-1.5 group/shotcode">
                              <p className="font-mono text-sm font-semibold text-zinc-300">
                                {shot.shotCode}
                                {shot.description && (
                                  <span className="font-sans font-normal text-zinc-500 ml-2">
                                    {shot.description}
                                  </span>
                                )}
                              </p>
                              <button
                                onClick={() => copyToClipboard(shot.shotCode, `shot-${shot.id}`)}
                                className="shrink-0 p-0.5 rounded opacity-0 group-hover/shotcode:opacity-100 text-zinc-600 hover:text-zinc-300 transition-all"
                                title="Copy shot code"
                              >
                                {copiedId === `shot-${shot.id}` ? (
                                  <Check className="h-3 w-3 text-emerald-400" />
                                ) : (
                                  <Copy className="h-3 w-3" />
                                )}
                              </button>
                            </div>
                          </div>
                          <div className="space-y-1.5 pl-3 border-l border-zinc-800">
                            {shot.tasks.map((task) => {
                              const ver = getLatestVersion(task);
                              const approvalKey =
                                ver?.approvalStatus ?? 'PENDING_REVIEW';
                              const approval =
                                APPROVAL_STYLES[approvalKey] ??
                                APPROVAL_STYLES.PENDING_REVIEW;
                              const ApprovalIcon = approval.Icon;
                              return (
                                <Link
                                  key={task.id}
                                  href={ver ? `/client/${token}/review/${ver.id}` : '#'}
                                  onClick={handleReviewClick}
                                  className={cn(
                                    'flex items-center gap-4 p-4 rounded-xl border transition-all group',
                                    'bg-zinc-900 border-zinc-800 hover:border-zinc-600 hover:bg-zinc-800/70',
                                    !ver && 'pointer-events-none opacity-40',
                                  )}
                                >
                                  <div className="flex-1 min-w-0">
                                    <div className="flex items-center gap-1.5">
                                      <p className="text-sm font-medium text-white">
                                        {task.title}
                                      </p>
                                      <button
                                        onClick={(e) => { e.preventDefault(); e.stopPropagation(); copyToClipboard(task.title, `task-${task.id}`); }}
                                        className="shrink-0 p-0.5 rounded opacity-0 group-hover:opacity-100 text-zinc-600 hover:text-zinc-300 transition-all"
                                        title="Copy task name"
                                      >
                                        {copiedId === `task-${task.id}` ? (
                                          <Check className="h-3 w-3 text-emerald-400" />
                                        ) : (
                                          <Copy className="h-3 w-3" />
                                        )}
                                      </button>
                                    </div>
                                    <p className="text-xs text-zinc-500">
                                      {TASK_TYPE_LABELS[task.type] ?? task.type}
                                    </p>
                                    {ver?.notes && (
                                      <p className="text-xs text-zinc-500 truncate italic mt-0.5">
                                        &ldquo;{ver.notes}&rdquo;
                                      </p>
                                    )}
                                  </div>
                                  {ver ? (
                                    <div className="flex items-center gap-3 shrink-0">
                                      {ver.createdAt && (
                                        <span className="text-xs text-zinc-600 hidden sm:block">
                                          {formatDate(ver.createdAt)}
                                        </span>
                                      )}
                                      <span
                                        className={cn(
                                          'inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full border text-xs font-medium',
                                          approval.className,
                                        )}
                                      >
                                        <ApprovalIcon className="h-3 w-3" />
                                        {approval.label}
                                      </span>
                                    </div>
                                  ) : (
                                    <span className="text-xs text-zinc-600 shrink-0">
                                      No versions yet
                                    </span>
                                  )}
                                  <ChevronRight className="h-4 w-4 text-zinc-600 group-hover:text-zinc-400 shrink-0 transition-colors" />
                                </Link>
                              );
                            })}
                          </div>
                        </div>
                      ))}
                    </div>
                  )}
                </div>
              );
            })}

            {filteredAssetTasks.length > 0 && (
              <div className="rounded-xl border border-zinc-800 overflow-hidden">
                {/* Assets header */}
                <button
                  className="w-full flex items-center gap-3 px-5 py-4 bg-zinc-900 hover:bg-zinc-800/80 transition-colors text-left"
                  onClick={() => toggleEpisode('__assets__')}
                >
                  <ChevronDown
                    className={cn(
                      'h-4 w-4 text-zinc-400 shrink-0 transition-transform duration-200',
                      collapsedEpisodes.has('__assets__') && '-rotate-90',
                    )}
                  />
                  <span className="text-xs font-semibold uppercase tracking-widest text-zinc-400 flex-1">
                    Assets
                  </span>
                  <span className="text-xs text-zinc-600">
                    {filteredAssetTasks.length}{' '}
                    {filteredAssetTasks.length === 1 ? 'item' : 'items'}
                  </span>
                </button>

                {!collapsedEpisodes.has('__assets__') && (
                  <div className="divide-y divide-zinc-800/60 bg-zinc-950/40 p-4 space-y-2">
                    {filteredAssetTasks.map((task) => {
                      const ver = getLatestVersion(task);
                      const approvalKey = ver?.approvalStatus ?? 'PENDING_REVIEW';
                      const approval =
                        APPROVAL_STYLES[approvalKey] ??
                        APPROVAL_STYLES.PENDING_REVIEW;
                      const ApprovalIcon = approval.Icon;
                      return (
                        <Link
                          key={task.id}
                          href={ver ? `/client/${token}/review/${ver.id}` : '#'}
                          onClick={handleReviewClick}
                            className={cn(
                              'flex items-center gap-4 p-4 rounded-xl border transition-all group',
                              'bg-zinc-900 border-zinc-800 hover:border-zinc-600 hover:bg-zinc-800/70',
                              !ver && 'pointer-events-none opacity-40',
                            )}
                          >
                            <Package className="h-4 w-4 text-zinc-500 shrink-0" />
                            <div className="min-w-[90px]">
                            <p className="font-mono font-semibold text-white text-sm">
                              {task.asset?.assetCode ?? TASK_TYPE_LABELS[task.type]}
                            </p>
                            <p className="text-xs text-zinc-500">
                              {TASK_TYPE_LABELS[task.type] ?? task.type}
                            </p>
                          </div>
                          <div className="flex-1 min-w-0">
                            <div className="flex items-center gap-1.5">
                              <p className="text-sm text-zinc-300 truncate">
                                {task.title}
                              </p>
                              <button
                                onClick={(e) => { e.preventDefault(); e.stopPropagation(); copyToClipboard(task.title, `task-${task.id}`); }}
                                className="shrink-0 p-0.5 rounded opacity-0 group-hover:opacity-100 text-zinc-600 hover:text-zinc-300 transition-all"
                                title="Copy task name"
                              >
                                {copiedId === `task-${task.id}` ? (
                                  <Check className="h-3 w-3 text-emerald-400" />
                                ) : (
                                  <Copy className="h-3 w-3" />
                                )}
                              </button>
                            </div>
                            {ver?.notes && (
                              <p className="text-xs text-zinc-500 truncate italic mt-0.5">
                                &ldquo;{ver.notes}&rdquo;
                              </p>
                            )}
                          </div>
                          {ver ? (
                            <div className="flex items-center gap-3 shrink-0">
                              <span
                                className={cn(
                                  'inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full border text-xs font-medium',
                                  approval.className,
                                )}
                              >
                                <ApprovalIcon className="h-3 w-3" />
                                {approval.label}
                              </span>
                            </div>
                          ) : (
                            <span className="text-xs text-zinc-600 shrink-0">
                              No versions yet
                            </span>
                          )}
                          <ChevronRight className="h-4 w-4 text-zinc-600 group-hover:text-zinc-400 shrink-0 transition-colors" />
                        </Link>
                      );
                    })}
                  </div>
                )}
              </div>
            )}

            {totalTasks === 0 && (
              <div className="text-center py-16 text-zinc-500">
                <Film className="h-10 w-10 mx-auto mb-3 opacity-30" />
                <p>No items have been shared for review yet.</p>
              </div>
            )}
            {totalTasks > 0 && filteredFlatItems.length === 0 && (
              <div className="text-center py-16 text-zinc-500">
                <Film className="h-10 w-10 mx-auto mb-3 opacity-30" />
                <p>No items match the current filter.</p>
              </div>
            )}
          </>
        )}
      </main>

      <footer className="border-t border-zinc-800 py-6 text-center text-xs text-zinc-600">
        Powered by <span className="text-zinc-400">TTDEV</span>
      </footer>
    </div>
  );
}
