// Supplemental sheets: AddPhotoSheet, ActivityFeedSheet
(function(){
  const { useState, useEffect, useMemo } = React;
  const { Avatar, useData, useActivity, Sheet, Btn } = window.FTUI;

  // ---------- ADD PHOTO SHEET ----------
  function AddPhotoSheet({ ctx, onClose }){
    const d = useData();
    const [tab, setTab] = useState('auto'); // auto | generate | url | upload
    const [urlVal, setUrlVal] = useState('');
    const [saving, setSaving] = useState(false);
    const [err, setErr] = useState('');
    const [genPrompt, setGenPrompt] = useState('');
    const [genPreview, setGenPreview] = useState(null);
    const [searchQ, setSearchQ] = useState('');
    const [searchResults, setSearchResults] = useState([]);
    const [searching, setSearching] = useState(false);

    useEffect(() => {
      if(ctx){ setTab('auto'); setUrlVal(''); setErr(''); setSaving(false); setGenPrompt(''); setGenPreview(null); setSearchResults([]); setSearchQ(''); }
    }, [ctx]);

    if(!ctx) return null;
    const item = d?.[ctx.cat]?.items.find(i => i.id === ctx.id);
    if(!item) return null;

    // Compress a data URL photo down to a target size so we don't blow up the Firestore 1MB doc limit.
    // For external URLs (Pexels, etc.), we pass through untouched — they're tiny strings.
    const compressDataUrl = (dataUrl, maxDim = 600, quality = 0.72) => new Promise((resolve, reject) => {
      if(!dataUrl?.startsWith?.('data:')) { resolve(dataUrl); return; }
      const img = new Image();
      img.onload = () => {
        const scale = Math.min(1, maxDim / Math.max(img.width, img.height));
        const w = Math.round(img.width * scale);
        const h = Math.round(img.height * scale);
        const canvas = document.createElement('canvas');
        canvas.width = w; canvas.height = h;
        canvas.getContext('2d').drawImage(img, 0, 0, w, h);
        resolve(canvas.toDataURL('image/jpeg', quality));
      };
      img.onerror = () => reject(new Error('could not process image'));
      img.src = dataUrl;
    });

    const setPhoto = async (photoUrl) => {
      try {
        setSaving(true); setErr('');
        let final = photoUrl;
        if(photoUrl && typeof photoUrl === 'string' && photoUrl.startsWith('data:')){
          const compressed = await compressDataUrl(photoUrl, 900, 0.82);
          if(window.FT?.uploadPhotoData){
            try {
              final = await window.FT.uploadPhotoData(compressed);
            } catch(upErr){
              console.warn('Storage upload failed, embedding instead:', upErr);
              final = compressed;
            }
          } else {
            final = compressed;
          }
        }
        FT.updateItem(ctx.cat, ctx.id, { photo: final });
        setSaving(false);
        onClose();
      } catch(e){
        setSaving(false);
        setErr(e.message || 'could not save photo');
      }
    };

    const defaultQuery = () => [item.text, item.where, item.nudge?.neighborhood].filter(Boolean).join(' ').slice(0,80);

    const runSearch = async (q) => {
      const query = (q || searchQ || defaultQuery()).trim();
      if(!query){ setErr('type a search or add a title first'); return; }
      setSearching(true); setErr(''); setSearchResults([]);
      try {
        const r = await fetch('https://nudge-proxy.allurhopesndreams.workers.dev/image-search', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ query, per_page: 8 })
        });
        const data = await r.json();
        if(data.error){ setErr(data.error); setSearching(false); return; }
        setSearchResults(data.photos || []);
        if(!(data.photos||[]).length) setErr('no photos found for that search');
      } catch(e){ setErr(e.message || 'search failed'); }
      setSearching(false);
    };

    const saveUrl = () => {
      const u = urlVal.trim();
      if(!u){ setErr('paste an image URL first'); return; }
      if(!/^https?:\/\//.test(u)){ setErr('needs to start with http(s)://'); return; }
      setPhoto(u);
    };

    const onFile = (file) => {
      if(!file) return;
      if(file.size > 4 * 1024 * 1024){ setErr('image too large (max 4MB)'); return; }
      setSaving(true); setErr('');
      const img = new Image();
      const reader = new FileReader();
      reader.onload = () => {
        img.onload = () => {
          // Downscale to max 900px wide, JPEG quality .82
          const max = 900;
          const scale = Math.min(1, max / Math.max(img.width, img.height));
          const w = Math.round(img.width * scale);
          const h = Math.round(img.height * scale);
          const canvas = document.createElement('canvas');
          canvas.width = w; canvas.height = h;
          const ctx2 = canvas.getContext('2d');
          ctx2.drawImage(img, 0, 0, w, h);
          const dataUrl = canvas.toDataURL('image/jpeg', 0.82);
          if(dataUrl.length > 900 * 1024){
            setErr('compressed photo is still too big — try a smaller one');
            setSaving(false);
            return;
          }
          setPhoto(dataUrl);
        };
        img.onerror = () => { setErr('couldn\'t load that image'); setSaving(false); };
        img.src = reader.result;
      };
      reader.onerror = () => { setErr('failed to read file'); setSaving(false); };
      reader.readAsDataURL(file);
    };

    const removePhoto = () => {
      FT.updateItem(ctx.cat, ctx.id, { photo: null });
      onClose();
    };

    const generateImage = async () => {
      const prompt = (genPrompt.trim() || item.text || '').slice(0, 200);
      if(!prompt){ setErr('add a title or prompt first'); return; }
      setSaving(true); setErr(''); setGenPreview(null);
      try {
        const r = await fetch('https://nudge-proxy.allurhopesndreams.workers.dev/gen-image', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ prompt })
        });
        const data = await r.json();
        if(data.error){ setErr(data.error); setSaving(false); return; }
        if(data.image){ setGenPreview(data.image); }
        else { setErr('no image returned'); }
      } catch(e){ setErr(e.message || 'generation failed'); }
      setSaving(false);
    };

    const useGenerated = () => {
      if(genPreview){ setPhoto(genPreview); }
    };

    return (
      <Sheet open={!!ctx} onClose={onClose} title={item.photo?'Change photo':'Add photo'}>
        <div style={{fontSize:13,color:'var(--text2)',marginBottom:12,lineHeight:1.45}}>
          Pick a photo for <b style={{color:'var(--text)'}}>{item.text}</b>
        </div>

        <div style={{display:'flex',gap:3,padding:3,borderRadius:99,background:'var(--card-strong)',border:'1px solid var(--border)',marginBottom:14}}>
          {[['auto','🔍'],['generate','🪄'],['url','🔗'],['upload','📷']].map(([k,lbl]) => (
            <button key={k} onClick={()=>{setTab(k); setErr('');}} style={{flex:1,padding:'7px 6px',borderRadius:99,background:tab===k?'var(--card)':'transparent',border:'none',color:tab===k?'var(--text)':'var(--text3)',fontSize:11,cursor:'pointer',fontFamily:'inherit',fontWeight:tab===k?600:400}}>
              {lbl} {k==='auto'?'Find':k==='generate'?'Gen':k==='url'?'URL':'Upload'}
            </button>
          ))}
        </div>

        {tab==='auto' && (
          <div>
            <div style={{fontSize:12.5,color:'var(--text3)',marginBottom:10,lineHeight:1.45}}>
              Search free stock photos (Pexels). Type a custom query or use the title below.
            </div>
            <div style={{position:'relative'}}>
              <input className="ft-input" placeholder={defaultQuery() || 'what kind of photo?'} value={searchQ} onChange={e=>setSearchQ(e.target.value)} onKeyDown={e=>e.key==='Enter'&&runSearch()} style={{paddingRight:48}} autoCorrect="on" autoCapitalize="sentences"/>
              <button onClick={()=>runSearch()} disabled={searching} style={{position:'absolute',right:5,top:5,bottom:5,width:38,padding:0,background:'linear-gradient(135deg,var(--rose),var(--lavender))',color:'#fff',border:'none',borderRadius:8,cursor:'pointer',fontSize:16,fontWeight:600,opacity:searching?.4:1}}>🔍</button>
            </div>
            {searching && <div style={{marginTop:14,textAlign:'center',color:'var(--text3)',fontSize:13,fontStyle:'italic'}}>searching…</div>}
            {searchResults.length > 0 && (
              <div style={{marginTop:12,display:'grid',gridTemplateColumns:'1fr 1fr',gap:8}}>
                {searchResults.map(p => (
                  <button key={p.id} onClick={()=>setPhoto(p.full)} style={{padding:0,border:'1px solid var(--border)',borderRadius:10,overflow:'hidden',cursor:'pointer',background:'var(--card)',aspectRatio:'1/1'}} title={`by ${p.photographer}`}>
                    <img src={p.thumb} alt={p.alt} style={{width:'100%',height:'100%',objectFit:'cover',display:'block'}}/>
                  </button>
                ))}
              </div>
            )}
            {searchResults.length > 0 && (
              <div style={{marginTop:8,fontSize:10.5,color:'var(--text3)',textAlign:'center'}}>Photos via Pexels · tap one to use</div>
            )}
          </div>
        )}

        {tab==='generate' && (
          <div>
            <div style={{fontSize:12.5,color:'var(--text3)',marginBottom:10,lineHeight:1.45}}>
              Generate a custom image with AI. Leave the prompt blank to use "{item.text}" as-is, or describe exactly what you want.
            </div>
            <label className="ft-label">Prompt (optional)</label>
            <input className="ft-input" placeholder={`e.g. "${item.text}" stylized as a watercolor`} value={genPrompt} onChange={e=>setGenPrompt(e.target.value)} autoCorrect="on" autoCapitalize="sentences"/>
            <Btn variant="solid" size="md" style={{width:'100%',marginTop:10}} onClick={generateImage} disabled={saving}>
              {saving ? 'generating… (~5-10s)' : '🪄 Generate image'}
            </Btn>
            {genPreview && (
              <div style={{marginTop:12}}>
                <div style={{borderRadius:14,overflow:'hidden',border:'1px solid var(--border)',background:'var(--card)',aspectRatio:'1/1'}}>
                  <img src={genPreview} alt="preview" style={{width:'100%',height:'100%',objectFit:'cover'}}/>
                </div>
                <div style={{display:'flex',gap:8,marginTop:10}}>
                  <Btn variant="ghost" size="md" style={{flex:1}} onClick={generateImage} disabled={saving}>↻ another</Btn>
                  <Btn variant="solid" size="md" style={{flex:1}} onClick={useGenerated}>use this ✓</Btn>
                </div>
              </div>
            )}
          </div>
        )}

        {tab==='url' && (
          <div>
            <label className="ft-label">Paste an image URL</label>
            <input className="ft-input" placeholder="https://…jpg" value={urlVal} onChange={e=>setUrlVal(e.target.value)} autoFocus autoCorrect="off" autoCapitalize="none" spellCheck="false"/>
            {urlVal && /^https?:\/\//.test(urlVal) && (
              <div style={{marginTop:10,borderRadius:12,overflow:'hidden',border:'1px solid var(--border)',background:'var(--card)',aspectRatio:'3/2',display:'flex',alignItems:'center',justifyContent:'center'}}>
                <img src={urlVal} alt="preview" style={{width:'100%',height:'100%',objectFit:'cover'}} onError={(e)=>{e.target.style.display='none';}}/>
              </div>
            )}
            <Btn variant="solid" size="md" style={{width:'100%',marginTop:12}} onClick={saveUrl} disabled={saving}>Save</Btn>
          </div>
        )}

        {tab==='upload' && (
          <div>
            <div style={{fontSize:12.5,color:'var(--text3)',marginBottom:10,lineHeight:1.45}}>
              From your device · auto-resized to ~900px wide.
            </div>
            <label htmlFor="ft-photo-file" style={{display:'block',padding:'22px 14px',borderRadius:14,border:'1.5px dashed var(--border-accent)',background:'color-mix(in oklab,var(--rose) 6%,transparent)',textAlign:'center',cursor:'pointer'}}>
              <div style={{fontSize:32,marginBottom:6}}>📷</div>
              <div style={{fontSize:13,color:'var(--text2)',fontWeight:500}}>tap to choose a photo</div>
              <div style={{fontSize:11,color:'var(--text3)',marginTop:3}}>JPG / PNG · up to 4MB</div>
            </label>
            <input id="ft-photo-file" type="file" accept="image/*" style={{display:'none'}} onChange={e=>onFile(e.target.files?.[0])}/>
          </div>
        )}

        {err && <div style={{marginTop:10,color:'var(--rose)',fontSize:12,fontFamily:'Caveat,cursive',fontSize:15}}>{err}</div>}

        {item.photo && (
          <div style={{marginTop:14,paddingTop:14,borderTop:'1px solid var(--border)'}}>
            <button onClick={removePhoto} className="ft-remove-photo-btn">× remove current photo</button>
          </div>
        )}
      </Sheet>
    );
  }

  // ---------- ACTIVITY FEED SHEET (full history w/ reactions) ----------
  function ActivityFeedSheet({ open, onClose, me }){
    const activity = useActivity();
    const d = useData();
    const [filter, setFilter] = useState('all'); // all | mine | theirs
    const [reactionsDoc, setReactionsDoc] = useState({});

    // Subscribe to activity reactions (stored on a dedicated doc)
    useEffect(() => {
      if(!open) return;
      const ref = window.FT.db.collection('lists').doc('activity_reactions');
      const unsub = ref.onSnapshot(doc => {
        setReactionsDoc(doc.exists ? (doc.data() || {}) : {});
      });
      return unsub;
    }, [open]);

    const toggleReaction = (entryKey, emoji) => {
      if(!me) return;
      const ref = window.FT.db.collection('lists').doc('activity_reactions');
      ref.get().then(doc => {
        const data = doc.exists ? (doc.data() || {}) : {};
        const entry = data[entryKey] || {};
        entry[emoji] = entry[emoji] || [];
        const i = entry[emoji].indexOf(me);
        if(i > -1) entry[emoji].splice(i, 1);
        else entry[emoji].push(me);
        if(!entry[emoji].length) delete entry[emoji];
        if(!Object.keys(entry).length) delete data[entryKey];
        else data[entryKey] = entry;
        ref.set(data);
      });
    };

    const timeAgo = (ts) => {
      if(!ts) return '';
      const s = Math.floor((Date.now()-ts)/1000);
      if(s<60) return 'just now';
      if(s<3600) return Math.floor(s/60)+'m';
      if(s<86400) return Math.floor(s/3600)+'h';
      const days = Math.floor(s/86400);
      if(days < 30) return days+'d';
      return new Date(ts).toLocaleDateString('en', {month:'short', day:'numeric'});
    };

    const filtered = useMemo(() => {
      if(!activity) return [];
      if(filter==='mine') return activity.filter(a => a.who === me);
      if(filter==='theirs') return activity.filter(a => a.who !== me);
      return activity;
    }, [activity, filter, me]);

    // Group by day for nice headers
    const grouped = useMemo(() => {
      const byDay = {};
      filtered.forEach(a => {
        const d = new Date(a.ts);
        const key = d.toDateString();
        (byDay[key] = byDay[key] || []).push(a);
      });
      const today = new Date().toDateString();
      const yest = new Date(Date.now()-86400000).toDateString();
      return Object.entries(byDay).map(([k, items]) => {
        const d = new Date(k);
        const label = k===today ? 'today' : k===yest ? 'yesterday' : d.toLocaleDateString('en',{weekday:'long', month:'short', day:'numeric'});
        return { key:k, label, items };
      });
    }, [filtered]);

    const navigateTo = (a) => {
      if(!a.cat) return;
      onClose();
      setTimeout(() => window.FTAPP?.navigate?.('list', a.cat, a.itemId), 50);
    };

    const REACTIONS = ['❤️','🥰','😍','🤣','✨','👀'];

    return (
      <Sheet open={open} onClose={onClose} title="Between us">
        <div style={{fontSize:12.5,color:'var(--text3)',marginBottom:14,lineHeight:1.45,fontFamily:'Caveat,cursive',fontSize:15.5}}>
          everything y'all have added, done, or sent — react to any of it ♡
        </div>

        <div style={{display:'flex',gap:4,padding:3,borderRadius:99,background:'var(--card-strong)',border:'1px solid var(--border)',marginBottom:14}}>
          {[['all','All'],['mine','Me'],['theirs','Them']].map(([k,lbl]) => (
            <button key={k} onClick={()=>setFilter(k)} style={{flex:1,padding:'6px 10px',borderRadius:99,background:filter===k?'var(--card)':'transparent',border:'none',color:filter===k?'var(--text)':'var(--text3)',fontSize:12,cursor:'pointer',fontFamily:'inherit',fontWeight:filter===k?600:400}}>{lbl}</button>
          ))}
        </div>

        {grouped.length === 0 && (
          <div style={{textAlign:'center',padding:'40px 20px',color:'var(--text3)',fontFamily:'Caveat,cursive',fontSize:17}}>
            nothing yet — go do something together ♡
          </div>
        )}

        {grouped.map(g => (
          <div key={g.key} style={{marginBottom:16}}>
            <div style={{fontSize:10.5,textTransform:'uppercase',letterSpacing:'.15em',color:'var(--text3)',margin:'8px 0 6px',fontWeight:600}}>{g.label}</div>
            {g.items.map((a, i) => {
              const entryKey = `${a.ts}-${a.who}`;
              const reactions = reactionsDoc[entryKey] || {};
              const activeEmojis = Object.keys(reactions).filter(e => reactions[e]?.length);
              return (
                <div key={entryKey+':'+i} className="ft-activity-entry">
                  <div className="ft-activity-main" onClick={()=>navigateTo(a)} style={{cursor:a.cat?'pointer':'default'}}>
                    <Avatar person={a.who} size={28}/>
                    <div style={{flex:1,minWidth:0}}>
                      <div style={{fontSize:13,color:'var(--text2)',lineHeight:1.45}}>
                        <b style={{color:'var(--text)'}}>{a.who}</b> {a.detail}
                      </div>
                      <div style={{fontSize:11,color:'var(--text3)',marginTop:2,display:'flex',gap:8,alignItems:'center'}}>
                        <span>{timeAgo(a.ts)}</span>
                        {a.cat && d?.[a.cat] && (
                          <span style={{padding:'1px 6px',borderRadius:99,background:'var(--card)',border:'1px solid var(--border)',fontSize:10}}>
                            {d[a.cat].emoji} {d[a.cat].title?.replace(/^[^\w]+\s*/,'')}
                          </span>
                        )}
                      </div>
                    </div>
                  </div>
                  <div className="ft-activity-reactions">
                    {activeEmojis.map(e => {
                      const mine = reactions[e].includes(me);
                      return (
                        <button key={e} onClick={()=>toggleReaction(entryKey, e)} className={`ft-reaction ${mine?'mine':''}`}>
                          <span className="ft-reaction-emoji">{e}</span>
                          <span className="ft-reaction-count">{reactions[e].length}</span>
                        </button>
                      );
                    })}
                    <button
                      className="ft-reaction-add"
                      onClick={(ev)=>{
                        ev.stopPropagation();
                        const menu = ev.currentTarget.nextElementSibling;
                        if(menu) menu.style.display = menu.style.display==='flex'?'none':'flex';
                      }}
                    >＋</button>
                    <div className="ft-reaction-picker">
                      {REACTIONS.map(e => (
                        <button key={e} onClick={(ev)=>{ev.stopPropagation(); toggleReaction(entryKey, e); ev.currentTarget.parentElement.style.display='none';}}>{e}</button>
                      ))}
                    </div>
                  </div>
                </div>
              );
            })}
          </div>
        ))}
      </Sheet>
    );
  }

  // export
  Object.assign(window, { AddPhotoSheet, ActivityFeedSheet });
})();
