/* eslint-disable */
;(function(){
// יפן 2026 — "תמונות שימושיות". Bundled references plus synchronized private uploads.
const ASSET_QC = './assets';
const {
  useStore: useStoreQC,
  uploadQuickCard,
  deleteQuickCard,
  resolveDocUrl,
  revokeDocUrl,
} = window.JP2026Store;
const { ChibiLightbox: ChibiLightboxQC, TapChibi: TapChibiQC } = window.JP2026Detail;

const BUNDLED_CARDS = [
  {
    id:'bundled-vegan-card',
    title:'כרטיס טבעוני',
    src:`${ASSET_QC}/cards/vegan-card.jpg`,
    alt:'כרטיס הסבר טבעוני לשימוש במסעדות ביפן',
  },
  {
    id:'bundled-trip-calendar',
    title:'לוח הטיול',
    src:`${ASSET_QC}/cards/trip-calendar.jpg`,
    alt:'לוח השנה של טיול יפן',
  },
];

const uploadedAlt = (card) => `תמונה שימושית: ${card.title}`;

function titleFromFilename(name) {
  const clean = String(name || '').trim();
  const dot = clean.lastIndexOf('.');
  return (dot > 0 ? clean.slice(0, dot) : clean).trim();
}

function imageExtension(contentType) {
  const subtype = String(contentType || '').toLowerCase().split('/')[1] || '';
  if (subtype === 'jpeg') return 'jpg';
  return /^(png|webp|gif|heic|heif|avif)$/.test(subtype) ? subtype : 'jpg';
}

function safeFilenamePart(value) {
  return String(value || '').split(/[\\/]/).pop().replace(/[\\/:*?"<>|]+/g, '-').trim();
}

function referenceFilename(card) {
  const originalName = safeFilenamePart(card && card.original_name);
  if (originalName) return originalName;
  const assetName = safeFilenamePart(card && card.src);
  if (assetName) return assetName;
  const title = safeFilenamePart(card && card.title) || 'תמונה-שימושית';
  return `${title}.${imageExtension(card && card.content_type)}`;
}

function errorText(error, fallback) {
  return error && typeof error.message === 'string' && error.message.trim()
    ? error.message.trim()
    : fallback;
}

function BundledCard({ card, onOpen }) {
  return (
    <article style={{ background:'var(--surface-card)', border:'var(--border-card)', borderRadius:'var(--r-lg)',
      boxShadow:'var(--shadow-sm)', overflow:'hidden' }}>
      <button type="button" onClick={()=>onOpen(card)} aria-label={`פתחו ${card.title}`} style={{ appearance:'none', border:'none',
        background:'transparent', padding:0, width:'100%', color:'inherit', cursor:'zoom-in', textAlign:'start' }}>
        <img src={card.src} alt={card.alt} style={{ width:'100%', height:190, objectFit:'cover', display:'block', background:'var(--surface-card-2)' }} />
        <span style={{ display:'block', padding:'12px 14px 14px', fontFamily:'var(--font-display)', fontSize:27,
          lineHeight:1.05, color:'var(--ink-900)', overflowWrap:'anywhere' }}>{card.title}</span>
      </button>
    </article>
  );
}

function UploadedPreview({ card }) {
  const [state, setState] = React.useState({ status:'loading', url:null });
  const [attempt, setAttempt] = React.useState(0);

  React.useEffect(() => {
    const retryOnline = () => setAttempt(value => value + 1);
    window.addEventListener('online', retryOnline);
    return () => window.removeEventListener('online', retryOnline);
  }, []);

  React.useEffect(() => {
    let cancelled = false;
    let ownedUrl = null;
    setState({ status:'loading', url:null });
    resolveDocUrl({ path:card.storage_path, contentType:card.content_type }).then((url) => {
      if (cancelled) { revokeDocUrl(url); return; }
      ownedUrl = url;
      setState(url ? { status:'ready', url } : { status:'missing', url:null });
    }).catch(() => {
      if (!cancelled) setState({ status:'missing', url:null });
    });
    return () => {
      cancelled = true;
      revokeDocUrl(ownedUrl);
    };
  }, [card.storage_path, card.content_type, attempt]);

  if (state.status === 'ready') {
    return <img src={state.url} alt={uploadedAlt(card)} style={{ width:'100%', height:190, objectFit:'cover', display:'block', background:'var(--surface-card-2)' }} />;
  }
  if (state.status === 'missing') {
    return (
      <span style={{ height:190, display:'grid', placeItems:'center', padding:20, boxSizing:'border-box', textAlign:'center',
        background:'var(--surface-card-2)', color:'var(--ink-500)', fontFamily:'var(--font-ui)', fontSize:13, lineHeight:1.45 }}>
        <span>התמונה לא זמינה כרגע<br/><span style={{ display:'inline-block', marginTop:6,
          color:'var(--sky-deep)' }}>התחברו לאינטרנט ופתחו שוב</span></span>
      </span>
    );
  }
  return <span aria-label="טוען תמונה" style={{ height:190, display:'grid', placeItems:'center', background:'var(--surface-card-2)',
    color:'var(--ink-500)', fontFamily:'var(--font-ui)', fontSize:13 }}>טוענים תמונה…</span>;
}

function UploadedCard({ card, onOpen, onDelete, deleting, opening }) {
  return (
    <article style={{ background:'var(--surface-card)', border:'var(--border-card)', borderRadius:'var(--r-lg)',
      boxShadow:'var(--shadow-sm)', overflow:'hidden' }}>
      <button type="button" onClick={()=>onOpen(card)} disabled={opening} aria-label={`פתחו ${card.title}`} style={{ appearance:'none', border:'none',
        background:'transparent', padding:0, width:'100%', color:'inherit', cursor:opening?'wait':'zoom-in', textAlign:'start' }}>
        <UploadedPreview card={card} />
        <span style={{ display:'block', padding:'12px 14px 8px', fontFamily:'var(--font-display)', fontSize:27,
          lineHeight:1.05, color:'var(--ink-900)', overflowWrap:'anywhere', whiteSpace:'normal' }}>{card.title}</span>
      </button>
      <div style={{ display:'flex', justifyContent:'flex-end', padding:'0 10px 10px' }}>
        <button type="button" onClick={()=>onDelete(card)} disabled={deleting} aria-label={`מחקו ${card.title}`} style={{ appearance:'none',
          border:'1px solid color-mix(in srgb, var(--peach-deep) 28%, transparent)', background:'transparent', color:'var(--peach-deep)',
          borderRadius:'var(--r-pill)', padding:'7px 12px', fontFamily:'var(--font-ui)', fontSize:12.5,
          cursor:deleting?'wait':'pointer', opacity:deleting ? .65 : 1 }}>
          {deleting ? 'מוחקים…' : 'מחיקת תמונה'}
        </button>
      </div>
    </article>
  );
}

function QuickCardsScreen() {
  const rows = useStoreQC('quick_cards');
  const uploadedCards = rows.filter(card => card && card.uploaded === true)
    .slice().sort((a, b) => String(b.created_at || '').localeCompare(String(a.created_at || '')));
  const fileInput = React.useRef(null);
  const viewerRef = React.useRef(null);
  const openRequest = React.useRef(0);
  const pendingOpenCard = React.useRef(null);
  const [headerLightbox, setHeaderLightbox] = React.useState(null);
  const [viewer, setViewer] = React.useState(null);
  const [openingId, setOpeningId] = React.useState(null);
  const [deletingId, setDeletingId] = React.useState(null);
  const [uploading, setUploading] = React.useState(false);
  const [message, setMessage] = React.useState(null);
  const CHIBI_QC = `${ASSET_QC}/chibi/chibi-quickcards.png`;

  React.useEffect(() => { viewerRef.current = viewer; }, [viewer]);
  React.useEffect(() => () => {
    openRequest.current += 1;
    pendingOpenCard.current = null;
    const current = viewerRef.current;
    if (current && current.ownedUrl) revokeDocUrl(current.src);
  }, []);

  const replaceViewer = (next) => {
    const current = viewerRef.current;
    if (current && current.ownedUrl) revokeDocUrl(current.src);
    viewerRef.current = next;
    setViewer(next);
  };
  const closeViewer = () => replaceViewer(null);

  // Realtime can remove a card while its full-size URL is resolving or already open.
  // Only the separately owned viewer URL is revoked here; preview URLs stay with
  // UploadedPreview and are cleaned by that component when its row unmounts.
  React.useEffect(() => {
    const liveIds = new Set(uploadedCards.map(card => card.id));
    const pendingId = pendingOpenCard.current;
    if (pendingId && !liveIds.has(pendingId)) {
      openRequest.current += 1;
      pendingOpenCard.current = null;
      setOpeningId(null);
    }
    const current = viewerRef.current;
    if (current && current.uploaded && !liveIds.has(current.cardId)) {
      replaceViewer(null);
    }
  }, [rows]);

  const openBundled = (card) => {
    openRequest.current += 1;
    pendingOpenCard.current = null;
    setOpeningId(null);
    replaceViewer({ src:card.src, alt:card.alt, filename:referenceFilename(card), ownedUrl:false, uploaded:false, cardId:card.id });
  };
  const openUploaded = async (card) => {
    const request = ++openRequest.current;
    pendingOpenCard.current = card.id;
    setOpeningId(card.id);
    setMessage(null);
    try {
      const url = await resolveDocUrl({ path:card.storage_path, contentType:card.content_type });
      if (request !== openRequest.current) { revokeDocUrl(url); return; }
      if (!url) throw new Error('התמונה אינה זמינה במטמון. התחברו לאינטרנט ונסו שוב.');
      pendingOpenCard.current = null;
      replaceViewer({ src:url, alt:uploadedAlt(card), filename:referenceFilename(card), ownedUrl:true, uploaded:true, cardId:card.id });
    } catch (error) {
      if (request === openRequest.current) setMessage({ kind:'error', text:errorText(error, 'לא הצלחנו לפתוח את התמונה.') });
    } finally {
      if (request === openRequest.current) {
        pendingOpenCard.current = null;
        setOpeningId(null);
      }
    }
  };

  const chooseFile = () => {
    setMessage(null);
    fileInput.current?.click();
  };
  const onFile = async (event) => {
    const input = event.currentTarget;
    const file = input.files && input.files[0];
    input.value = '';
    if (!file) return;
    if (!file.type || !file.type.toLowerCase().startsWith('image/')) {
      setMessage({ kind:'error', text:'אפשר להעלות קובץ תמונה בלבד.' });
      return;
    }
    const suggested = titleFromFilename(file.name) || 'תמונה שימושית';
    let title = window.prompt('הזינו כותרת בעברית לתמונה:', suggested);
    while (title !== null && !title.trim()) {
      title = window.prompt('חובה להזין כותרת. הזינו כותרת בעברית:', suggested);
    }
    if (title === null) return;
    setUploading(true);
    setMessage({ kind:'status', text:'מעלים את התמונה…' });
    try {
      await uploadQuickCard(file, title.trim());
      setMessage({ kind:'success', text:'התמונה עלתה ומסונכרנת לשניכם.' });
    } catch (error) {
      setMessage({ kind:'error', text:errorText(error, 'לא הצלחנו להעלות את התמונה.') });
    } finally { setUploading(false); }
  };

  const removeUploaded = async (card) => {
    if (!window.confirm(`למחוק את «${card.title}» אצל שני המטיילים?`)) return;
    openRequest.current += 1;
    pendingOpenCard.current = null;
    setOpeningId(null);
    setDeletingId(card.id);
    setMessage(null);
    try {
      await deleteQuickCard(card);
      if (viewerRef.current && viewerRef.current.cardId === card.id) closeViewer();
      setMessage({ kind:'success', text:'התמונה נמחקה.' });
    } catch (error) {
      setMessage({ kind:'error', text:errorText(error, 'לא הצלחנו למחוק את התמונה. היא נשארה ברשימה.') });
    } finally { setDeletingId(null); }
  };

  return (
    <div dir="rtl" style={{ paddingBottom:30 }}>
      <header style={{ position:'relative', padding:'16px 20px 10px', paddingInlineEnd:112, minHeight:76, boxSizing:'border-box' }}>
        <TapChibiQC src={CHIBI_QC} alt="משה וליעוז מציגים תמונות שימושיות" onOpen={setHeaderLightbox} style={{ position:'absolute', top:4,
          insetInlineEnd:14, width:72, height:72, borderRadius:'var(--r-md)' }} />
        <div style={{ fontFamily:'var(--font-ui)', fontSize:13, color:'var(--ink-500)' }}>עוד · שימושי ביפן</div>
        <h1 style={{ fontFamily:'var(--font-display)', fontSize:42, lineHeight:.9, color:'var(--ink-900)', margin:'2px 0 0',
          overflowWrap:'anywhere' }}>תמונות שימושיות</h1>
        <div style={{ fontFamily:'var(--font-ui)', fontSize:14, lineHeight:1.4, color:'var(--ink-500)', marginTop:4 }}>כל מה שצריך להראות ברגע הנכון 🖼️</div>
      </header>

      <section aria-label="הוספת תמונה" style={{ margin:'10px 20px 2px' }}>
        <button type="button" onClick={chooseFile} disabled={uploading} style={{ appearance:'none', border:'none', width:'100%', marginTop:10,
          padding:'11px 16px', borderRadius:'var(--r-pill)', background:'var(--ink-900)', color:'var(--paper-cream)',
          fontFamily:'var(--font-ui)', fontSize:15, cursor:uploading?'wait':'pointer', opacity:uploading ? .7 : 1 }}>
          {uploading ? 'מעלים…' : 'הוספת תמונה'}
        </button>
        <input ref={fileInput} type="file" accept="image/*" onChange={onFile} hidden />
      </section>

      {message && <div role={message.kind === 'error' ? 'alert' : 'status'} aria-live="polite" style={{ margin:'10px 20px 0', padding:'10px 12px',
        borderRadius:'var(--r-md)', background:message.kind==='error'?'var(--peach-tint)':message.kind==='success'?'var(--vegan-full-tint)':'var(--sky-tint)',
        color:'var(--ink-700)', fontFamily:'var(--font-ui)', fontSize:13, lineHeight:1.45 }}>{message.text}</div>}

      <section aria-label="תמונות שימושיות" style={{ display:'grid', gridTemplateColumns:'repeat(2, minmax(0, 1fr))', gap:12,
        padding:'14px 20px 0' }}>
        {BUNDLED_CARDS.map(card => <BundledCard key={card.id} card={card} onOpen={openBundled} />)}
        {uploadedCards.map(card => <UploadedCard key={card.id} card={card} onOpen={openUploaded} onDelete={removeUploaded}
          opening={openingId===card.id} deleting={deletingId===card.id} />)}
      </section>

      {headerLightbox && <ChibiLightboxQC src={headerLightbox} alt="משה וליעוז מציגים תמונות שימושיות" onClose={()=>setHeaderLightbox(null)} />}
      {viewer && <ChibiLightboxQC src={viewer.src} alt={viewer.alt} filename={viewer.filename} variant="reference" onClose={closeViewer} />}
    </div>
  );
}

window.JP2026QuickCards = QuickCardsScreen;

})();
