     1→'use client';
     2→
     3→import { useState, useCallback, useRef, useEffect } from 'react';
     4→import { motion, AnimatePresence } from 'framer-motion';
     5→import {
     6→  Upload, Image as ImageIcon, Sparkles, Download, ArrowRight,
     7→  Palette, Camera, Layers, SlidersHorizontal, Loader2, Check,
     8→  Trash2, RotateCcw, Eye, Wand2, Sun, Paintbrush, Film,
     9→  Pencil, History, ChevronLeft, X, GripVertical, WandSparkles,
    10→  Square, RectangleVertical, Monitor, Settings, Megaphone, Code
    11→} from 'lucide-react';
    12→import { Button } from '@/components/ui/button';
    13→import { Textarea } from '@/components/ui/textarea';
    14→import { Progress } from '@/components/ui/progress';
    15→import { Card, CardContent } from '@/components/ui/card';
    16→import {
    17→  Dialog,
    18→  DialogContent,
    19→  DialogHeader,
    20→  DialogTitle,
    21→  DialogTrigger,
    22→} from '@/components/ui/dialog';
    23→import { Input } from '@/components/ui/input';
    24→import { Switch } from '@/components/ui/switch';
    25→import { Label } from '@/components/ui/label';
    26→import { useAppStore, type PhotoProject } from '@/store/photo-store';
    27→
    28→/* ─── Types ─── */
    29→interface BannerData {
    30→  id: string;
    31→  adType: string;
    32→  imageUrl: string;
    33→  adCode: string;
    34→  linkUrl: string;
    35→  text: string;
    36→  active: boolean;
    37→  position: string;
    38→}
    39→
    40→/* ─── Banner Display Component ─── */
    41→function BannerDisplay({ position }: { position: 'top' | 'above-upload' | 'below-features' }) {
    42→  const [banner, setBanner] = useState<BannerData | null>(null);
    43→  const [dismissed, setDismissed] = useState(false);
    44→
    45→  useEffect(() => {
    46→    fetch('/api/banner')
    47→      .then((r) => r.json())
    48→      .then((data) => {
    49→        if (data.banner && data.banner.position === position) {
    50→          setBanner(data.banner);
    51→        }
    52→      })
    53→      .catch(() => {});
    54→  }, [position]);
    55→
    56→  if (!banner || !banner.active || dismissed) return null;
    57→
    58→  // External ad code (Google AdSense, etc.)
    59→  if (banner.adType === 'external' && banner.adCode) {
    60→    return (
    61→      <motion.div
    62→        initial={{ opacity: 0, y: -10 }}
    63→        animate={{ opacity: 1, y: 0 }}
    64→        className="relative w-full max-w-4xl mx-auto"
    65→      >
    66→        <div className="rounded-xl overflow-hidden bg-card/50 border border-border/30 p-1">
    67→          <div
    68→            className="w-full min-h-[60px] flex items-center justify-center"
    69→            dangerouslySetInnerHTML={{ __html: banner.adCode }}
    70→          />
    71→        </div>
    72→        <button
    73→          onClick={() => setDismissed(true)}
    74→          className="absolute -top-2 -left-2 w-6 h-6 rounded-full bg-muted text-muted-foreground flex items-center justify-center hover:bg-muted-foreground hover:text-background transition-colors border border-border/50"
    75→          aria-label="إغلاق الإعلان"
    76→        >
    77→          <X className="w-3 h-3" />
    78→        </button>
    79→      </motion.div>
    80→    );
    81→  }
    82→
    83→  // Image banner
    84→  if (!banner.imageUrl) return null;
    85→
    86→  const Wrapper = banner.linkUrl ? 'a' : 'div';
    87→  const wrapperProps = banner.linkUrl
    88→    ? { href: banner.linkUrl, target: '_blank' as const, rel: 'noopener noreferrer' }
    89→    : {};
    90→
    91→  return (
    92→    <motion.div
    93→      initial={{ opacity: 0, y: -10 }}
    94→      animate={{ opacity: 1, y: 0 }}
    95→      className="relative w-full max-w-4xl mx-auto"
    96→    >
    97→      <Wrapper
    98→        {...wrapperProps}
    99→        className="block relative rounded-xl overflow-hidden"
   100→      >
   101→        <img
   102→          src={banner.imageUrl}
   103→          alt={banner.text || 'إعلان'}
   104→          className="w-full h-auto object-cover max-h-48 rounded-xl"
   105→        />
   106→        {banner.text && (
   107→          <div className="absolute inset-0 bg-gradient-to-t from-black/60 via-transparent to-transparent flex items-end p-4">
   108→            <p className="text-white text-sm sm:text-base font-medium">{banner.text}</p>
   109→          </div>
   110→        )}
   111→      </Wrapper>
   112→      <button
   113→        onClick={() => setDismissed(true)}
   114→        className="absolute top-2 left-2 w-6 h-6 rounded-full bg-black/50 text-white flex items-center justify-center hover:bg-black/70 transition-colors"
   115→        aria-label="إغلاق الإعلان"
   116→      >
   117→        <X className="w-3 h-3" />
   118→      </button>
   119→    </motion.div>
   120→  );
   121→}
   122→
   123→/* ─── Banner Admin Panel ─── */
   124→function BannerAdmin({ open, onOpenChange }: { open: boolean; onOpenChange: (v: boolean) => void }) {
   125→  const [adType, setAdType] = useState<'image' | 'external'>('image');
   126→  const [imageUrl, setImageUrl] = useState('');
   127→  const [adCode, setAdCode] = useState('');
   128→  const [linkUrl, setLinkUrl] = useState('');
   129→  const [text, setText] = useState('');
   130→  const [active, setActive] = useState(false);
   131→  const [position, setPosition] = useState('top');
   132→  const [saving, setSaving] = useState(false);
   133→  const [uploading, setUploading] = useState(false);
   134→  const [message, setMessage] = useState<{ type: 'success' | 'error'; text: string } | null>(null);
   135→  const fileInputRef = useRef<HTMLInputElement>(null);
   136→
   137→  // Load existing banner on open
   138→  useEffect(() => {
   139→    if (!open) return;
   140→    fetch('/api/banner')
   141→      .then((r) => r.json())
   142→      .then((data) => {
   143→        if (data.banner) {
   144→          setAdType((data.banner.adType as 'image' | 'external') || 'image');
   145→          setImageUrl(data.banner.imageUrl || '');
   146→          setAdCode(data.banner.adCode || '');
   147→          setLinkUrl(data.banner.linkUrl);
   148→          setText(data.banner.text);
   149→          setActive(data.banner.active);
   150→          setPosition(data.banner.position);
   151→        } else {
   152→          setAdType('image');
   153→          setImageUrl('');
   154→          setAdCode('');
   155→          setLinkUrl('');
   156→          setText('');
   157→          setActive(false);
   158→          setPosition('top');
   159→        }
   160→        setMessage(null);
   161→      })
   162→      .catch(() => {});
   163→  }, [open]);
   164→
   165→  const handleUpload = useCallback(async (file: File) => {
   166→    if (!file.type.startsWith('image/')) return;
   167→    setUploading(true);
   168→    setMessage(null);
   169→    try {
   170→      const formData = new FormData();
   171→      formData.append('image', file);
   172→      const res = await fetch('/api/banner', { method: 'POST', body: formData });
   173→      const data = await res.json();
   174→      if (!res.ok) throw new Error(data.error || 'فشل رفع الصورة');
   175→      setImageUrl(data.imageUrl);
   176→    } catch (err: unknown) {
   177→      setMessage({ type: 'error', text: err instanceof Error ? err.message : 'خطأ' });
   178→    } finally {
   179→      setUploading(false);
   180→    }
   181→  }, []);
   182→
   183→  const handleSave = useCallback(async () => {
   184→    if (adType === 'image' && !imageUrl) {
   185→      setMessage({ type: 'error', text: 'يرجى رفع صورة البانر أولاً' });
   186→      return;
   187→    }
   188→    if (adType === 'external' && !adCode.trim()) {
   189→      setMessage({ type: 'error', text: 'يرجى لصق كود الإعلان الخارجي' });
   190→      return;
   191→    }
   192→    setSaving(true);
   193→    setMessage(null);
   194→    try {
   195→      const res = await fetch('/api/banner', {
   196→        method: 'PUT',
   197→        headers: { 'Content-Type': 'application/json' },
   198→        body: JSON.stringify({ adType, imageUrl, adCode, linkUrl, text, active, position }),
   199→      });
   200→      const data = await res.json();
   201→      if (!res.ok) throw new Error(data.error || 'فشل الحفظ');
   202→      setMessage({ type: 'success', text: 'تم حفظ البانر بنجاح' });
   203→    } catch (err: unknown) {
   204→      setMessage({ type: 'error', text: err instanceof Error ? err.message : 'خطأ' });
   205→    } finally {
   206→      setSaving(false);
   207→    }
   208→  }, [adType, imageUrl, adCode, linkUrl, text, active, position]);
   209→
   210→  const POSITION_OPTIONS = [
   211→    { value: 'top', label: 'أعلى الصفحة' },
   212→    { value: 'above-upload', label: 'فوق منطقة الرفع' },
   213→    { value: 'below-features', label: 'أسفل المميزات' },
   214→  ];
   215→
   216→  return (
   217→    <Dialog open={open} onOpenChange={onOpenChange}>
   218→      <DialogContent className="max-w-md max-h-[90vh] overflow-y-auto" dir="rtl">
   219→        <DialogHeader>
   220→          <DialogTitle className="flex items-center gap-2">
   221→            <Megaphone className="w-5 h-5" />
   222→            إدارة البانر الإعلاني
   223→          </DialogTitle>
   224→        </DialogHeader>
   225→
   226→        <div className="space-y-4 mt-2">
   227→          {/* Ad Type Selector */}
   228→          <div className="space-y-2">
   229→            <Label>نوع الإعلان</Label>
   230→            <div className="grid grid-cols-2 gap-2">
   231→              <button
   232→                onClick={() => setAdType('image')}
   233→                className={`p-3 rounded-lg border text-sm font-medium transition-all flex flex-col items-center gap-1.5 ${
   234→                  adType === 'image'
   235→                    ? 'border-primary bg-primary/10 text-primary'
   236→                    : 'border-border/50 hover:border-primary/30 text-muted-foreground'
   237→                }`}
   238→              >
   239→                <ImageIcon className="w-5 h-5" />
   240→                صورة مرفوعة
   241→              </button>
   242→              <button
   243→                onClick={() => setAdType('external')}
   244→                className={`p-3 rounded-lg border text-sm font-medium transition-all flex flex-col items-center gap-1.5 ${
   245→                  adType === 'external'
   246→                    ? 'border-primary bg-primary/10 text-primary'
   247→                    : 'border-border/50 hover:border-primary/30 text-muted-foreground'
   248→                }`}
   249→              >
   250→                <Code className="w-5 h-5" />
   251→                كود خارجي
   252→              </button>
   253→            </div>
   254→          </div>
   255→
   256→          {/* Image Upload (only for image type) */}
   257→          {adType === 'image' && (
   258→            <div className="space-y-2">
   259→              <Label>صورة البانر</Label>
   260→              <div
   261→                onClick={() => !uploading && fileInputRef.current?.click()}
   262→                className={`relative rounded-lg border-2 border-dashed p-4 text-center cursor-pointer transition-all
   263→                  ${imageUrl ? 'border-primary/30' : 'border-muted-foreground/30 hover:border-primary/50'}`}
   264→              >
   265→                <input
   266→                  ref={fileInputRef}
   267→                  type="file"
   268→                  accept="image/*"
   269→                  className="hidden"
   270→                  onChange={(e) => {
   271→                    const f = e.target.files?.[0];
   272→                    if (f) handleUpload(f);
   273→                    e.target.value = '';
   274→                  }}
   275→                />
   276→                {uploading ? (
   277→                  <div className="flex items-center justify-center gap-2 py-2">
   278→                    <Loader2 className="w-5 h-5 animate-spin text-primary" />
   279→                    <span className="text-sm text-muted-foreground">جارٍ الرفع...</span>
   280→                  </div>
   281→                ) : imageUrl ? (
   282→                  <div className="space-y-2">
   283→                    <img src={imageUrl} alt="بانر" className="w-full h-24 object-cover rounded-md" />
   284→                    <p className="text-xs text-muted-foreground">انقر لتغيير الصورة</p>
   285→                  </div>
   286→                ) : (
   287→                  <div className="py-2">
   288→                    <Upload className="w-8 h-8 mx-auto text-muted-foreground/50 mb-2" />
   289→                    <p className="text-sm text-muted-foreground">انقر لاختيار صورة البانر</p>
   290→                    <p className="text-xs text-muted-foreground mt-1">PNG, JPG, WEBP — حتى 2 ميجا</p>
   291→                  </div>
   292→                )}
   293→              </div>
   294→            </div>
   295→          )}
   296→
   297→          {/* External Ad Code (only for external type) */}
   298→          {adType === 'external' && (
   299→            <div className="space-y-2">
   300→              <Label>كود الإعلان الخارجي</Label>
   301→              <p className="text-xs text-muted-foreground">
   302→                الصق كود الإعلان من جوجل أدسنس أو أي شبكة إعلانية أخرى
   303→              </p>
   304→              <Textarea
   305→                value={adCode}
   306→                onChange={(e) => setAdCode(e.target.value)}
   307→                placeholder={'<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-XXXXX"></script>\n<ins class="adsbygoogle" ...></ins>'}
   308→                className="min-h-[120px] font-mono text-xs"
   309→                dir="ltr"
   310→              />
   311→            </div>
   312→          )}
   313→
   314→          {/* Link URL (only for image type) */}
   315→          {adType === 'image' && (
   316→            <div className="space-y-2">
   317→              <Label>رابط الإعلان (اختياري)</Label>
   318→              <Input
   319→                value={linkUrl}
   320→                onChange={(e) => setLinkUrl(e.target.value)}
   321→                placeholder="https://example.com"
   322→                dir="ltr"
   323→              />
   324→            </div>
   325→          )}
   326→
   327→          {/* Text Overlay (only for image type) */}
   328→          {adType === 'image' && (
   329→            <div className="space-y-2">
   330→              <Label>نص على البانر (اختياري)</Label>
   331→              <Input
   332→                value={text}
   333→                onChange={(e) => setText(e.target.value)}
   334→                placeholder="عنوان الإعلان..."
   335→              />
   336→            </div>
   337→          )}
   338→
   339→          {/* Position */}
   340→          <div className="space-y-2">
   341→            <Label>موضع البانر</Label>
   342→            <div className="grid grid-cols-3 gap-2">
   343→              {POSITION_OPTIONS.map((opt) => (
   344→                <button
   345→                  key={opt.value}
   346→                  onClick={() => setPosition(opt.value)}
   347→                  className={`p-2 rounded-lg border text-xs font-medium transition-all
   348→                    ${position === opt.value
   349→                      ? 'border-primary bg-primary/10 text-primary'
   350→                      : 'border-border/50 hover:border-primary/30 text-muted-foreground'}`}
   351→                >
   352→                  {opt.label}
   353→                </button>
   354→              ))}
   355→            </div>
   356→          </div>
   357→
   358→          {/* Active Toggle */}
   359→          <div className="flex items-center justify-between p-3 rounded-lg border border-border/50">
   360→            <Label className="cursor-pointer">عرض البانر</Label>
   361→            <Switch checked={active} onCheckedChange={setActive} />
   362→          </div>
   363→
   364→          {/* Message */}
   365→          <AnimatePresence>
   366→            {message && (
   367→              <motion.div
   368→                initial={{ opacity: 0, y: -5 }}
   369→                animate={{ opacity: 1, y: 0 }}
   370→                exit={{ opacity: 0 }}
   371→                className={`text-sm p-3 rounded-lg ${message.type === 'success' ? 'bg-emerald-500/10 text-emerald-600' : 'bg-red-500/10 text-red-600'}`}
   372→              >
   373→                {message.text}
   374→              </motion.div>
   375→            )}
   376→          </AnimatePresence>
   377→
   378→          {/* Save Button */}
   379→          <Button
   380→            onClick={handleSave}
   381→            disabled={saving || (adType === 'image' ? !imageUrl : !adCode.trim())}
   382→            className="w-full gap-2"
   383→          >
   384→            {saving ? <Loader2 className="w-4 h-4 animate-spin" /> : <Check className="w-4 h-4" />}
   385→            {saving ? 'جارٍ الحفظ...' : 'حفظ البانر'}
   386→          </Button>
   387→        </div>
   388→      </DialogContent>
   389→    </Dialog>
   390→  );
   391→}
   392→
   393→/* ─── Edit Tool Definitions ─── */
   394→const EDIT_TOOLS = [
   395→  { id: 'oil-painting', label: 'لوحة زيتية', icon: Paintbrush, prompt: 'Transform this image into an oil painting style, with visible brushstrokes and rich, vibrant colors, maintain the composition and subject', color: 'from-amber-500/20 to-orange-600/20' },
   396→  { id: 'cartoon', label: 'رسم كرتوني', icon: Pencil, prompt: 'Transform this image into a cartoon illustration style, with bold outlines, flat colors, and simplified shapes, keep the main subject recognizable', color: 'from-pink-500/20 to-rose-600/20' },
   397→  { id: 'bw', label: 'أبيض وأسود', icon: Camera, prompt: 'Convert this image to a stunning black and white photograph with high contrast and dramatic lighting, professional photography style', color: 'from-gray-500/20 to-gray-700/20' },
   398→  { id: 'golden-hour', label: 'إضاءة ذهبية', icon: Sun, prompt: 'Apply warm golden hour lighting to this image, with beautiful warm tones, soft shadows, and a magical sunset glow, maintain all subjects', color: 'from-yellow-500/20 to-amber-600/20' },
   399→  { id: 'enhance', label: 'تحسين الجودة', icon: Sparkles, prompt: 'Enhance the quality and sharpness of this image, improve colors, add more detail and clarity, make it look professional and high-resolution', color: 'from-emerald-500/20 to-teal-600/20' },
   400→  { id: 'bg-remove', label: 'خلفية احترافية', icon: Layers, prompt: 'Enhance this photo with a clean neutral studio background while preserving the main subject naturally', color: 'from-cyan-500/20 to-blue-600/20' },
   401→  { id: 'cinematic', label: 'تأثير سينمائي', icon: Film, prompt: 'Apply a cinematic color grading to this image, with deep shadows, teal and orange tones, letterbox style, dramatic and moody atmosphere', color: 'from-violet-500/20 to-purple-600/20' },
   402→  { id: 'illustration', label: 'أسلوب رسومي', icon: Palette, prompt: 'Transform this image into a digital illustration style, clean lines, artistic rendering, vibrant but harmonious colors, maintain the scene composition', color: 'from-fuchsia-500/20 to-pink-600/20' },
   403→];
   404→
   405→/* ─── Header Component ─── */
   406→function Header({ onOpenBannerAdmin }: { onOpenBannerAdmin: () => void }) {
   407→  const { currentView, setView } = useAppStore();
   408→  return (
   409→    <header className="glass sticky top-0 z-50">
   410→      <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 h-16 flex items-center justify-between">
   411→        <button
   412→          onClick={() => setView('home')}
   413→          className="flex items-center gap-3 group"
   414→        >
   415→          <div className="w-9 h-9 rounded-lg bg-primary/20 flex items-center justify-center">
   416→            <Wand2 className="w-5 h-5 text-primary" />
   417→          </div>
   418→          <span className="text-lg font-bold gradient-text">محرر الصور Fouad AI</span>
   419→        </button>
   420→        <nav className="flex items-center gap-1">
   421→          <Button
   422→            variant={currentView === 'home' ? 'default' : 'ghost'}
   423→            size="sm"
   424→            onClick={() => setView('home')}
   425→            className="gap-2"
   426→          >
   427→            <ImageIcon className="w-4 h-4" />
   428→            <span className="hidden sm:inline">الرئيسية</span>
   429→          </Button>
   430→          <Button
   431→            variant={currentView === 'gallery' ? 'default' : 'ghost'}
   432→            size="sm"
   433→            onClick={() => setView('gallery')}
   434→            className="gap-2"
   435→          >
   436→            <History className="w-4 h-4" />
   437→            <span className="hidden sm:inline">المعرض</span>
   438→          </Button>
   439→          <Button
   440→            variant={currentView === 'generate' ? 'default' : 'ghost'}
   441→            size="sm"
   442→            onClick={() => setView('generate')}
   443→            className="gap-2"
   444→          >
   445→            <WandSparkles className="w-4 h-4" />
   446→            <span className="hidden sm:inline">توليد الصور</span>
   447→          </Button>
   448→          <Button
   449→            variant="ghost"
   450→            size="icon"
   451→            className="mr-1"
   452→            onClick={onOpenBannerAdmin}
   453→            title="إدارة البانر"
   454→          >
   455→            <Settings className="w-4 h-4" />
   456→          </Button>
   457→        </nav>
   458→      </div>
   459→    </header>
   460→  );
   461→}
   462→
   463→/* ─── Footer Component ─── */
   464→function Footer() {
   465→  return (
   466→    <footer className="glass mt-auto">
   467→      <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4 flex flex-col sm:flex-row items-center justify-between gap-2 text-sm text-muted-foreground">
   468→        <p>محرر الصور Fouad AI — قوّة الذكاء الاصطناعي بين يديك</p>
   469→        <p>© {new Date().getFullYear()} جميع الحقوق محفوظة</p>
   470→      </div>
   471→    </footer>
   472→  );
   473→}
   474→
   475→/* ─── Upload Area Component ─── */
   476→function UploadArea() {
   477→  const { setOriginalImage, setOriginalFileName, setView, setAnalysis, setEditedImage, setEditError } = useAppStore();
   478→  const [isDragOver, setIsDragOver] = useState(false);
   479→  const [isUploading, setIsUploading] = useState(false);
   480→  const fileInputRef = useRef<HTMLInputElement>(null);
   481→
   482→  const handleFile = useCallback(async (file: File) => {
   483→    if (!file.type.startsWith('image/')) return;
   484→    setIsUploading(true);
   485→    setEditError(null);
   486→    setEditedImage(null);
   487→    setAnalysis(null);
   488→    try {
   489→      const formData = new FormData();
   490→      formData.append('image', file);
   491→
   492→      const res = await fetch('/api/upload', { method: 'POST', body: formData });
   493→      const data = await res.json();
   494→      if (!res.ok) throw new Error(data.error || 'فشل رفع الصورة');
   495→
   496→      setOriginalImage(data.imageUrl);
   497→      setOriginalFileName(file.name);
   498→      setView('editor');
   499→    } catch (err: unknown) {
   500→      const message = err instanceof Error ? err.message : 'حدث خطأ';
   501→      setEditError(message);
   502→    } finally {
   503→      setIsUploading(false);
   504→    }
   505→  }, [setOriginalImage, setOriginalFileName, setView, setEditedImage, setAnalysis, setEditError]);
   506→
   507→  const onDrop = useCallback((e: React.DragEvent) => {
   508→    e.preventDefault();
   509→    setIsDragOver(false);
   510→    const file = e.dataTransfer.files[0];
   511→    if (file) handleFile(file);
   512→  }, [handleFile]);
   513→
   514→  const onDragOver = useCallback((e: React.DragEvent) => {
   515→    e.preventDefault();
   516→    setIsDragOver(true);
   517→  }, []);
   518→
   519→  const onDragLeave = useCallback(() => setIsDragOver(false), []);
   520→
   521→  return (
   522→    <motion.div
   523→      initial={{ opacity: 0, y: 30 }}
   524→      animate={{ opacity: 1, y: 0 }}
   525→      transition={{ duration: 0.6 }}
   526→      className="w-full max-w-2xl mx-auto"
   527→    >
   528→      <div
   529→        onDrop={onDrop}
   530→        onDragOver={onDragOver}
   531→        onDragLeave={onDragLeave}
   532→        onClick={() => fileInputRef.current?.click()}
   533→        className={`
   534→          relative cursor-pointer rounded-2xl border-2 border-dashed p-12 sm:p-16
   535→          transition-all duration-300 text-center
   536→          ${isDragOver
   537→            ? 'upload-area-active border-primary'
   538→            : 'border-muted-foreground/30 hover:border-primary/50 hover:bg-primary/5'
   539→          }
   540→        `}
   541→      >
   542→        <input
   543→          ref={fileInputRef}
   544→          type="file"
   545→          accept="image/*"
   546→          className="hidden"
   547→          onChange={(e) => {
   548→            const file = e.target.files?.[0];
   549→            if (file) handleFile(file);
   550→            e.target.value = '';
   551→          }}
   552→        />
   553→        {isUploading ? (
   554→          <div className="flex flex-col items-center gap-4">
   555→            <Loader2 className="w-12 h-12 text-primary animate-spin" />
   556→            <p className="text-lg text-muted-foreground">جارٍ رفع الصورة...</p>
   557→          </div>
   558→        ) : (
   559→          <div className="flex flex-col items-center gap-4">
   560→            <div className="w-20 h-20 rounded-full bg-primary/10 flex items-center justify-center">
   561→              <Upload className="w-10 h-10 text-primary" />
   562→            </div>
   563→            <div>
   564→              <p className="text-xl font-semibold mb-2">اسحب الصورة هنا أو انقر للاختيار</p>
   565→              <p className="text-muted-foreground text-sm">يدعم: PNG, JPG, WEBP — حتى 10 ميجا</p>
   566→            </div>
   567→          </div>
   568→        )}
   569→      </div>
   570→    </motion.div>
   571→  );
   572→}
   573→
   574→/* ─── Feature Cards ─── */
   575→function FeatureCards() {
   576→  const features = [
   577→    { icon: Sparkles, title: 'تحرير بالذكاء', desc: 'أدوات تعديل ذكية تفهم صورتك وتحسّنها' },
   578→    { icon: Palette, title: 'أنماط فنية', desc: 'حوّل صورك إلى لوحات زيتية أو رسوم كرتونية' },
   579→    { icon: SlidersHorizontal, title: 'مقارنة فورية', desc: 'قارن بين الأصل والنسخة المحرّرة بسهولة' },
   580→    { icon: Download, title: 'تحميل مباشر', desc: 'حمّل الصور المحرّرة بجودة عالية' },
   581→  ];
   582→  return (
   583→    <div className="grid grid-cols-2 lg:grid-cols-4 gap-4 max-w-5xl mx-auto mt-16">
   584→      {features.map((f, i) => (
   585→        <motion.div
   586→          key={f.title}
   587→          initial={{ opacity: 0, y: 20 }}
   588→          animate={{ opacity: 1, y: 0 }}
   589→          transition={{ duration: 0.5, delay: 0.2 + i * 0.1 }}
   590→        >
   591→          <Card className="glass h-full text-center p-4 sm:p-6">
   592→            <CardContent className="p-0 flex flex-col items-center gap-3">
   593→              <div className="w-12 h-12 rounded-xl bg-primary/15 flex items-center justify-center">
   594→                <f.icon className="w-6 h-6 text-primary" />
   595→              </div>
   596→              <h3 className="font-semibold text-sm sm:text-base">{f.title}</h3>
   597→              <p className="text-xs sm:text-sm text-muted-foreground">{f.desc}</p>
   598→            </CardContent>
   599→          </Card>
   600→        </motion.div>
   601→      ))}
   602→    </div>
   603→  );
   604→}
   605→
   606→/* ─── Home View ─── */
   607→function HomeView() {
   608→  return (
   609→    <main className="flex-1 flex flex-col items-center px-4 py-12">
   610→      <BannerDisplay position="top" />
   611→      <div className="my-6">
   612→        <BannerDisplay position="above-upload" />
   613→      </div>
   614→      <motion.div
   615→        initial={{ opacity: 0, y: -20 }}
   616→        animate={{ opacity: 1, y: 0 }}
   617→        transition={{ duration: 0.5 }}
   618→        className="text-center mb-10"
   619→      >
   620→        <h1 className="text-4xl sm:text-5xl lg:text-6xl font-bold mb-4">
   621→          <span className="gradient-text">محرر الصور Fouad AI</span>
   622→        </h1>
   623→        <p className="text-lg sm:text-xl text-muted-foreground max-w-xl mx-auto">
   624→          ارفع صورتك واختر التأثير المطلوب — وشاهد الذكاء الاصطناعي يُبدع
   625→        </p>
   626→      </motion.div>
   627→      <UploadArea />
   628→      <FeatureCards />
   629→      <div className="my-6">
   630→        <BannerDisplay position="below-features" />
   631→      </div>
   632→    </main>
   633→  );
   634→}
   635→
   636→/* ─── Before/After Comparison Slider ─── */
   637→function ComparisonSlider({ original, edited }: { original: string; edited: string }) {
   638→  const containerRef = useRef<HTMLDivElement>(null);
   639→  const [position, setPosition] = useState(50);
   640→  const [containerWidth, setContainerWidth] = useState(0);
   641→  const isDragging = useRef(false);
   642→
   643→  useEffect(() => {
   644→    const el = containerRef.current;
   645→    if (!el) return;
   646→    const observer = new ResizeObserver((entries) => {
   647→      for (const entry of entries) {
   648→        setContainerWidth(entry.contentRect.width);
   649→      }
   650→    });
   651→    observer.observe(el);
   652→    return () => observer.disconnect();
   653→  }, []);
   654→
   655→  const updatePosition = useCallback((clientX: number) => {
   656→    if (!containerRef.current) return;
   657→    const rect = containerRef.current.getBoundingClientRect();
   658→    // RTL: position is measured from the right edge
   659→    const x = clientX - rect.left;
   660→    const pct = Math.min(100, Math.max(0, (x / rect.width) * 100));
   661→    setPosition(pct);
   662→  }, []);
   663→
   664→  const handlePointerDown = useCallback((e: React.PointerEvent) => {
   665→    isDragging.current = true;
   666→    (e.target as HTMLElement).setPointerCapture(e.pointerId);
   667→    updatePosition(e.clientX);
   668→  }, [updatePosition]);
   669→
   670→  const handlePointerMove = useCallback((e: React.PointerEvent) => {
   671→    if (!isDragging.current) return;
   672→    updatePosition(e.clientX);
   673→  }, [updatePosition]);
   674→
   675→  const handlePointerUp = useCallback(() => {
   676→    isDragging.current = false;
   677→  }, []);
   678→
   679→  return (
   680→    <div
   681→      ref={containerRef}
   682→      className="comparison-container rounded-xl overflow-hidden bg-black/50 relative w-full"
   683→      style={{ aspectRatio: 'auto' }}
   684→      onPointerDown={handlePointerDown}
   685→      onPointerMove={handlePointerMove}
   686→      onPointerUp={handlePointerUp}
   687→    >
   688→      {/* Edited image (full width, behind) */}
   689→      <img
   690→        src={edited}
   691→        alt="After"
   692→        className="w-full h-auto block"
   693→        draggable={false}
   694→      />
   695→
   696→      {/* Original image (clipped from right in RTL) */}
   697→      <div
   698→        className="absolute inset-0 overflow-hidden"
   699→        style={{ width: `${position}%` }}
   700→      >
   701→        <img
   702→          src={original}
   703→          alt="Before"
   704→          className="w-full h-auto block"
   705→          style={{ width: containerWidth > 0 ? `${containerWidth}px` : '100%' }}
   706→          draggable={false}
   707→        />
   708→      </div>
   709→
   710→      {/* Slider line */}
   711→      <div
   712→        className="comparison-slider-line"
   713→        style={{ left: `${position}%` }}
   714→      >
   715→        <div className="comparison-slider-handle">
   716→          <GripVertical className="w-5 h-5 text-gray-700" />
   717→        </div>
   718→      </div>
   719→
   720→      {/* Labels */}
   721→      <div className="absolute top-3 right-3 bg-black/60 text-white text-xs px-2 py-1 rounded-md">الأصلي</div>
   722→      <div className="absolute top-3 left-3 bg-primary/80 text-white text-xs px-2 py-1 rounded-md">المحرّر</div>
   723→    </div>
   724→  );
   725→}
   726→
   727→/* ─── Editor View ─── */
   728→function EditorView() {
   729→  const {
   730→    originalImage, editedImage, isEditing, editProgress, editError,
   731→    analysis, customPrompt, setCustomPrompt, setEditedImage,
   732→    setEditProgress, setIsEditing, setEditError, setAnalysis,
   733→    setView, resetEditor, projects, setProjects, originalFileName,
   734→  } = useAppStore();
   735→  const [selectedTool, setSelectedTool] = useState<string | null>(null);
   736→  const [lastEditArgs, setLastEditArgs] = useState<{ prompt: string; label: string; toolType: string } | null>(null);
   737→  const [editCount, setEditCount] = useState(0);
   738→  const [isAnalyzing, setIsAnalyzing] = useState(false);
   739→  const fileInputRef = useRef<HTMLInputElement>(null);
   740→
   741→  const handleAnalyze = useCallback(async () => {
   742→    if (!originalImage) return;
   743→    setIsAnalyzing(true);
   744→    try {
   745→      const res = await fetch('/api/analyze', {
   746→        method: 'POST',
   747→        headers: { 'Content-Type': 'application/json' },
   748→        body: JSON.stringify({ imageUrl: originalImage }),
   749→      });
   750→      const data = await res.json();
   751→      if (!res.ok) throw new Error(data.error || 'فشل التحليل');
   752→      setAnalysis(data.analysis);
   753→    } catch (err: unknown) {
   754→      const message = err instanceof Error ? err.message : 'حدث خطأ';
   755→      setEditError(message);
   756→    } finally {
   757→      setIsAnalyzing(false);
   758→    }
   759→  }, [originalImage, setAnalysis, setEditError]);
   760→
   761→  const handleEdit = useCallback(async (prompt: string, label: string, toolType: string) => {
   762→    // Use the last edited image as base for stacking edits
   763→    const baseImage = editedImage || originalImage;
   764→    if (!baseImage) return;
   765→    setLastEditArgs({ prompt, label, toolType });
   766→    setIsEditing(true);
   767→    setEditError(null);
   768→    setEditedImage(null);
   769→    setEditProgress(0);
   770→
   771→    try {
   772→      const res = await fetch('/api/edit', {
   773→        method: 'POST',
   774→        headers: { 'Content-Type': 'application/json' },
   775→        body: JSON.stringify({
   776→          imageUrl: baseImage,
   777→          prompt,
   778→          label,
   779→          toolType,
   780→        }),
   781→      });
   782→
   783→      if (!res.ok) {
   784→        const data = await res.json();
   785→        throw new Error(data.error || 'فشل التعديل');
   786→      }
   787→
   788→      const reader = res.body?.getReader();
   789→      if (!reader) throw new Error('لا يمكن قراءة الاستجابة');
   790→
   791→      const decoder = new TextDecoder();
   792→      let buffer = '';
   793→
   794→      while (true) {
   795→        const { done, value } = await reader.read();
   796→        if (done) break;
   797→
   798→        buffer += decoder.decode(value, { stream: true });
   799→        const lines = buffer.split('\n');
   800→        buffer = lines.pop() || '';
   801→
   802→        for (const line of lines) {
   803→          if (line.startsWith('data: ')) {
   804→            const data = line.slice(6);
   805→            let parsed: Record<string, unknown>;
   806→            try {
   807→              parsed = JSON.parse(data);
   808→            } catch {
   809→              continue; // Skip malformed JSON lines
   810→            }
   811→
   812→            if (parsed.type === 'progress') {
   813→              setEditProgress(parsed.value as number);
   814→            } else if (parsed.type === 'done') {
   815→              setEditedImage(parsed.editedImageUrl as string);
   816→              setEditProgress(100);
   817→              setEditCount((c) => c + 1);
   818→              // Refresh gallery
   819→              try {
   820→                const projectsRes = await fetch('/api/projects');
   821→                if (projectsRes.ok) {
   822→                  const projectsData = await projectsRes.json();
   823→                  setProjects(projectsData);
   824→                }
   825→              } catch { /* ignore gallery refresh failure */ }
   826→            } else if (parsed.type === 'error') {
   827→              throw new Error(parsed.message as string);
   828→            }
   829→          }
   830→        }
   831→      }
   832→    } catch (err: unknown) {
   833→      const message = err instanceof Error ? err.message : 'حدث خطأ أثناء التعديل';
   834→      setEditError(message);
   835→    } finally {
   836→      setIsEditing(false);
   837→      setSelectedTool(null);
   838→    }
   839→  }, [originalImage, editedImage, setIsEditing, setEditError, setEditedImage, setEditProgress, setProjects]);
   840→
   841→  const handleCustomEdit = useCallback(() => {
   842→    if (!customPrompt.trim()) return;
   843→    handleEdit(customPrompt.trim(), 'تعديل مخصص', 'custom');
   844→  }, [customPrompt, handleEdit]);
   845→
   846→  const handleNewImage = useCallback(() => {
   847→    resetEditor();
   848→    setView('home');
   849→  }, [resetEditor, setView]);
   850→
   851→  const handleResetToOriginal = useCallback(() => {
   852→    setEditedImage(null);
   853→    setEditCount(0);
   854→    setEditError(null);
   855→  }, [setEditedImage, setEditError]);
   856→
   857→  const handleReupload = useCallback(async (e: React.ChangeEvent<HTMLInputElement>) => {
   858→    const file = e.target.files?.[0];
   859→    if (!file || !file.type.startsWith('image/')) return;
   860→    const formData = new FormData();
   861→    formData.append('image', file);
   862→    try {
   863→      const res = await fetch('/api/upload', { method: 'POST', body: formData });
   864→      const data = await res.json();
   865→      if (!res.ok) throw new Error(data.error);
   866→      useAppStore.getState().setOriginalImage(data.imageUrl);
   867→      useAppStore.getState().setOriginalFileName(file.name);
   868→      useAppStore.getState().setEditedImage(null);
   869→      useAppStore.getState().setAnalysis(null);
   870→    } catch {}
   871→    e.target.value = '';
   872→  }, []);
   873→
   874→  const handleDownload = useCallback(() => {
   875→    if (!editedImage) return;
   876→    const a = document.createElement('a');
   877→    a.href = editedImage;
   878→    const ext = originalFileName?.split('.').pop() || 'png';
   879→    const baseName = originalFileName ? originalFileName.replace(/\.[^.]+$/, '') : 'image';
   880→    a.download = `Fouad-AI-${baseName}.${ext}`;
   881→    a.click();
   882→  }, [editedImage, originalFileName]);
   883→
   884→  return (
   885→    <main className="flex-1 px-4 py-6 max-w-7xl mx-auto w-full">
   886→      {/* Top bar */}
   887→      <div className="flex items-center justify-between mb-6">
   888→        <div className="flex items-center gap-2">
   889→          <Button variant="ghost" onClick={handleNewImage} className="gap-2">
   890→            <ChevronLeft className="w-4 h-4" />
   891→            صورة جديدة
   892→          </Button>
   893→          {editedImage && (
   894→            <Button variant="outline" size="sm" onClick={handleResetToOriginal} className="gap-1.5 text-xs">
   895→              <RotateCcw className="w-3.5 h-3.5" />
   896→              العودة للأصل
   897→            </Button>
   898→          )}
   899→          {editCount > 0 && (
   900→            <span className="text-xs text-muted-foreground bg-muted/50 px-2 py-1 rounded-full">
   901→              {editCount} تعديل{editCount > 1 ? 'ات' : ''}
   902→            </span>
   903→          )}
   904→        </div>
   905→        {editedImage && (
   906→          <Button onClick={handleDownload} className="gap-2">
   907→            <Download className="w-4 h-4" />
   908→            تحميل الصورة
   909→          </Button>
   910→        )}
   911→      </div>
   912→
   913→      <div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
   914→        {/* Image Preview (2/3 width on desktop) */}
   915→        <div className="lg:col-span-2">
   916→          <Card className="glass overflow-hidden">
   917→            <CardContent className="p-0 relative">
   918→              {/* Image display */}
   919→              <div className="relative min-h-[300px] sm:min-h-[400px] flex items-center justify-center bg-black/30">
   920→                {isEditing && (
   921→                  <div className="absolute inset-0 z-20 flex flex-col items-center justify-center bg-black/50 backdrop-blur-sm">
   922→                    <Loader2 className="w-12 h-12 text-primary animate-spin mb-4" />
   923→                    <p className="text-lg font-semibold mb-2">جارٍ التعديل بالذكاء الاصطناعي...</p>
   924→                    <Progress value={editProgress} className="w-48 h-2" />
   925→                    <p className="text-sm text-muted-foreground mt-2">{editProgress}%</p>
   926→                  </div>
   927→                )}
   928→
   929→                {editedImage ? (
   930→                  <ComparisonSlider original={originalImage!} edited={editedImage} />
   931→                ) : (
   932→                  <img
   933→                    src={originalImage!}
   934→                    alt="Original"
   935→                    className="max-w-full max-h-[70vh] object-contain mx-auto"
   936→                  />
   937→                )}
   938→              </div>
   939→
   940→              {/* Image info bar */}
   941→              <div className="p-3 border-t border-border/50 flex items-center justify-between text-sm text-muted-foreground">
   942→                <span className="truncate max-w-[60%]">{originalFileName || 'صورة'}</span>
   943→                <Button variant="ghost" size="sm" className="gap-1 text-xs h-8" onClick={() => fileInputRef.current?.click()}>
   944→                  <RotateCcw className="w-3 h-3" />
   945→                  تغيير الصورة
   946→                </Button>
   947→                <input ref={fileInputRef} type="file" accept="image/*" className="hidden" onChange={handleReupload} />
   948→              </div>
   949→            </CardContent>
   950→          </Card>
   951→
   952→          {/* Analysis section */}
   953→          <div className="mt-4">
   954→            <Button
   955→              variant="outline"
   956→              onClick={handleAnalyze}
   957→              disabled={isAnalyzing || !originalImage}
   958→              className="w-full gap-2 mb-3"
   959→            >
   960→              {isAnalyzing ? (
   961→                <Loader2 className="w-4 h-4 animate-spin" />
   962→              ) : (
   963→                <Eye className="w-4 h-4" />
   964→              )}
   965→              تحليل الصورة بالذكاء الاصطناعي
   966→            </Button>
   967→            <AnimatePresence>
   968→              {analysis && (
   969→                <motion.div
   970→                  initial={{ opacity: 0, height: 0 }}
   971→                  animate={{ opacity: 1, height: 'auto' }}
   972→                  exit={{ opacity: 0, height: 0 }}
   973→                >
   974→                  <Card className="glass">
   975→                    <CardContent className="p-4">
   976→                      <h3 className="text-sm font-semibold mb-2 flex items-center gap-2">
   977→                        <Eye className="w-4 h-4 text-primary" />
   978→                        نتيجة التحليل
   979→                      </h3>
   980→                      <p className="text-sm text-muted-foreground leading-relaxed whitespace-pre-wrap">{analysis}</p>
   981→                    </CardContent>
   982→                  </Card>
   983→                </motion.div>
   984→              )}
   985→            </AnimatePresence>
   986→          </div>
   987→        </div>
   988→
   989→        {/* Tools Panel (1/3 width on desktop) */}
   990→        <div className="lg:col-span-1 space-y-4">
   991→          {/* Quick Tools */}
   992→          <Card className="glass">
   993→            <CardContent className="p-4">
   994→              <h3 className="font-semibold mb-3 flex items-center gap-2">
   995→                <Wand2 className="w-4 h-4 text-primary" />
   996→                أدوات التحرير السريعة
   997→              </h3>
   998→              <div className="grid grid-cols-2 gap-2">
   999→                {EDIT_TOOLS.map((tool) => {
  1000→                  const Icon = tool.icon;
  1001→                  const isLoading = isEditing && selectedTool === tool.id;
  1002→                  return (
  1003→                    <button
  1004→                      key={tool.id}
  1005→                      onClick={() => {
  1006→                        if (isEditing) return;
  1007→                        setSelectedTool(tool.id);
  1008→                        handleEdit(tool.prompt, tool.label, 'quick-tool');
  1009→                      }}
  1010→                      disabled={isEditing}
  1011→                      className={`
  1012→                        tool-card relative flex flex-col items-center gap-2 p-3 rounded-xl
  1013→                        border border-border/50 text-center transition-all
  1014→                        ${isLoading ? 'ring-2 ring-primary' : 'hover:border-primary/40'}
  1015→                        ${isEditing ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer'}
  1016→                      `}
  1017→                    >
  1018→                      <div className={`w-10 h-10 rounded-lg bg-gradient-to-br ${tool.color} flex items-center justify-center`}>
  1019→                        {isLoading ? (
  1020→                          <Loader2 className="w-5 h-5 text-primary animate-spin" />
  1021→                        ) : (
  1022→                          <Icon className="w-5 h-5 text-foreground" />
  1023→                        )}
  1024→                      </div>
  1025→                      <span className="text-xs font-medium">{tool.label}</span>
  1026→                    </button>
  1027→                  );
  1028→                })}
  1029→              </div>
  1030→            </CardContent>
  1031→          </Card>
  1032→
  1033→          {/* Custom Prompt */}
  1034→          <Card className="glass">
  1035→            <CardContent className="p-4">
  1036→              <h3 className="font-semibold mb-3 flex items-center gap-2">
  1037→                <Pencil className="w-4 h-4 text-primary" />
  1038→                تعديل مخصص
  1039→              </h3>
  1040→              <Textarea
  1041→                value={customPrompt}
  1042→                onChange={(e) => setCustomPrompt(e.target.value)}
  1043→                placeholder="صِف التعديل الذي تريده... مثال: غيّر الخلفية إلى شاطئ عند الغروب"
  1044→                className="min-h-[100px] resize-none mb-3"
  1045→                disabled={isEditing}
  1046→              />
  1047→              <Button
  1048→                onClick={handleCustomEdit}
  1049→                disabled={isEditing || !customPrompt.trim()}
  1050→                className="w-full gap-2"
  1051→              >
  1052→                {isEditing ? (
  1053→                  <Loader2 className="w-4 h-4 animate-spin" />
  1054→                ) : (
  1055→                  <Sparkles className="w-4 h-4" />
  1056→                )}
  1057→                تطبيق التعديل
  1058→              </Button>
  1059→            </CardContent>
  1060→          </Card>
  1061→
  1062→          {/* Error display */}
  1063→          <AnimatePresence>
  1064→            {editError && (
  1065→              <motion.div
  1066→                initial={{ opacity: 0, y: 10 }}
  1067→                animate={{ opacity: 1, y: 0 }}
  1068→                exit={{ opacity: 0, y: -10 }}
  1069→              >
  1070→                <Card className="border-destructive/50 bg-destructive/10">
  1071→                  <CardContent className="p-4 flex items-start gap-3">
  1072→                    <X className="w-5 h-5 text-destructive mt-0.5 shrink-0" />
  1073→                    <div className="flex-1">
  1074→                      <p className="text-sm font-medium text-destructive">حدث خطأ</p>
  1075→                      <p className="text-xs text-muted-foreground mt-1">{editError}</p>
  1076→                    </div>
  1077→                    {lastEditArgs && (
  1078→                      <Button
  1079→                        variant="outline"
  1080→                        size="sm"
  1081→                        className="shrink-0 gap-1 text-xs h-8"
  1082→                        onClick={() => {
  1083→                          setEditError(null);
  1084→                          handleEdit(lastEditArgs.prompt, lastEditArgs.label, lastEditArgs.toolType);
  1085→                        }}
  1086→                      >
  1087→                        <RotateCcw className="w-3 h-3" />
  1088→                        إعادة المحاولة
  1089→                      </Button>
  1090→                    )}
  1091→                  </CardContent>
  1092→                </Card>
  1093→              </motion.div>
  1094→            )}
  1095→          </AnimatePresence>
  1096→        </div>
  1097→      </div>
  1098→    </main>
  1099→  );
  1100→}
  1101→
  1102→/* ─── Gallery View ─── */
  1103→function GalleryView() {
  1104→  const { projects, setProjects, setView, setOriginalImage, setOriginalFileName, setEditedImage, setAnalysis } = useAppStore();
  1105→  const [isLoading, setIsLoading] = useState(true);
  1106→
  1107→  useEffect(() => {
  1108→    const loadProjects = async () => {
  1109→      try {
  1110→        const res = await fetch('/api/projects');
  1111→        if (res.ok) {
  1112→          const data = await res.json();
  1113→          setProjects(data);
  1114→        }
  1115→      } catch {}
  1116→      setIsLoading(false);
  1117→    };
  1118→    loadProjects();
  1119→  }, [setProjects]);
  1120→
  1121→  const handleDelete = useCallback(async (id: string) => {
  1122→    try {
  1123→      const res = await fetch(`/api/projects/${id}`, { method: 'DELETE' });
  1124→      if (res.ok) {
  1125→        setProjects(projects.filter((p) => p.id !== id));
  1126→      }
  1127→    } catch {}
  1128→  }, [projects, setProjects]);
  1129→
  1130→  const handleOpen = useCallback((project: PhotoProject) => {
  1131→    const lastEdit = project.edits?.[project.edits.length - 1];
  1132→    if (lastEdit?.editedPath) {
  1133→      setOriginalImage(lastEdit.originalPath);
  1134→      setEditedImage(lastEdit.editedPath);
  1135→      setOriginalFileName(project.title);
  1136→      setAnalysis(null);
  1137→      setView('editor');
  1138→    } else if (lastEdit) {
  1139→      setOriginalImage(lastEdit.originalPath);
  1140→      setEditedImage(null);
  1141→      setOriginalFileName(project.title);
  1142→      setAnalysis(null);
  1143→      setView('editor');
  1144→    }
  1145→  }, [setOriginalImage, setEditedImage, setOriginalFileName, setAnalysis, setView]);
  1146→
  1147→  if (isLoading) {
  1148→    return (
  1149→      <main className="flex-1 flex items-center justify-center">
  1150→        <Loader2 className="w-8 h-8 text-primary animate-spin" />
  1151→      </main>
  1152→    );
  1153→  }
  1154→
  1155→  return (
  1156→    <main className="flex-1 px-4 py-8 max-w-6xl mx-auto w-full">
  1157→      <motion.div
  1158→        initial={{ opacity: 0, y: -10 }}
  1159→        animate={{ opacity: 1, y: 0 }}
  1160→        className="text-center mb-8"
  1161→      >
  1162→        <h2 className="text-3xl font-bold mb-2">
  1163→          <span className="gradient-text">المعرض</span>
  1164→        </h2>
  1165→        <p className="text-muted-foreground">جميع مشاريع تعديل الصور السابقة</p>
  1166→      </motion.div>
  1167→
  1168→      {projects.length === 0 ? (
  1169→        <motion.div
  1170→          initial={{ opacity: 0 }}
  1171→          animate={{ opacity: 1 }}
  1172→          className="text-center py-20"
  1173→        >
  1174→          <div className="w-20 h-20 rounded-full bg-muted/30 flex items-center justify-center mx-auto mb-4">
  1175→            <ImageIcon className="w-10 h-10 text-muted-foreground" />
  1176→          </div>
  1177→          <p className="text-lg text-muted-foreground mb-4">لا توجد مشاريع بعد</p>
  1178→          <Button onClick={() => setView('home')} className="gap-2">
  1179→            <Upload className="w-4 h-4" />
  1180→            ابدأ بتعديل صورة
  1181→          </Button>
  1182→        </motion.div>
  1183→      ) : (
  1184→        <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
  1185→          {projects.map((project, i) => {
  1186→            const lastEdit = project.edits?.[project.edits.length - 1];
  1187→            const thumbnail = lastEdit?.editedPath || lastEdit?.originalPath || '';
  1188→            return (
  1189→              <motion.div
  1190→                key={project.id}
  1191→                initial={{ opacity: 0, y: 20 }}
  1192→                animate={{ opacity: 1, y: 0 }}
  1193→                transition={{ delay: i * 0.05 }}
  1194→              >
  1195→                <Card className="glass overflow-hidden group cursor-pointer hover:border-primary/40 transition-all" onClick={() => handleOpen(project)}>
  1196→                  <div className="aspect-video bg-black/30 relative overflow-hidden">
  1197→                    {thumbnail ? (
  1198→                      <img src={thumbnail} alt={project.title} className="w-full h-full object-cover" />
  1199→                    ) : (
  1200→                      <div className="w-full h-full flex items-center justify-center">
  1201→                        <ImageIcon className="w-8 h-8 text-muted-foreground" />
  1202→                      </div>
  1203→                    )}
  1204→                    <div className="absolute inset-0 bg-black/0 group-hover:bg-black/30 transition-colors flex items-center justify-center">
  1205→                      <span className="opacity-0 group-hover:opacity-100 transition-opacity bg-white/20 backdrop-blur-sm px-3 py-1.5 rounded-lg text-sm font-medium">
  1206→                        فتح المشروع
  1207→                      </span>
  1208→                    </div>
  1209→                  </div>
  1210→                  <CardContent className="p-3 flex items-center justify-between">
  1211→                    <div>
  1212→                      <p className="font-medium text-sm truncate">{project.title}</p>
  1213→                      <p className="text-xs text-muted-foreground">
  1214→                        {new Date(project.createdAt).toLocaleDateString('ar-EG')}
  1215→                        {project.edits?.length ? ` — ${project.edits.length} تعديل` : ''}
  1216→                      </p>
  1217→                    </div>
  1218→                    <Button
  1219→                      variant="ghost"
  1220→                      size="icon"
  1221→                      className="h-8 w-8 text-muted-foreground hover:text-destructive shrink-0"
  1222→                      onClick={(e) => {
  1223→                        e.stopPropagation();
  1224→                        handleDelete(project.id);
  1225→                      }}
  1226→                    >
  1227→                      <Trash2 className="w-4 h-4" />
  1228→                    </Button>
  1229→                  </CardContent>
  1230→                </Card>
  1231→              </motion.div>
  1232→            );
  1233→          })}
  1234→        </div>
  1235→      )}
  1236→    </main>
  1237→  );
  1238→}
  1239→
  1240→/* ─── Generate View ─── */
  1241→const SIZE_OPTIONS = [
  1242→  { id: 'square', label: 'مربع', icon: Square, desc: '1024×1024', color: 'from-primary/20 to-primary/5' },
  1243→  { id: 'portrait', label: 'عمودي', icon: RectangleVertical, desc: '864×1152', color: 'from-amber-500/20 to-amber-600/5' },
  1244→  { id: 'landscape', label: 'أفقي', icon: Monitor, desc: '1344×768', color: 'from-emerald-500/20 to-emerald-600/5' },
  1245→  { id: 'wide', label: 'عريض', icon: Monitor, desc: '1440×720', color: 'from-violet-500/20 to-violet-600/5' },
  1246→];
  1247→
  1248→function GenerateView() {
  1249→  const { setOriginalImage, setOriginalFileName, setView, setEditedImage, setAnalysis } = useAppStore();
  1250→  const [prompt, setPrompt] = useState('');
  1251→  const [selectedSize, setSelectedSize] = useState('square');
  1252→  const [isGenerating, setIsGenerating] = useState(false);
  1253→  const [generatedImage, setGeneratedImage] = useState<string | null>(null);
  1254→  const [error, setError] = useState<string | null>(null);
  1255→  const [progress, setProgress] = useState(0);
  1256→  const [progressMsg, setProgressMsg] = useState('');
  1257→
  1258→  const pollIntervalRef = useRef<ReturnType<typeof setInterval> | null>(null);
  1259→
  1260→  const handleGenerate = useCallback(async () => {
  1261→    if (!prompt.trim() || isGenerating) return;
  1262→    setIsGenerating(true);
  1263→    setError(null);
  1264→    setGeneratedImage(null);
  1265→    setProgress(0);
  1266→    setProgressMsg('جارٍ البدء...');
  1267→
  1268→    try {
  1269→      // Step 1: Start the job (returns immediately)
  1270→      const startRes = await fetch('/api/generate', {
  1271→        method: 'POST',
  1272→        headers: { 'Content-Type': 'application/json' },
  1273→        body: JSON.stringify({ prompt: prompt.trim(), sizeId: selectedSize }),
  1274→      });
  1275→
  1276→      const startData = await startRes.json();
  1277→
  1278→      if (!startRes.ok || startData.error) {
  1279→        throw new Error(startData.error || 'حدث خطأ غير متوقع');
  1280→      }
  1281→
  1282→      const { jobId } = startData;
  1283→      if (!jobId) {
  1284→        throw new Error('لم يتم إنشاء العملية');
  1285→      }
  1286→
  1287→      // Step 2: Poll every 3 seconds until done or error
  1288→      const result = await new Promise<{ imageUrl: string }>((resolve, reject) => {
  1289→        let attempts = 0;
  1290→        const maxAttempts = 120; // 6 minutes max
  1291→
  1292→        pollIntervalRef.current = setInterval(async () => {
  1293→          attempts++;
  1294→
  1295→          if (attempts > maxAttempts) {
  1296→            if (pollIntervalRef.current) clearInterval(pollIntervalRef.current);
  1297→            pollIntervalRef.current = null;
  1298→            reject(new Error('انتهت المهلة. حاول مرة أخرى.'));
  1299→            return;
  1300→          }
  1301→
  1302→          try {
  1303→            const pollRes = await fetch(`/api/generate?jobId=${jobId}`);
  1304→            const pollData = await pollRes.json();
  1305→
  1306→            if (pollData.error && !pollData.status) {
  1307→              if (pollIntervalRef.current) clearInterval(pollIntervalRef.current);
  1308→              pollIntervalRef.current = null;
  1309→              reject(new Error(pollData.error));
  1310→              return;
  1311→            }
  1312→
  1313→            // Update progress
  1314→            if (pollData.progress !== undefined) {
  1315→              setProgress((prev) => Math.max(prev, pollData.progress));
  1316→            }
  1317→            if (pollData.message) {
  1318→              setProgressMsg(pollData.message);
  1319→            }
  1320→
  1321→            // Check terminal states
  1322→            if (pollData.status === 'done' && pollData.imageUrl) {
  1323→              if (pollIntervalRef.current) clearInterval(pollIntervalRef.current);
  1324→              pollIntervalRef.current = null;
  1325→              resolve({ imageUrl: pollData.imageUrl });
  1326→            } else if (pollData.status === 'error') {
  1327→              if (pollIntervalRef.current) clearInterval(pollIntervalRef.current);
  1328→              pollIntervalRef.current = null;
  1329→              reject(new Error(pollData.error || 'فشل توليد الصورة'));
  1330→            }
  1331→          } catch (pollErr: unknown) {
  1332→            // Network error on a single poll — don't abort, just retry
  1333→            console.error('[GEN] Poll error, retrying...', pollErr);
  1334→          }
  1335→        }, 3000);
  1336→      });
  1337→
  1338→      setGeneratedImage(result.imageUrl);
  1339→    } catch (err: unknown) {
  1340→      setError(err instanceof Error ? err.message : 'حدث خطأ');
  1341→    } finally {
  1342→      if (pollIntervalRef.current) {
  1343→        clearInterval(pollIntervalRef.current);
  1344→        pollIntervalRef.current = null;
  1345→      }
  1346→      setIsGenerating(false);
  1347→    }
  1348→  }, [prompt, selectedSize, isGenerating]);
  1349→
  1350→  // Cleanup polling on unmount
  1351→  useEffect(() => {
  1352→    return () => {
  1353→      if (pollIntervalRef.current) {
  1354→        clearInterval(pollIntervalRef.current);
  1355→        pollIntervalRef.current = null;
  1356→      }
  1357→    };
  1358→  }, []);
  1359→
  1360→  const handleSendToEditor = useCallback(() => {
  1361→    if (!generatedImage) return;
  1362→    setOriginalImage(generatedImage);
  1363→    setOriginalFileName('Fouad-AI-generated.png');
  1364→    setEditedImage(null);
  1365→    setAnalysis(null);
  1366→    setView('editor');
  1367→  }, [generatedImage, setOriginalImage, setOriginalFileName, setEditedImage, setAnalysis, setView]);
  1368→
  1369→  const handleDownload = useCallback(() => {
  1370→    if (!generatedImage) return;
  1371→    const a = document.createElement('a');
  1372→    a.href = generatedImage;
  1373→    a.download = 'Fouad-AI-generated.png';
  1374→    a.click();
  1375→  }, [generatedImage]);
  1376→
  1377→  return (
  1378→    <main className="flex-1 px-4 py-6 max-w-5xl mx-auto w-full">
  1379→      <motion.div
  1380→        initial={{ opacity: 0, y: -10 }}
  1381→        animate={{ opacity: 1, y: 0 }}
  1382→        className="text-center mb-8"
  1383→      >
  1384→        <h2 className="text-3xl font-bold mb-2">
  1385→          <span className="gradient-text">رسم الصور بالذكاء</span>
  1386→        </h2>
  1387→        <p className="text-muted-foreground">صِف الصورة التي تريدها وسنرسمها لك</p>
  1388→      </motion.div>
  1389→
  1390→      <div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
  1391→        {/* Left: Input */}
  1392→        <div className="space-y-4">
  1393→          {/* Prompt */}
  1394→          <Card className="glass">
  1395→            <CardContent className="p-4">
  1396→              <h3 className="font-semibold mb-3 flex items-center gap-2">
  1397→                <Pencil className="w-4 h-4 text-primary" />
  1398→                وصف الصورة
  1399→              </h3>
  1400→              <Textarea
  1401→                value={prompt}
  1402→                onChange={(e) => setPrompt(e.target.value)}
  1403→                placeholder="مثال: قطة جميلة تجلس في حديقة مليئة بالزهور عند الغروب..."
  1404→                className="min-h-[120px] resize-none mb-3"
  1405→                disabled={isGenerating}
  1406→              />
  1407→              <p className="text-xs text-muted-foreground mb-3">
  1408→                يمكنك الكتابة بالعربية أو الإنجليزية
  1409→              </p>
  1410→
  1411→              {/* Size selector */}
  1412→              <h4 className="text-sm font-medium mb-2">حجم الصورة</h4>
  1413→              <div className="grid grid-cols-4 gap-2">
  1414→                {SIZE_OPTIONS.map((s) => {
  1415→                  const Icon = s.icon;
  1416→                  return (
  1417→                    <button
  1418→                      key={s.id}
  1419→                      onClick={() => setSelectedSize(s.id)}
  1420→                      disabled={isGenerating}
  1421→                      className={`
  1422→                        flex flex-col items-center gap-1.5 p-2.5 rounded-xl border text-center transition-all
  1423→                        ${selectedSize === s.id
  1424→                          ? 'border-primary bg-primary/10 ring-1 ring-primary/30'
  1425→                          : 'border-border/50 hover:border-primary/30'}
  1426→                        ${isGenerating ? 'opacity-50 cursor-not-allowed' : 'cursor-pointer'}
  1427→                      `}
  1428→                    >
  1429→                      <Icon className="w-4 h-4 text-foreground" />
  1430→                      <span className="text-xs font-medium">{s.label}</span>
  1431→                      <span className="text-[10px] text-muted-foreground">{s.desc}</span>
  1432→                    </button>
  1433→                  );
  1434→                })}
  1435→              </div>
  1436→
  1437→              {/* Generate button */}
  1438→              <Button
  1439→                onClick={handleGenerate}
  1440→                disabled={isGenerating || !prompt.trim()}
  1441→                className="w-full gap-2 mt-4"
  1442→                size="lg"
  1443→              >
  1444→                {isGenerating ? (
  1445→                  <Loader2 className="w-5 h-5 animate-spin" />
  1446→                ) : (
  1447→                  <WandSparkles className="w-5 h-5" />
  1448→                )}
  1449→                {isGenerating ? 'جارٍ الرسم...' : 'ارسم الصورة'}
  1450→              </Button>
  1451→            </CardContent>
  1452→          </Card>
  1453→
  1454→          {/* Error */}
  1455→          <AnimatePresence>
  1456→            {error && (
  1457→              <motion.div initial={{ opacity: 0, y: 10 }} animate={{ opacity: 1, y: 0 }} exit={{ opacity: 0, y: -10 }}>
  1458→                <Card className="border-destructive/50 bg-destructive/10">
  1459→                  <CardContent className="p-4 flex items-start gap-3">
  1460→                    <X className="w-5 h-5 text-destructive mt-0.5 shrink-0" />
  1461→                    <div className="flex-1">
  1462→                      <p className="text-sm font-medium text-destructive">خطأ</p>
  1463→                      <p className="text-xs text-muted-foreground mt-1">{error}</p>
  1464→                    </div>
  1465→                    <Button
  1466→                      variant="outline"
  1467→                      size="sm"
  1468→                      className="shrink-0 gap-1 text-xs"
  1469→                      onClick={() => handleGenerate()}
  1470→                    >
  1471→                      <RotateCcw className="w-3 h-3" />
  1472→                      إعادة المحاولة
  1473→                    </Button>
  1474→                  </CardContent>
  1475→                </Card>
  1476→              </motion.div>
  1477→            )}
  1478→          </AnimatePresence>
  1479→        </div>
  1480→
  1481→        {/* Right: Result */}
  1482→        <div>
  1483→          <Card className="glass overflow-hidden">
  1484→            <CardContent className="p-0">
  1485→              <div className="relative min-h-[400px] flex items-center justify-center bg-black/30">
  1486→                {isGenerating && (
  1487→                  <div className="absolute inset-0 z-10 flex flex-col items-center justify-center bg-black/50 backdrop-blur-sm gap-4 px-8">
  1488→                    <Loader2 className="w-16 h-16 text-primary animate-spin" />
  1489→                    <p className="text-sm font-medium animate-pulse">{progressMsg || 'جارٍ رسم الصورة بالذكاء الاصطناعي...'}</p>
  1490→                    <Progress value={progress} className="w-64 h-2" />
  1491→                    <p className="text-xs text-muted-foreground">{progress}%</p>
  1492→                  </div>
  1493→                )}
  1494→
  1495→                {generatedImage ? (
  1496→                  <img
  1497→                    src={generatedImage}
  1498→                    alt="Generated"
  1499→                    className="w-full h-auto block"
  1500→                  />
  1501→                ) : !isGenerating ? (
  1502→                  <div className="flex flex-col items-center gap-4 py-16">
  1503→                    <div className="w-20 h-20 rounded-full bg-muted/20 flex items-center justify-center">
  1504→                      <WandSparkles className="w-10 h-10 text-muted-foreground/50" />
  1505→                    </div>
  1506→                    <p className="text-muted-foreground text-center px-4">
  1507→                      الصورة المرسومة ستظهر هنا
  1508→                    </p>
  1509→                  </div>
  1510→                ) : null}
  1511→              </div>
  1512→
  1513→              {/* Action buttons */}
  1514→              {generatedImage && (
  1515→                <div className="p-3 border-t border-border/50 flex items-center gap-2">
  1516→                  <Button onClick={handleSendToEditor} className="flex-1 gap-2" size="sm">
  1517→                    <ArrowRight className="w-4 h-4" />
  1518→                    تعديل الصورة
  1519→                  </Button>
  1520→                  <Button onClick={handleDownload} variant="outline" className="gap-2" size="sm">
  1521→                    <Download className="w-4 h-4" />
  1522→                    تحميل
  1523→                  </Button>
  1524→                </div>
  1525→              )}
  1526→            </CardContent>
  1527→          </Card>
  1528→
  1529→          {/* Example prompts */}
  1530→          {!generatedImage && !isGenerating && (
  1531→            <Card className="glass mt-4">
  1532→              <CardContent className="p-4">
  1533→                <h4 className="text-sm font-medium mb-3 flex items-center gap-2">
  1534→                  <Sparkles className="w-4 h-4 text-primary" />
  1535→                  أفكار للتجربة
  1536→                </h4>
  1537→                <div className="flex flex-wrap gap-2">
  1538→                  {[
  1539→                    'غروب على شاطئ بصخور ملساء',
  1540→                    'مدينة مستقبلية بالليل',
  1541→                    'طائر فيلمنق زاهي الألوان',
  1542→                    'قرية جبلية وسط الضباب',
  1543→                  ].map((example) => (
  1544→                    <button
  1545→                      key={example}
  1546→                      onClick={() => setPrompt(example)}
  1547→                      className="text-xs px-3 py-1.5 rounded-full border border-border/50 hover:border-primary/40 hover:bg-primary/5 transition-all cursor-pointer"
  1548→                    >
  1549→                      {example}
  1550→                    </button>
  1551→                  ))}
  1552→                </div>
  1553→              </CardContent>
  1554→            </Card>
  1555→          )}
  1556→        </div>
  1557→      </div>
  1558→    </main>
  1559→  );
  1560→}
  1561→
  1562→/* ─── Main Client Component ─── */
  1563→export default function HomeClient() {
  1564→  const { currentView, editError, setEditError } = useAppStore();
  1565→  const [bannerAdminOpen, setBannerAdminOpen] = useState(false);
  1566→
  1567→  // Dismiss errors on click outside
  1568→  useEffect(() => {
  1569→    if (editError) {
  1570→      const timer = setTimeout(() => setEditError(null), 8000);
  1571→      return () => clearTimeout(timer);
  1572→    }
  1573→  }, [editError, setEditError]);
  1574→
  1575→  return (
  1576→    <div className="min-h-screen flex flex-col">
  1577→      <Header onOpenBannerAdmin={() => setBannerAdminOpen(true)} />
  1578→      <BannerAdmin open={bannerAdminOpen} onOpenChange={setBannerAdminOpen} />
  1579→      <AnimatePresence mode="wait">
  1580→        {currentView === 'home' && (
  1581→          <motion.div key="home" initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }} className="flex-1">
  1582→            <HomeView />
  1583→          </motion.div>
  1584→        )}
  1585→        {currentView === 'editor' && (
  1586→          <motion.div key="editor" initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }} className="flex-1 flex flex-col">
  1587→            <EditorView />
  1588→          </motion.div>
  1589→        )}
  1590→        {currentView === 'gallery' && (
  1591→          <motion.div key="gallery" initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }} className="flex-1">
  1592→            <GalleryView />
  1593→          </motion.div>
  1594→        )}
  1595→        {currentView === 'generate' && (
  1596→          <motion.div key="generate" initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }} className="flex-1 flex flex-col">
  1597→            <GenerateView />
  1598→          </motion.div>
  1599→        )}
  1600→      </AnimatePresence>
  1601→      <Footer />
  1602→    </div>
  1603→  );
  1604→}