/* global React, I, fmt0, statusTone, SEED, Badge, Button, api */
// Screen primitives + shared chrome for VRV Quoter

const { useState, useRef, useEffect, useCallback } = React;

// ─── Swipeable Card Component ────────────────────────────────────
function SwipeableCard({ children, onDelete, deleteLabel = 'Delete' }) {
  const containerRef = useRef(null);
  const [offsetX, setOffsetX] = useState(0);
  const [isDragging, setIsDragging] = useState(false);
  const [showDelete, setShowDelete] = useState(false);
  const startX = useRef(0);
  const currentX = useRef(0);
  const hasMoved = useRef(false);
  const lastSwipeEnd = useRef(0); // Timestamp of last swipe end

  const DELETE_THRESHOLD = 50; // pixels to swipe to reveal delete
  const DELETE_WIDTH = 80;
  const CLICK_THRESHOLD = 10; // pixels - if moved less than this, it's a click
  const CLICK_DELAY = 100; // ms to ignore clicks after swipe

  // Get X position from touch or mouse event
  const getClientX = (e) => {
    if (e.touches && e.touches[0]) return e.touches[0].clientX;
    return e.clientX;
  };

  const handleStart = (e) => {
    startX.current = getClientX(e);
    currentX.current = startX.current;
    hasMoved.current = false;
    setIsDragging(true);
  };

  const handleMove = (e) => {
    if (!isDragging) return;
    currentX.current = getClientX(e);
    const diff = currentX.current - startX.current;

    // Mark as moved if beyond click threshold
    if (Math.abs(diff) > CLICK_THRESHOLD) {
      hasMoved.current = true;
    }

    // Only allow swiping left (negative diff)
    if (diff < 0) {
      setOffsetX(Math.max(diff, -DELETE_WIDTH - 20));
    } else if (showDelete) {
      // If delete is showing, allow swiping right to close
      setOffsetX(Math.min(0, -DELETE_WIDTH + diff));
    }
  };

  const handleEnd = (e) => {
    if (!isDragging) return;
    setIsDragging(false);
    const diff = currentX.current - startX.current;

    // Record swipe end time if user actually moved
    if (hasMoved.current) {
      lastSwipeEnd.current = Date.now();
    }

    if (diff < -DELETE_THRESHOLD) {
      // Swiped enough to show delete
      setOffsetX(-DELETE_WIDTH);
      setShowDelete(true);
    } else if (showDelete && diff > DELETE_THRESHOLD) {
      // Swiped right to close
      setOffsetX(0);
      setShowDelete(false);
    } else if (!hasMoved.current) {
      // It was a tap/click, not a swipe - let the click through
      // Don't change anything
    } else {
      // Snap back
      setOffsetX(0);
      if (!showDelete) setShowDelete(false);
    }
  };

  // Prevent click if user was swiping
  const handleClick = (e) => {
    const recentSwipe = (Date.now() - lastSwipeEnd.current) < CLICK_DELAY;

    // If user swiped (not tapped), block the click but don't hide delete
    if (hasMoved.current || recentSwipe) {
      e.stopPropagation();
      e.stopImmediatePropagation();
      e.preventDefault();
      hasMoved.current = false;
      return;
    }

    // If delete is showing and user tapped the card (not the delete button), hide it
    if (showDelete) {
      e.stopPropagation();
      e.stopImmediatePropagation();
      e.preventDefault();
      setOffsetX(0);
      setShowDelete(false);
    }
  };

  const handleDelete = (e) => {
    e.stopPropagation();
    e.preventDefault();
    setOffsetX(0);
    setShowDelete(false);
    if (onDelete) onDelete();
  };

  return (
    <div ref={containerRef} style={{ position: 'relative', overflow: 'hidden', borderRadius: 8 }}>
      {/* Delete button behind */}
      <div style={{
        position: 'absolute',
        right: 0,
        top: 0,
        bottom: 0,
        width: DELETE_WIDTH,
        background: '#EF4444',
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
        borderRadius: '0 8px 8px 0',
      }}>
        <button
          onClick={handleDelete}
          style={{
            background: 'transparent',
            border: 0,
            color: '#fff',
            fontFamily: 'inherit',
            fontSize: 13,
            fontWeight: 600,
            cursor: 'pointer',
            padding: '8px 12px',
            display: 'flex',
            flexDirection: 'column',
            alignItems: 'center',
            gap: 4,
          }}
        >
          <I.Trash size={18} />
          {deleteLabel}
        </button>
      </div>

      {/* Main card content */}
      <div
        onTouchStart={handleStart}
        onTouchMove={handleMove}
        onTouchEnd={handleEnd}
        onMouseDown={handleStart}
        onMouseMove={isDragging ? handleMove : undefined}
        onMouseUp={handleEnd}
        onMouseLeave={isDragging ? handleEnd : undefined}
        onClickCapture={handleClick}
        style={{
          transform: `translateX(${offsetX}px)`,
          transition: isDragging ? 'none' : 'transform 0.2s ease-out',
          position: 'relative',
          zIndex: 1,
          background: '#262626',
          userSelect: 'none',
        }}
      >
        {children}
      </div>
    </div>
  );
}

// ─── Phone-frame app shell ────────────────────────────────────────
function PhoneShell({ children, title, subtitle, onBack, right, scrollable = true, bg, progress }) {
  return (
    <div style={{ width: '100%', height: '100%', position: 'relative', background: bg || '#171717', overflow: 'hidden', display: 'flex', flexDirection: 'column' }}>
      <div style={{
        height: 56, flex: '0 0 56px', display: 'flex', alignItems: 'center',
        padding: '0 8px', borderBottom: '1px solid #262626',
        background: 'rgba(23,23,23,0.92)', backdropFilter: 'blur(20px)',
        WebkitBackdropFilter: 'blur(20px)', position: 'relative', zIndex: 5,
        marginTop: 62,
      }}>
        <div style={{ width: 40, display: 'flex', justifyContent: 'flex-start' }}>
          {onBack &&
          <button onClick={onBack} aria-label="Back" style={{
            width: 36, height: 36, borderRadius: 6, border: 0, background: 'transparent',
            color: '#fff', display: 'flex', alignItems: 'center', justifyContent: 'center', cursor: 'pointer'
          }}><I.ChevronLeft size={22} /></button>
          }
        </div>
        <div style={{ flex: 1, textAlign: 'center', color: '#fff', fontSize: 15, fontWeight: 600, letterSpacing: '-0.2px' }}>
          {title}
          {subtitle && <div style={{ color: '#B8B8B8', fontSize: 12, fontWeight: 400, marginTop: 1, fontVariantNumeric: 'tabular-nums' }}>{subtitle}</div>}
        </div>
        <div style={{ width: 40, display: 'flex', justifyContent: 'flex-end', gap: 4 }}>{right}</div>
      </div>
      {typeof progress === 'number' && progress > 0 && (
        <div style={{ height: 3, background: '#2C2C2C', position: 'relative', flex: '0 0 3px' }}>
          <div style={{
            position: 'absolute', top: 0, left: 0, height: '100%',
            width: `${Math.min(100, Math.max(0, progress * 100))}%`,
            background: '#FEC230',
            transition: 'width .35s cubic-bezier(.2,.8,.2,1)',
          }}/>
        </div>
      )}
      <div style={{ flex: 1, minHeight: 0, overflowY: scrollable ? 'auto' : 'hidden', WebkitOverflowScrolling: 'touch' }}>
        {children}
      </div>
    </div>);

}

// ─── Login ────────────────────────────────────────────────────────
function LoginScreen({ onLogin, authError }) {
  const [email, setEmail] = useState('');
  const [pw, setPw] = useState('');
  const [show, setShow] = useState(false);
  const [busy, setBusy] = useState(false);
  const [error, setError] = useState(null);

  // Update error from prop
  useEffect(() => {
    if (authError) {
      setError(authError);
      setBusy(false);
    }
  }, [authError]);

  const submit = async (e) => {
    e?.preventDefault();
    if (!email || !pw) {
      setError('Please enter email and password');
      return;
    }
    setBusy(true);
    setError(null);

    try {
      const result = await onLogin(email, pw);
      if (!result.success) {
        setError(result.error || 'Login failed');
        setBusy(false);
      }
      // On success, App will navigate to dashboard
    } catch (err) {
      setError(err.message || 'Login failed');
      setBusy(false);
    }
  };

  return (
    <div style={{ width: '100%', height: '100%', position: 'relative', background: '#171717', overflow: 'hidden' }}>
      {/* subtle yellow glow background */}
      <div style={{
        position: 'absolute', top: -120, left: -120, width: 380, height: 380, borderRadius: '50%',
        background: 'radial-gradient(circle, rgba(254,194,48,0.18), transparent 60%)', pointerEvents: 'none'
      }} />
      <div style={{
        position: 'absolute', bottom: -160, right: -120, width: 380, height: 380, borderRadius: '50%',
        background: 'radial-gradient(circle, rgba(220,108,61,0.14), transparent 60%)', pointerEvents: 'none'
      }} />

      <div style={{ position: 'relative', height: '100%', display: 'flex', flexDirection: 'column', padding: '40px 24px 24px' }}>
        {/* Logo */}
        <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginTop: 32 }}>
          <img src="assets/logo.png" alt="TRAiDMIN" style={{ height: 28, width: 'auto' }} />
        </div>

        <div style={{ flex: 1, display: 'flex', flexDirection: 'column', justifyContent: 'center', gap: 6 }}>
          <div style={{ color: '#B8B8B8', fontSize: 13, fontWeight: 500, letterSpacing: '0.04em', textTransform: 'uppercase' }}>VRV Quoter</div>
          <div style={{ color: '#fff', fontSize: 26, fontWeight: 700, lineHeight: '32px', letterSpacing: '-0.5px', marginTop: 2 }}>
            Sign in to <span style={{ color: '#FEC230' }}>your</span><br />quoting workspace
          </div>
          <div style={{ color: '#B8B8B8', fontSize: 14, lineHeight: '22px', marginTop: 8, marginBottom: 28 }}>
            Turn manufacturer VRV/VRF quotes into customer-ready commercial quotes in minutes.
          </div>

          {/* Error message */}
          {error && (
            <div style={{
              padding: '10px 12px', background: 'rgba(239,68,68,0.12)',
              border: '1px solid rgba(239,68,68,0.32)', borderRadius: 8,
              marginBottom: 16, display: 'flex', gap: 10, alignItems: 'center',
            }}>
              <I.AlertCircle size={16} color="#EF4444" />
              <div style={{ color: '#EF4444', fontSize: 13 }}>{error}</div>
            </div>
          )}

          <form onSubmit={submit} style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
            <Field label="Email">
              <input
                type="email"
                value={email}
                onChange={(e) => setEmail(e.target.value)}
                placeholder="you@company.com"
                autoComplete="email"
                style={inputStyle}
              />
            </Field>
            <Field label="Password">
              <div style={{ position: 'relative' }}>
                <input
                  type={show ? 'text' : 'password'}
                  value={pw}
                  onChange={(e) => setPw(e.target.value)}
                  placeholder="Enter your password"
                  autoComplete="current-password"
                  style={{ ...inputStyle, paddingRight: 44 }}
                />
                <button type="button" onClick={() => setShow(!show)} aria-label={show ? 'Hide password' : 'Show password'} style={{
                  position: 'absolute', right: 8, top: '50%', transform: 'translateY(-50%)',
                  width: 32, height: 32, display: 'flex', alignItems: 'center', justifyContent: 'center',
                  background: 'transparent', border: 0, color: '#B8B8B8', cursor: 'pointer', padding: 0,
                }}>
                  {show ? <I.EyeOff size={18} /> : <I.Eye size={18} />}
                </button>
              </div>
            </Field>
            <div style={{ height: 8 }} />
            <Button variant="primary" full onClick={submit} disabled={busy}>
              {busy ? (
                <span style={{ display: 'flex', alignItems: 'center', gap: 8, justifyContent: 'center' }}>
                  <span style={{
                    width: 16, height: 16, border: '2px solid rgba(0,0,0,0.2)',
                    borderTopColor: '#000', borderRadius: '50%',
                    animation: 'vrvSpin 0.8s linear infinite',
                  }}/>
                  Signing in...
                </span>
              ) : 'Sign in'}
            </Button>
          </form>
        </div>

        <div style={{ color: '#808080', fontSize: 11, textAlign: 'center', lineHeight: '18px' }}>
          v1.4.0 · TRAiDMIN VRV Quoter
        </div>
      </div>
    </div>);

}

const inputStyle = {
  width: '100%', height: 44, padding: '0 14px', borderRadius: 6,
  background: '#262626', border: '1px solid #404040',
  color: '#fff', fontSize: 14, fontFamily: 'inherit', outline: 'none',
  boxSizing: 'border-box'
};

function Field({ label, children, right }) {
  return (
    <label style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
      <span style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', color: '#B8B8B8', fontSize: 12, fontWeight: 500 }}>
        <span>{label}</span>{right}
      </span>
      {children}
    </label>);

}

// ─── Dashboard ────────────────────────────────────────────────────
function DashboardScreen({ onCreate, onOpenQuote, quotes: propQuotes, onRefresh, onLogout, currentUser }) {
  // Use prop quotes only - no fallback to seed data, ensure it's an array
  const quotes = Array.isArray(propQuotes) ? propQuotes : [];
  console.log('[Dashboard] Received quotes:', quotes.length, quotes);
  const totalValue = quotes.reduce((a, q) => a + (q.final_price || q.total || 0), 0);
  const [profileOpen, setProfileOpen] = useState(false);

  // Load quotes on mount
  useEffect(() => {
    if (onRefresh) {
      onRefresh();
    }
  }, []);

  // Get user info for display
  const userName = currentUser?.name || currentUser?.email?.split('@')[0] || 'User';
  const userEmail = currentUser?.email || '';
  const userInitial = userName.charAt(0).toUpperCase();

  // Get greeting based on time of day
  const getGreeting = () => {
    const hour = new Date().getHours();
    if (hour < 12) return 'Morning';
    if (hour < 18) return 'Afternoon';
    return 'Evening';
  };

  // Delete quote handler
  const handleDeleteQuote = async (quoteId) => {
    if (!quoteId || typeof api === 'undefined') return;
    try {
      await api.deleteQuote(quoteId);
      // Refresh the list after deletion
      if (onRefresh) onRefresh();
    } catch (err) {
      console.error('Failed to delete quote:', err);
      alert('Failed to delete quote: ' + err.message);
    }
  };

  // Format date
  const formatDate = () => {
    const d = new Date();
    const days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
    const months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
    return `${days[d.getDay()]}, ${d.getDate()} ${months[d.getMonth()]}`;
  };

  return (
    <PhoneShell
      title="VRV/VRF Quotes"
      right={<button onClick={() => setProfileOpen(true)} style={navBtn}><I.User size={20} /></button>}>

      <div style={{ padding: '16px 16px 120px' }}>
        {/* Greeting */}
        <div style={{ marginBottom: 12 }}>
          <div style={{ color: '#B8B8B8', fontSize: 12 }}>{formatDate()}</div>
          <div style={{ color: '#fff', fontSize: 22, fontWeight: 700, lineHeight: '28px', letterSpacing: '-0.3px', marginTop: 2 }}>
            {getGreeting()}, {userName.split(' ')[0]}
          </div>
        </div>

        {/* Hero CTA card */}
        <button onClick={() => {
          console.log('[Dashboard] Create button clicked, onCreate:', typeof onCreate);
          if (onCreate) {
            onCreate();
          } else {
            console.error('[Dashboard] onCreate prop is undefined!');
            alert('Error: Create function not available');
          }
        }} style={{
          width: '100%', textAlign: 'left', cursor: 'pointer', fontFamily: 'inherit',
          background: 'linear-gradient(135deg, #FEC230 0%, #FECC51 60%, #DC9C3D 100%)',
          border: 0, borderRadius: 10, padding: 16, color: '#000',
          display: 'flex', alignItems: 'center', gap: 14, marginBottom: 18,
          boxShadow: '0 0 0 1px rgba(254,194,48,0.4), 0 8px 24px -12px rgba(254,194,48,0.5)',
          position: 'relative', overflow: 'hidden'
        }}>
          <div style={{
            position: 'absolute', top: -30, right: -30, width: 120, height: 120, borderRadius: '50%',
            background: 'radial-gradient(circle, rgba(255,255,255,0.4), transparent 65%)'
          }} />
          <div style={{
            width: 44, height: 44, borderRadius: 8, background: 'rgba(0,0,0,0.12)',
            display: 'flex', alignItems: 'center', justifyContent: 'center', flex: '0 0 44px', position: 'relative'
          }}>
            <I.FilePlus2 size={22} />
          </div>
          <div style={{ flex: 1, position: 'relative' }}>
            <div style={{ fontSize: 15, fontWeight: 700, lineHeight: '20px' }}>Create VRV/VRF Quote</div>
          </div>
          <I.ChevronRight size={22} style={{ position: 'relative' }} />
        </button>

        {/* Stats strip */}
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 8, marginBottom: 18 }}>
          <Stat label="Active quotes" value={quotes.filter((q) => ['Sent', 'Draft', 'Needs review'].includes(q.status)).length} />
          <Stat label="Pipeline" value={fmt0(totalValue)} />
        </div>

        {/* Quotes list */}
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', margin: '4px 2px 8px' }}>
          <div style={{ color: '#D4D4D4', fontSize: 12, fontWeight: 700, letterSpacing: '0.02em' }}>RECENT QUOTES</div>
        </div>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
          {quotes.length === 0 ? (
            <div style={{
              padding: '32px 16px', textAlign: 'center',
              background: '#262626', border: '1px solid #404040', borderRadius: 8,
            }}>
              <div style={{ color: '#808080', fontSize: 14 }}>No quotes yet</div>
              <div style={{ color: '#525252', fontSize: 12, marginTop: 4 }}>Create your first quote to get started</div>
            </div>
          ) : quotes.map((q) => {
            // Map API field names to display names - prioritize meaningful info
            // Title: project_name (address) > quote_reference > manufacturer + status > generic
            let displayName = 'New Quote';
            if (q.project_name) {
              displayName = q.project_name;
            } else if (q.quote_reference) {
              displayName = q.quote_reference;
            } else if (q.manufacturer) {
              displayName = `${q.manufacturer} Quote`;
            } else if (q.status === 'uploaded') {
              displayName = 'Processing...';
            } else if (q.status === 'draft') {
              displayName = 'Draft Quote';
            }

            // Subtitle: client_name (contractor) > manufacturer > status description
            let displayClient = '';
            if (q.client_name) {
              displayClient = q.client_name;
            } else if (q.manufacturer && q.project_name) {
              // If we have project name as title, show manufacturer as subtitle
              displayClient = q.manufacturer;
            } else if (q.status === 'uploaded') {
              displayClient = 'Extracting data...';
            } else if (q.status === 'failed_api_error' || q.status === 'failed_invalid_pdf') {
              displayClient = 'Extraction failed';
            } else {
              displayClient = 'No client assigned';
            }

            const displayDate = q.created_at ? new Date(q.created_at).toLocaleDateString('en-AU', { day: 'numeric', month: 'short' }) : 'Draft';
            const displayTotal = q.total || q.final_price || 0;

            return (
              <SwipeableCard key={q.id} onDelete={() => handleDeleteQuote(q.id)}>
                <button onClick={() => onOpenQuote?.(q)} style={{
                  width: '100%', textAlign: 'left', cursor: 'pointer', fontFamily: 'inherit',
                  background: '#262626', border: '1px solid #404040', borderRadius: 8, padding: '12px 14px',
                  display: 'flex', flexDirection: 'column', gap: 8
                }}>
                  <div style={{ display: 'flex', justifyContent: 'space-between', gap: 8, alignItems: 'flex-start' }}>
                    <div style={{ flex: 1, minWidth: 0 }}>
                      <div style={{ color: '#fff', fontSize: 14, fontWeight: 600, lineHeight: '20px', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{displayName}</div>
                      <div style={{ color: '#B8B8B8', fontSize: 12, marginTop: 2, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{displayClient}</div>
                    </div>
                    <Badge tone={statusTone(q.status)}>{q.status}</Badge>
                </div>
                  <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', borderTop: '1px solid #404040', paddingTop: 8 }}>
                    <span style={{ color: '#808080', fontSize: 11 }}>{displayDate}</span>
                    {displayTotal > 0 && <span style={{ color: '#fff', fontSize: 14, fontWeight: 700, fontVariantNumeric: 'tabular-nums' }}>{fmt0(displayTotal)}</span>}
                  </div>
                </button>
              </SwipeableCard>
            );
          })}
        </div>
      </div>
      {profileOpen && (
        <div onClick={() => setProfileOpen(false)} style={{
          position: 'absolute', inset: 0, background: 'rgba(0,0,0,0.6)', zIndex: 30,
          display: 'flex', alignItems: 'flex-end', animation: 'vrvIn .25s ease-out',
        }}>
          <div onClick={(e) => e.stopPropagation()} style={{
            width: '100%', background: '#1f1f1f', borderTopLeftRadius: 16, borderTopRightRadius: 16,
            padding: '20px 16px 28px', borderTop: '1px solid #404040',
          }}>
            <div style={{ width: 36, height: 4, background: '#525252', borderRadius: 2, margin: '0 auto 16px' }}/>
            <div style={{ display: 'flex', alignItems: 'center', gap: 12, marginBottom: 16 }}>
              <div style={{ width: 48, height: 48, borderRadius: '50%', background: 'linear-gradient(135deg, #FEC230, #DC6C3D)', display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#000', fontSize: 18, fontWeight: 700 }}>{userInitial}</div>
              <div style={{ flex: 1 }}>
                <div style={{ color: '#fff', fontSize: 15, fontWeight: 600 }}>{userName}</div>
                <div style={{ color: '#B8B8B8', fontSize: 12 }}>{userEmail}</div>
              </div>
            </div>
            <button onClick={() => { setProfileOpen(false); onLogout?.(); }} style={{
              width: '100%', marginTop: 12, padding: '12px', background: '#262626', border: '1px solid #404040',
              borderRadius: 8, color: '#EF4444', fontFamily: 'inherit', fontSize: 14, fontWeight: 500, cursor: 'pointer',
            }}>Sign out</button>
          </div>
        </div>
      )}
    </PhoneShell>);

}

const navBtn = {
  width: 36, height: 36, borderRadius: 6, border: 0, background: 'transparent',
  color: '#fff', cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center'
};

function Stat({ label, value }) {
  return (
    <div style={{ background: '#262626', border: '1px solid #404040', borderRadius: 8, padding: '10px 12px' }}>
      <div style={{ color: '#B8B8B8', fontSize: 11, fontWeight: 500 }}>{label}</div>
      <div style={{ color: '#fff', fontSize: 18, fontWeight: 700, fontVariantNumeric: 'tabular-nums', marginTop: 2 }}>{value}</div>
    </div>);

}

// ─── Upload ───────────────────────────────────────────────────────
// File upload zone component for reuse
function FileUploadZone({ label, hint, file, onFile, onRemove, disabled, dragActive, onDragActive, inputRef, accept }) {
  const isDocx = file?.name?.toLowerCase().endsWith('.docx');
  const fileTypeLabel = isDocx ? 'DOCX' : 'PDF';

  return (
    <div style={{ marginBottom: 12 }}>
      <div style={{ color: '#FEC230', fontSize: 11, fontWeight: 700, letterSpacing: '0.04em', marginBottom: 6 }}>
        {label}
      </div>
      {!file ? (
        <div
          onDragOver={(e) => { e.preventDefault(); onDragActive?.(true); }}
          onDragLeave={() => onDragActive?.(false)}
          onDrop={(e) => {
            e.preventDefault();
            onDragActive?.(false);
            const f = e.dataTransfer?.files?.[0];
            if (f) onFile(f);
          }}
          onClick={() => !disabled && inputRef?.current?.click()}
          style={{
            padding: '24px 16px',
            border: `1.5px dashed ${dragActive ? '#FEC230' : '#525252'}`,
            borderRadius: 10,
            background: dragActive ? 'rgba(254,194,48,0.06)' : '#1f1f1f',
            display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 8,
            cursor: disabled ? 'not-allowed' : 'pointer',
            opacity: disabled ? 0.5 : 1,
            transition: 'all .18s ease',
          }}
        >
          <I.UploadCloud size={24} color={dragActive ? '#FEC230' : '#808080'} />
          <div style={{ color: '#B8B8B8', fontSize: 12, textAlign: 'center' }}>
            {hint}
          </div>
        </div>
      ) : (
        <div style={{
          padding: 12,
          background: '#1f1f1f', border: '1px solid #22C55E', borderRadius: 10,
          display: 'flex', alignItems: 'center', gap: 10,
        }}>
          <div style={{
            width: 36, height: 44, borderRadius: 4, background: '#262626',
            border: '1px solid #525252', display: 'flex', alignItems: 'center', justifyContent: 'center',
            color: '#FEC230', fontSize: 9, fontWeight: 700, flex: '0 0 36px',
          }}>{fileTypeLabel}</div>
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{
              color: '#fff', fontSize: 13, fontWeight: 600, lineHeight: '18px',
              overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap',
            }}>{file.name}</div>
            <div style={{ color: '#22C55E', fontSize: 11, marginTop: 2, display: 'flex', alignItems: 'center', gap: 4 }}>
              <I.Check size={12} strokeWidth={3} /> Ready
            </div>
          </div>
          <button onClick={onRemove} disabled={disabled} aria-label="Remove file" style={{
            width: 28, height: 28, borderRadius: 6, border: '1px solid #404040',
            background: '#262626', color: '#B8B8B8', cursor: disabled ? 'not-allowed' : 'pointer',
            display: 'flex', alignItems: 'center', justifyContent: 'center', flex: '0 0 28px',
            opacity: disabled ? 0.5 : 1,
          }}>
            <I.X size={14} />
          </button>
        </div>
      )}
    </div>
  );
}

function UploadScreen({ onBack, onUploaded, quoteId, progress }) {
  // V3: Two file upload - quote PDF (required) + technical document (optional)
  const [quoteFile, setQuoteFile] = useState(null); // {name, size, file}
  const [technicalFile, setTechnicalFile] = useState(null); // {name, size, file}
  const [uploading, setUploading] = useState(false);
  const [uploadError, setUploadError] = useState(null);
  const [errorRetryable, setErrorRetryable] = useState(false);
  const [quoteDragActive, setQuoteDragActive] = useState(false);
  const [technicalDragActive, setTechnicalDragActive] = useState(false);

  const quoteInputRef = useRef();
  const technicalInputRef = useRef();

  // Quote file validation (PDF only)
  const validateQuoteFile = (file) => {
    const ext = '.' + file.name.split('.').pop()?.toLowerCase();
    const isValidType = file.type === 'application/pdf' || ext === '.pdf';
    if (!isValidType) {
      return 'Please select a PDF document';
    }
    if (file.size > 50 * 1024 * 1024) {
      return 'File must be under 50 MB';
    }
    return null;
  };

  // Technical file validation (PDF or DOCX)
  const validateTechnicalFile = (file) => {
    const ext = '.' + file.name.split('.').pop()?.toLowerCase();
    const isValidType = file.type === 'application/pdf' ||
                        file.type === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' ||
                        ext === '.pdf' ||
                        ext === '.docx';
    if (!isValidType) {
      return 'Please select a PDF or DOCX document';
    }
    if (file.size > 50 * 1024 * 1024) {
      return 'File must be under 50 MB';
    }
    return null;
  };

  const handleQuoteFile = (file) => {
    const error = validateQuoteFile(file);
    if (error) {
      setUploadError(error);
      setErrorRetryable(false);
      return;
    }
    setUploadError(null);
    setErrorRetryable(false);
    const sizeMb = (file.size / (1024 * 1024)).toFixed(1);
    setQuoteFile({ name: file.name, size: `${sizeMb} MB`, file });
  };

  const handleTechnicalFile = (file) => {
    const error = validateTechnicalFile(file);
    if (error) {
      setUploadError(error);
      setErrorRetryable(false);
      return;
    }
    setUploadError(null);
    setErrorRetryable(false);
    const sizeMb = (file.size / (1024 * 1024)).toFixed(1);
    setTechnicalFile({ name: file.name, size: `${sizeMb} MB`, file });
  };

  const generate = async () => {
    if (!quoteFile) return;

    setUploading(true);
    setUploadError(null);

    try {
      console.log('[Upload] Uploading documents...');
      console.log('[Upload] Quote PDF:', quoteFile.name);
      if (technicalFile) {
        console.log('[Upload] Technical document:', technicalFile.name);
      }

      // Upload both files together
      await api.uploadDocuments(
        quoteId,
        quoteFile.file,
        technicalFile?.file || null
      );

      // Success - navigate to loader
      onUploaded({
        filename: quoteFile.name,
        technicalFilename: technicalFile?.name || null,
        error: false,
      });
    } catch (err) {
      const message = err.message || '';

      // PDF recognition errors - show dedicated error screen
      if (message.includes('invalid') || message.includes('not a quote') || message.includes('not recognized') || message.includes('not recognised')) {
        onUploaded({ filename: quoteFile.name, error: true, errorType: 'failed_invalid_pdf' });
        return;
      }

      // Rate limit / quota errors - show dedicated error screen
      if (message.includes('Rate Limit') || message.includes('Too many') || message.includes('quota') || message.includes('429')) {
        onUploaded({ filename: quoteFile.name, error: true, errorType: 'failed_rate_limit' });
        return;
      }

      // Server / API errors - show dedicated error screen
      if (message.includes('500') || message.includes('server error') || message.includes('API') || message.includes('extraction failed')) {
        onUploaded({ filename: quoteFile.name, error: true, errorType: 'failed_api_error' });
        return;
      }

      // Remaining errors show inline with retry option
      let userMessage = 'Upload failed. Please try again.';
      let canRetry = true;

      if (message.includes('network') || message.includes('fetch') || message.includes('Failed to fetch')) {
        userMessage = 'Network error. Please check your connection and try again.';
      } else if (message.includes('timeout') || message.includes('timed out')) {
        userMessage = 'Request timed out. The server may be busy - please try again.';
      } else if (message.includes('file') && message.includes('size')) {
        userMessage = 'File too large. Please upload a smaller file (max 50MB).';
        canRetry = false;
      } else if (message.includes('format') || message.includes('type') || message.includes('Invalid file')) {
        userMessage = 'Invalid file format. Please check file types (PDF for quote, PDF/DOCX for technical).';
        canRetry = false;
      } else if (message.includes('auth') || message.includes('401') || message.includes('unauthorized')) {
        userMessage = 'Session expired. Please refresh the page and sign in again.';
        canRetry = false;
      } else if (message) {
        userMessage = message;
      }

      setUploadError(userMessage);
      setErrorRetryable(canRetry);
      setUploading(false);
    }
  };

  const retryUpload = () => {
    setUploadError(null);
    setErrorRetryable(false);
    generate();
  };

  return (
    <PhoneShell title="New VRV Quote" onBack={onBack} progress={progress}>
      <div style={{ padding: '16px 16px 140px' }}>
        <div style={{ color: '#fff', fontSize: 20, fontWeight: 700, letterSpacing: '-0.3px', lineHeight: '26px' }}>
          Upload your documents
        </div>
        <div style={{ color: '#B8B8B8', fontSize: 13, lineHeight: '20px', marginTop: 6, marginBottom: 16 }}>
          Upload your manufacturer quote and optional technical document. Our AI will extract equipment, pricing, and design details.
        </div>

        {/* Hidden file inputs */}
        <input
          ref={quoteInputRef}
          type="file"
          accept=".pdf,application/pdf"
          style={{ display: 'none' }}
          onChange={(e) => e.target.files?.[0] && handleQuoteFile(e.target.files[0])}
        />
        <input
          ref={technicalInputRef}
          type="file"
          accept=".pdf,.docx,application/pdf,application/vnd.openxmlformats-officedocument.wordprocessingml.document"
          style={{ display: 'none' }}
          onChange={(e) => e.target.files?.[0] && handleTechnicalFile(e.target.files[0])}
        />

        {/* Upload error with retry option */}
        {uploadError && (
          <div style={{
            marginBottom: 14, padding: '10px 12px', background: 'rgba(239,68,68,0.12)',
            border: '1px solid rgba(239,68,68,0.32)', borderRadius: 8,
          }}>
            <div style={{ display: 'flex', gap: 10, alignItems: 'flex-start' }}>
              <I.AlertCircle size={16} color="#EF4444" style={{ flexShrink: 0, marginTop: 1 }} />
              <div style={{ flex: 1 }}>
                <div style={{ color: '#EF4444', fontSize: 13 }}>{uploadError}</div>
                {errorRetryable && (
                  <button
                    onClick={retryUpload}
                    style={{
                      marginTop: 8, padding: '6px 12px', borderRadius: 4,
                      background: 'rgba(239,68,68,0.2)', border: '1px solid rgba(239,68,68,0.4)',
                      color: '#EF4444', fontSize: 12, fontWeight: 500, cursor: 'pointer',
                      display: 'flex', alignItems: 'center', gap: 6,
                    }}
                  >
                    <I.RefreshCw size={12} />
                    Try Again
                  </button>
                )}
              </div>
            </div>
          </div>
        )}

        {/* 1. Quote Document Upload (Required) */}
        <FileUploadZone
          label="MANUFACTURER QUOTE (REQUIRED)"
          hint="Drag & drop or tap to select your manufacturer quote PDF"
          file={quoteFile}
          onFile={handleQuoteFile}
          onRemove={() => setQuoteFile(null)}
          disabled={uploading}
          dragActive={quoteDragActive}
          onDragActive={setQuoteDragActive}
          inputRef={quoteInputRef}
          accept=".pdf"
        />

        {/* 2. Technical Document Upload (Optional) */}
        <FileUploadZone
          label="TECHNICAL DOCUMENT (OPTIONAL)"
          hint="Design specification, equipment schedule, or system layout (PDF or DOCX)"
          file={technicalFile}
          onFile={handleTechnicalFile}
          onRemove={() => setTechnicalFile(null)}
          disabled={uploading}
          dragActive={technicalDragActive}
          onDragActive={setTechnicalDragActive}
          inputRef={technicalInputRef}
          accept=".pdf,.docx"
        />

        {/* Info about technical document */}
        {!technicalFile && quoteFile && (
          <div style={{
            padding: '10px 12px', background: 'rgba(254,194,48,0.08)',
            border: '1px solid rgba(254,194,48,0.2)', borderRadius: 8,
            display: 'flex', gap: 10, marginBottom: 12,
          }}>
            <I.Info size={16} color="#FEC230" style={{ flexShrink: 0, marginTop: 1 }} />
            <div style={{ color: '#B8B8B8', fontSize: 12, lineHeight: '18px' }}>
              <strong style={{ color: '#FEC230' }}>Tip:</strong> Adding a technical document provides room-by-room details, capacity specs, and design rationale for richer quote copy.
            </div>
          </div>
        )}

        {/* Ready indicator */}
        {quoteFile && (
          <div style={{
            marginTop: 14, padding: '10px 12px', background: '#262626',
            border: '1px solid #404040', borderRadius: 8,
            display: 'flex', alignItems: 'center', gap: 10,
          }}>
            <div style={{
              width: 32, height: 32, borderRadius: '50%',
              background: 'rgba(34,197,94,0.15)',
              border: '2px solid #22C55E',
              display: 'flex', alignItems: 'center', justifyContent: 'center',
            }}>
              <I.Check size={16} color="#22C55E" strokeWidth={3} />
            </div>
            <div style={{ flex: 1 }}>
              <div style={{ color: '#fff', fontSize: 13, fontWeight: 600 }}>
                Ready to extract
              </div>
              <div style={{ color: '#808080', fontSize: 11, marginTop: 1 }}>
                {technicalFile ? '2 documents ready' : '1 document ready'} · Click Generate Quote to continue
              </div>
            </div>
          </div>
        )}
      </div>

      {/* Sticky footer */}
      <div style={{
        position: 'absolute', bottom: 0, left: 0, right: 0, padding: '12px 16px 16px',
        background: 'linear-gradient(to top, rgba(23,23,23,1) 60%, rgba(23,23,23,0))',
      }}>
        <Button variant="primary" full disabled={!quoteFile || uploading} onClick={generate}>
          {uploading ? (
            <span style={{ display: 'flex', alignItems: 'center', gap: 8, justifyContent: 'center' }}>
              <span style={{
                width: 16, height: 16, border: '2px solid rgba(0,0,0,0.2)',
                borderTopColor: '#000', borderRadius: '50%',
                animation: 'vrvSpin 0.8s linear infinite',
              }}/>
              Processing...
            </span>
          ) : 'Generate Quote'}
        </Button>
      </div>
    </PhoneShell>
  );
}

// ─── Custom Header - for screens with title + subtotal/subtitle ──
function CustomHeader({ title, subtitle, onBack, right }) {
  return (
    <div style={{
      marginTop: 62, position: 'relative',
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      padding: '12px 16px 8px', minHeight: 56,
    }}>
      {onBack && (
        <button onClick={onBack} aria-label="Back" style={{
          position: 'absolute', left: 8, top: '50%', transform: 'translateY(-50%)',
          width: 36, height: 36, borderRadius: 8, border: 0, background: 'transparent',
          color: '#fff', display: 'flex', alignItems: 'center', justifyContent: 'center', cursor: 'pointer',
        }}><I.ChevronLeft size={22}/></button>
      )}
      <div style={{ textAlign: 'center' }}>
        <div style={{ color: '#fff', fontSize: 17, fontWeight: 600 }}>{title}</div>
        {subtitle && <div style={{ color: '#A3A3A3', fontSize: 13, fontVariantNumeric: 'tabular-nums', marginTop: 2 }}>{subtitle}</div>}
      </div>
      {right && (
        <div style={{ position: 'absolute', right: 8, top: '50%', transform: 'translateY(-50%)' }}>{right}</div>
      )}
    </div>
  );
}

window.PhoneShell = PhoneShell;
window.CustomHeader = CustomHeader;
window.LoginScreen = LoginScreen;
window.DashboardScreen = DashboardScreen;
window.UploadScreen = UploadScreen;
