/* ============================================================
   Төрмен — ratings & reviews (Medusa API + fallback)
   Bilingual RU/KZ. Avatars are initials, no stock faces.
   ============================================================ */
const { useState:useStateR, useEffect:useEffectR, useCallback:useCbR } = React;

const REVIEW_DEFAULT = { rating:0, count:0, dist:[0,0,0,0,0], recommend:0, list:[] };
const STORE_SOURCES = [
  { id:'2gis',   icon:'map-pin',   label:'2ГИС',     rating:4.8, count:'420' },
  { id:'insta',  icon:'instagram', label:'Instagram', rating:4.9, count:'760' },
  { id:'tg',     icon:'send',      label:'Telegram',  rating:5.0, count:'660' },
];

function reviewsApiEnabled(){
  return window.isMedusaConfigured?.() && typeof window.medusaFetch === 'function';
}

function getVoterKey(){
  const key = 'tormen_voter_key';
  let id = localStorage.getItem(key);
  if(!id){
    id = 'v_' + Math.random().toString(36).slice(2) + Date.now().toString(36);
    localStorage.setItem(key, id);
  }
  return id;
}

function formatReviewDate(iso, lang){
  if(!iso) return lang==='kz' ? 'жаңа ғана' : 'только что';
  const diffDays = Math.max(0, Math.floor((Date.now() - new Date(iso).getTime()) / 86400000));
  if(lang==='kz'){
    if(diffDays < 1) return 'жаңа ғана';
    if(diffDays < 7) return `${diffDays} күн бұрын`;
    if(diffDays < 30) return `${Math.max(1, Math.floor(diffDays/7))} апта бұрын`;
    return `${Math.max(1, Math.floor(diffDays/30))} ай бұрын`;
  }
  if(diffDays < 1) return 'только что';
  if(diffDays < 7) return diffDays === 1 ? 'вчера' : `${diffDays} дн. назад`;
  if(diffDays < 30) return `${Math.max(1, Math.floor(diffDays/7))} нед. назад`;
  return `${Math.max(1, Math.floor(diffDays/30))} мес. назад`;
}

const REVIEW_MAX_PHOTOS = 4;
const REVIEW_MAX_PHOTO_BYTES = 5 * 1024 * 1024;

function parseReviewImages(raw){
  if(!raw) return [];
  const list = Array.isArray(raw) ? raw : [];
  return list
    .map(url=> window.normalizeMedusaAssetUrl?.(url) || url)
    .filter(url=> typeof url === 'string' && url.startsWith('http'));
}

function mapApiReview(row){
  const created = row.created_at || row.updated_at;
  return {
    id: row.id,
    n: row.author_name,
    d: { ru: formatReviewDate(created, 'ru'), kz: formatReviewDate(created, 'kz') },
    s: row.rating,
    p: row.persons || null,
    t: { ru: row.text_ru, kz: row.text_kz || row.text_ru },
    images: parseReviewImages(row.images),
    verified: !!row.verified,
    h: row.helpful_count ?? 0,
    voted_by_me: !!row.voted_by_me,
    fresh: false,
  };
}

async function uploadReviewImages(files){
  if(!files?.length) return [];
  const env = window.TORMEN_ENV?.medusa || {};
  const fd = new FormData();
  files.forEach(file=> fd.append('files', file));
  const ctrl = new AbortController();
  const timer = setTimeout(()=> ctrl.abort(), 30000);
  let res;
  try{
    res = await fetch(`${env.backendUrl}/store/tormen/reviews/upload`, {
      method: 'POST',
      headers: { 'x-publishable-api-key': env.publishableKey },
      body: fd,
      signal: ctrl.signal,
    });
  }finally{ clearTimeout(timer); }
  let data = {};
  try{ data = await res.json(); }catch(_){}
  if(!res.ok) throw new Error(data.message || data.type || 'upload_failed');
  return (data.files || []).map(f=> window.normalizeMedusaAssetUrl?.(f.url) || f.url).filter(Boolean);
}

async function fetchReviewSummary(scope, productHandle){
  const q = new URLSearchParams({ scope });
  if(productHandle) q.set('product_handle', productHandle);
  const data = await window.medusaFetch(`/store/tormen/reviews/summary?${q}`);
  return data.summary || REVIEW_DEFAULT;
}

async function fetchReviews(scope, productHandle, limit=50){
  const q = new URLSearchParams({ scope, limit: String(limit), voter_key: getVoterKey() });
  if(productHandle) q.set('product_handle', productHandle);
  const data = await window.medusaFetch(`/store/tormen/reviews?${q}`);
  return (data.reviews || []).map(mapApiReview);
}

async function submitReview(payload){
  return window.medusaFetch('/store/tormen/reviews', { method:'POST', body: payload, auth: true });
}

async function voteReviewHelpful(reviewId){
  return window.medusaFetch(`/store/tormen/reviews/${reviewId}/helpful`, {
    method:'POST',
    auth: false,
    body: { voter_key: getVoterKey() },
  });
}

function reviewsFor(id){ return REVIEW_DEFAULT; }

function useReviewBundle(scope, productHandle){
  const [summary,setSummary]=useStateR(null);
  const [items,setItems]=useStateR([]);
  const [loading,setLoading]=useStateR(true);
  const [error,setError]=useStateR(null);

  const reload = useCbR(async ()=>{
    if(!reviewsApiEnabled()){
      setSummary(REVIEW_DEFAULT);
      setItems([]);
      setLoading(false);
      setError('offline');
      return;
    }
    setLoading(true);
    setError(null);
    try{
      const [sum, list] = await Promise.all([
        fetchReviewSummary(scope, productHandle),
        fetchReviews(scope, productHandle),
      ]);
      setSummary(sum);
      setItems(list);
    }catch(e){
      setSummary(REVIEW_DEFAULT);
      setItems([]);
      setError(e?.message || 'reviews_failed');
    }finally{
      setLoading(false);
    }
  }, [scope, productHandle]);

  useEffectR(()=>{ reload(); }, [reload]);

  const patchItem = useCbR((reviewId, patch)=>{
    setItems(prev=> prev.map(item=> item.id === reviewId ? { ...item, ...patch } : item));
  }, []);

  return { summary: summary || REVIEW_DEFAULT, items, loading, error, reload, patchItem };
}

function useReviewSummary(scope, productHandle){
  const { summary, loading } = useReviewBundle(scope, productHandle);
  return { summary, loading };
}

/* ---------- avatar (initials) ---------- */
function Avatar({ name='', size=42 }){
  const init = (name.trim()[0]||'?').toUpperCase();
  return (
    <span className="grid place-items-center rounded-full shrink-0 serif" style={{
      width:size, height:size, background:'linear-gradient(135deg,var(--ember-2),var(--wine))', color:'var(--gold-2)',
      fontWeight:600, fontSize:size*0.42, fontStyle:'italic',
      boxShadow:'inset 0 1px 0 rgba(255,255,255,0.18)' }}>{init}</span>
  );
}

/* ---------- rating distribution bars ---------- */
function RatingBars({ dist }){
  return (
    <div className="flex flex-col gap-2 w-full">
      {dist.map((pct,i)=>(
        <div key={i} className="flex items-center gap-3">
          <span className="tnum text-[11px] w-3 text-right" style={{ color:'var(--ink-3)' }}>{5-i}</span>
          <span className="flex-1 rounded-full overflow-hidden" style={{ height:3, background:'var(--surface-2)' }}>
            <span className="block h-full rounded-full" style={{ width:pct+'%', background:'linear-gradient(90deg,var(--gold),var(--ember))' }} />
          </span>
          <span className="tnum text-[11px] w-8 text-right" style={{ color:'var(--ink-3)' }}>{pct}%</span>
        </div>
      ))}
    </div>
  );
}

/* ---------- overview block (editorial band: big score + slim bars) ---------- */
function RatingOverview({ rating, count, dist, sources, recommend, className='' }){
  const { t } = useLang();
  return (
    <div className={className}>
      <div className="flex items-end gap-4">
        <span className="display grad-text tnum" style={{ fontSize:'clamp(64px,7vw,80px)', lineHeight:0.9 }}>{rating.toFixed(1)}</span>
        <div className="pb-1.5">
          <Stars value={rating} size={15} />
          <div className="text-xs mt-1.5 tnum" style={{ color:'var(--ink-3)' }}>{count.toLocaleString('ru-RU').replace(/,/g,' ')} {t('rev_reviews')}</div>
        </div>
      </div>
      {recommend!=null && (
        <div className="flex items-center gap-2 mt-4 text-sm" style={{ color:'var(--ink-2)' }}>
          <Icon name="thumbs-up" size={15} style={{ color:'var(--emerald)' }} />
          <span><span className="font-semibold tnum" style={{ color:'var(--ink)' }}>{recommend}%</span> {t('rev_recommend')}</span>
        </div>
      )}
      <hr className="hairline my-5" />
      <RatingBars dist={dist} />
      {sources && (
        <React.Fragment>
          <hr className="hairline my-5" />
          <div className="flex flex-wrap gap-2">
            {sources.map(s=>(
              <span key={s.id} className="inline-flex items-center gap-1.5 py-1.5 px-3 rounded-full" style={{ background:'var(--surface-1)', border:'1px solid var(--border)' }}>
                <Icon name={s.icon} size={13} style={{ color:'var(--gold)' }} />
                <span className="tnum text-sm font-semibold" style={{ color:'var(--ink)' }}>{s.rating.toFixed(1)}</span>
                <span className="text-[11px]" style={{ color:'var(--ink-3)' }}>{s.label}</span>
              </span>
            ))}
          </div>
        </React.Fragment>
      )}
    </div>
  );
}

/* ---------- review photo lightbox (in-app) ---------- */
function ReviewPhotoLightbox({ images, index, onIndexChange, onClose }){
  const n = images.length;
  const move = (d)=> onIndexChange((index + d + n) % n);
  useEffectR(()=>{
    const prev = document.body.style.overflow;
    document.body.style.overflow = 'hidden';
    const h=(e)=>{
      if(e.key==='Escape') onClose();
      if(n>1 && e.key==='ArrowRight') move(1);
      if(n>1 && e.key==='ArrowLeft') move(-1);
    };
    window.addEventListener('keydown', h);
    return ()=>{ document.body.style.overflow = prev; window.removeEventListener('keydown', h); };
  }, [index, n]);
  return (
    <div className="fixed inset-0 z-[140] flex items-center justify-center p-4 fade-in"
      style={{ background:'rgba(0,0,0,0.92)' }} onClick={onClose} role="dialog" aria-modal="true">
      <button type="button" onClick={onClose} className="absolute top-4 right-4 grid place-items-center rounded-full"
        style={{ width:42, height:42, background:'rgba(255,255,255,0.12)', color:'#fff' }} aria-label="Close">
        <Icon name="x" size={22} />
      </button>
      {n > 1 && (
        <React.Fragment>
          <button type="button" onClick={(e)=>{ e.stopPropagation(); move(-1); }}
            className="absolute left-3 md:left-6 grid place-items-center rounded-full"
            style={{ width:46, height:46, background:'rgba(255,255,255,0.12)', color:'#fff' }} aria-label="Previous">
            <Icon name="chevron-left" size={24} />
          </button>
          <button type="button" onClick={(e)=>{ e.stopPropagation(); move(1); }}
            className="absolute right-3 md:right-6 grid place-items-center rounded-full"
            style={{ width:46, height:46, background:'rgba(255,255,255,0.12)', color:'#fff' }} aria-label="Next">
            <Icon name="chevron-right" size={24} />
          </button>
        </React.Fragment>
      )}
      <div className="pop" onClick={e=>e.stopPropagation()} style={{ maxWidth:'min(920px,92vw)' }}>
        <img src={images[index]} alt="" className="w-full object-contain rounded-2xl"
          style={{ maxHeight:'78vh', boxShadow:'var(--shadow)' }} />
        {n > 1 && (
          <div className="flex items-center justify-center gap-2 mt-4">
            {images.map((url,i)=>(
              <button key={url+i} type="button" onClick={(e)=>{ e.stopPropagation(); onIndexChange(i); }}
                className="rounded-full transition-all"
                style={{ width:i===index?22:8, height:8, background:i===index?'var(--ember)':'rgba(255,255,255,0.4)' }}
                aria-label={`Photo ${i+1}`} />
            ))}
          </div>
        )}
      </div>
    </div>
  );
}

/* ---------- review photo strip ---------- */
function ReviewPhotoStrip({ images, className='' }){
  const [lightbox,setLightbox]=useStateR(null);
  if(!images?.length) return null;
  return (
    <React.Fragment>
      <div className={`flex gap-2 flex-wrap ${className}`}>
        {images.map((url,i)=>(
          <button key={url+i} type="button" onClick={()=>setLightbox(i)}
            className="block overflow-hidden shrink-0 transition-opacity hover:opacity-90"
            style={{ width:72, height:72, borderRadius:12, border:'1px solid var(--border-soft)', cursor:'zoom-in' }}>
            <img src={url} alt="" className="w-full h-full object-cover" loading="lazy" />
          </button>
        ))}
      </div>
      {lightbox != null && (
        <ReviewPhotoLightbox
          images={images}
          index={lightbox}
          onIndexChange={setLightbox}
          onClose={()=>setLightbox(null)}
        />
      )}
    </React.Fragment>
  );
}

/* ---------- single review card ---------- */
function ReviewCard({ r, setName, helpful, voted, onVote, plain=false }){
  const { t, tx } = useLang();
  if(plain){
    return (
      <article className="py-6 flex flex-col">
        <p className="leading-relaxed flex-1" style={{ fontSize:15, color:'var(--ink)' }}>{tx(r.t)}</p>
        <ReviewPhotoStrip images={r.images} className="mt-3" />
        <div className="flex items-center gap-3 mt-4">
          <Avatar name={r.n} size={36} />
          <div className="flex-1 min-w-0">
            <div className="flex items-center gap-2">
              <span className="font-semibold text-sm leading-tight truncate">{r.n}</span>
              <Stars value={r.s} size={12} />
            </div>
            <div className="flex flex-wrap items-center gap-x-1.5 gap-y-0.5 mt-0.5 text-[11px]" style={{ color:'var(--ink-3)' }}>
              <span>{tx(r.d)}</span>
              {r.p && <React.Fragment><span aria-hidden="true">·</span><span className="tnum">{r.p} {t('persons')}</span></React.Fragment>}
            </div>
          </div>
          {onVote && (
            <button onClick={onVote} className={`helpful-btn shrink-0 ${voted?'on':''}`}>
              <Icon name="thumbs-up" size={13} stroke={voted?0:2} style={{ fill:voted?'currentColor':'none' }} />
              {helpful!=null?helpful:''}
            </button>
          )}
        </div>
      </article>
    );
  }
  return (
    <div className="h-full flex flex-col lift" style={{ background:'var(--surface-1)', border:'1px solid var(--border-soft)', borderRadius:'var(--radius)', padding:'24px 24px 20px' }}>
      <span aria-hidden="true" className="serif block select-none" style={{ fontSize:40, lineHeight:1, height:26, color:'color-mix(in srgb,var(--gold) 30%,transparent)' }}>{'“'}</span>
      <p className="leading-relaxed flex-1" style={{ fontSize:15, color:'var(--ink)' }}>{tx(r.t)}</p>
      <ReviewPhotoStrip images={r.images} className="mt-4" />
      <div className="flex items-center gap-3 mt-5 pt-4" style={{ borderTop:'1px solid var(--border-soft)' }}>
        <Avatar name={r.n} size={38} />
        <div className="flex-1 min-w-0">
          <div className="flex items-center gap-2">
            <span className="font-semibold text-sm leading-tight truncate">{r.n}</span>
            <Stars value={r.s} size={12} />
          </div>
          <div className="flex flex-wrap items-center gap-x-1.5 gap-y-0.5 mt-0.5 text-[11px]" style={{ color:'var(--ink-3)' }}>
            <span>{tx(r.d)}</span>
            <span aria-hidden="true">·</span>
            {r.verified !== false && (
              <span className="inline-flex items-center gap-1">
                <Icon name="check-circle" size={12} style={{ color:'var(--emerald)' }} />{t('rev_verified')}
              </span>
            )}
            {r.p && <React.Fragment><span aria-hidden="true">·</span><span className="tnum">{r.p} {t('persons')}</span></React.Fragment>}
            {setName && <React.Fragment><span aria-hidden="true">·</span><span className="truncate">{setName}</span></React.Fragment>}
          </div>
        </div>
        {onVote && (
          <button onClick={onVote} className={`helpful-btn shrink-0 ${voted?'on':''}`}>
            <Icon name="thumbs-up" size={13} stroke={voted?0:2} style={{ fill:voted?'currentColor':'none' }} />
            {t('rev_helpful')}{helpful!=null?` · ${helpful}`:''}
          </button>
        )}
      </div>
    </div>
  );
}

/* ---------- sortable list with helpful votes ---------- */
function ReviewList({ items, scope, withSort=false, limit=4, plain=false, onHelpfulPatch }){
  const { t } = useLang();
  const [sort,setSort]=useStateR('new');
  const [showAll,setShowAll]=useStateR(false);
  const [busy,setBusy]=useStateR({});
  const toggleHelp = async (entry)=>{
    if(!entry.reviewId || busy[entry.reviewId] || !reviewsApiEnabled()) return;
    setBusy(b=> ({ ...b, [entry.reviewId]: true }));
    try{
      const data = await voteReviewHelpful(entry.reviewId);
      onHelpfulPatch?.(entry.reviewId, {
        h: data.review?.helpful_count ?? entry.helpful,
        voted_by_me: !!data.voted,
      });
    }catch(_){}
    finally{
      setBusy(b=>{ const n={...b}; delete n[entry.reviewId]; return n; });
    }
  };
  const enriched = items.map((r,i)=>{
    const key = r.id || (scope+'-'+i);
    return { r, id: key, reviewId: r.id, helpful: r.h ?? 0, voted: !!r.voted_by_me };
  });
  const fresh = enriched.filter(e=>e.r.fresh);
  let rest = enriched.filter(e=>!e.r.fresh);
  if(sort==='top')     rest=[...rest].sort((a,b)=> b.r.s - a.r.s);
  if(sort==='helpful') rest=[...rest].sort((a,b)=> b.helpful - a.helpful);
  const ordered=[...fresh,...rest];
  const shown = showAll ? ordered : ordered.slice(0,limit);
  return (
    <div>
      {withSort && (
        <div className="flex items-center gap-2 mb-4 flex-wrap">
          <span className="text-xs mr-1" style={{ color:'var(--ink-3)' }}>{t('rev_sort')}:</span>
          {[['new','rev_sort_new'],['top','rev_sort_top'],['helpful','rev_sort_helpful']].map(([v,k])=>
            <button key={v} className={`chip ${sort===v?'on':''}`} onClick={()=>setSort(v)}>{t(k)}</button>)}
        </div>
      )}
      <div className={plain ? 'divide-y divide-[color-mix(in_srgb,var(--border-soft)_100%,transparent)]' : 'grid sm:grid-cols-2 gap-4'}>
        {shown.map((e,i)=> plain
          ? <ReviewCard key={e.id} r={e.r} setName={e.r.fresh?e.r._setName:null} helpful={e.helpful} voted={e.voted} onVote={()=>toggleHelp(e)} plain />
          : <Reveal key={e.id} delay={(i%2)*60} className="min-w-0">
              <ReviewCard r={e.r} setName={e.r.fresh?e.r._setName:null} helpful={e.helpful} voted={e.voted} onVote={()=>toggleHelp(e)} />
            </Reveal>
        )}
      </div>
      {ordered.length>limit && (
        <button className="btn btn-ghost mt-5" onClick={()=>setShowAll(s=>!s)}>
          <Icon name={showAll?'chevron-up':'chevron-down'} size={16} />{showAll?t('back'):t('rev_show_all')+` (${ordered.length})`}
        </button>
      )}
    </div>
  );
}

/* ---------- review composer (interactive) ---------- */
function ReviewComposer({ onSubmit, plain=false, prominent=false, disabled=false }){
  const { t } = useLang();
  const fileRef = React.useRef(null);
  const [open,setOpen]=useStateR(false);
  const [stars,setStars]=useStateR(0);
  const [hover,setHover]=useStateR(0);
  const [name,setName]=useStateR('');
  const [text,setText]=useStateR('');
  const [photos,setPhotos]=useStateR([]);
  const [uploading,setUploading]=useStateR(false);
  const [done,setDone]=useStateR(false);

  const addPhotos = (fileList)=>{
    const next = [];
    for(const file of (fileList || [])){
      if(!file?.type?.startsWith('image/')) continue;
      if(file.size > REVIEW_MAX_PHOTO_BYTES) continue;
      next.push({ id: Math.random().toString(36).slice(2), file, preview: URL.createObjectURL(file) });
    }
    if(!next.length) return;
    setPhotos(prev=>{
      const room = REVIEW_MAX_PHOTOS - prev.length;
      return room > 0 ? [...prev, ...next.slice(0, room)] : prev;
    });
  };

  const removePhoto = (id)=>{
    setPhotos(prev=>{
      const hit = prev.find(p=> p.id === id);
      if(hit?.preview) URL.revokeObjectURL(hit.preview);
      return prev.filter(p=> p.id !== id);
    });
  };

  const cardShell = prominent
    ? 'rounded-2xl p-5 md:p-6'
    : plain ? 'py-4' : 'glass glass-strong p-6 pop';
  const cardStyle = prominent
    ? { background:'var(--surface-1)', border:'1px solid var(--border)' }
    : undefined;
  const fieldStyle = prominent
    ? { background:'var(--surface-2)', border:'1px solid var(--border)', borderRadius:'12px', padding:'12px 14px', color:'var(--ink)' }
    : plain
      ? { background:'transparent', border:'none', borderBottom:'1px solid var(--border-soft)', borderRadius:0, paddingLeft:0, paddingRight:0 }
      : { background:'var(--surface-1)', border:'1px solid var(--border)', color:'var(--ink)' };

  if(done){
    return (
      <div className={`${cardShell} flex items-center gap-4`} style={cardStyle}>
        <span className="grid place-items-center rounded-full shrink-0" style={{ width:48, height:48, background:'var(--emerald)', color:'var(--on-accent)' }}><Icon name="check" size={24} stroke={2.4} /></span>
        <div>
          <div className="font-semibold">{t('rev_thanks')}</div>
          <div className="text-sm" style={{ color:'var(--ink-2)' }}>{t('rev_thanks_d')}</div>
        </div>
      </div>
    );
  }
  if(!open){
    if(prominent){
      return (
        <button type="button" onClick={()=>!disabled && setOpen(true)} disabled={disabled}
          className={`${cardShell} w-full text-left transition-colors hover:brightness-[1.02] ${disabled?'opacity-60 cursor-not-allowed':''}`}
          style={cardStyle}>
          <div className="flex items-start gap-4">
            <span className="grid place-items-center rounded-full shrink-0" style={{ width:48, height:48, background:'var(--surface-2)', border:'1px solid var(--border)' }}>
              <Icon name="pen-line" size={20} style={{ color:'var(--gold)' }} />
            </span>
            <div className="flex-1 min-w-0 pt-0.5">
              <div className="font-semibold text-base mb-1">{t('rev_write')}</div>
              <div className="text-sm leading-relaxed" style={{ color:'var(--ink-2)' }}>{t('rev_write_hint')}</div>
            </div>
            <Icon name="chevron-right" size={20} className="shrink-0 mt-3" style={{ color:'var(--ink-3)' }} />
          </div>
        </button>
      );
    }
    return (
      <button className="btn btn-ghost" onClick={()=>setOpen(true)}>
        <Icon name="pen-line" size={16} style={{ color:'var(--gold)' }} />{t('rev_write')}
      </button>
    );
  }
  const submit=async ()=>{
    if(uploading || disabled) return;
    const s = stars||5;
    const payload = {
      n: name.trim() || (t('lang_name')==='ҚАЗ' ? 'Қонақ' : 'Гость'),
      d: { ru:'только что', kz:'жаңа ғана' },
      s,
      t: { ru: text || '—', kz: text || '—' },
      fresh: true,
      images: [],
    };
    setUploading(true);
    try{
      if(photos.length && reviewsApiEnabled()){
        payload.images = await uploadReviewImages(photos.map(p=> p.file));
      }
      if(onSubmit) await onSubmit(payload);
      photos.forEach(p=> p.preview && URL.revokeObjectURL(p.preview));
      setPhotos([]);
      setDone(true);
    }catch(_){}
    finally{ setUploading(false); }
  };
  const starRow = (
    <div className="flex items-center gap-1.5" role="group" aria-label={t('rev_your_rating')}>
      {[1,2,3,4,5].map(i=>(
        <button key={i} type="button" onMouseEnter={()=>setHover(i)} onMouseLeave={()=>setHover(0)} onClick={()=>setStars(i)}
          className="transition-transform hover:scale-110" style={{ lineHeight:0 }}>
          <Icon name="star" size={prominent?32:30} stroke={0} style={{ fill:(hover||stars)>=i?'var(--gold)':'var(--ink-4)', color:'transparent' }} />
        </button>
      ))}
      {prominent && stars > 0 && (
        <span className="text-sm tnum ml-2" style={{ color:'var(--ink-2)' }}>{stars}/5</span>
      )}
    </div>
  );
  return (
    <div className={cardShell} style={cardStyle}>
      {prominent && (
        <div className="flex items-center justify-between gap-3 mb-5">
          <h3 className="font-semibold text-base">{t('rev_write')}</h3>
          <button type="button" className="text-sm shrink-0" style={{ color:'var(--ink-3)' }} onClick={()=>setOpen(false)}>{t('back')}</button>
        </div>
      )}
      {prominent ? (
        <label className="block mb-5">
          <span className="text-sm font-medium block mb-2">{t('rev_your_rating')}</span>
          {starRow}
        </label>
      ) : (
        <React.Fragment>
          <div className="eyebrow mb-3">{t('rev_your_rating')}</div>
          <div className="mb-4">{starRow}</div>
        </React.Fragment>
      )}
      <label className={`block ${prominent?'mb-4':'mb-3'}`}>
        {prominent && <span className="text-sm font-medium block mb-2">{t('name_f')}</span>}
        <input value={name} onChange={e=>setName(e.target.value)} placeholder={prominent ? t('name_f') : t('name_f')}
          className="w-full text-sm outline-none"
          style={{ ...fieldStyle, color:'var(--ink)' }} />
      </label>
      <label className={`block ${prominent?'mb-5':'mb-4'}`}>
        {prominent && <span className="text-sm font-medium block mb-2">{t('rev_your_text')}</span>}
        <textarea value={text} onChange={e=>setText(e.target.value)} placeholder={t('rev_placeholder')} rows={prominent?4:3}
          className="w-full text-sm outline-none resize-none"
          style={{ ...fieldStyle, color:'var(--ink)' }} />
      </label>
      <div className={`${prominent?'mb-5':'mb-4'}`}>
        <input ref={fileRef} type="file" accept="image/*" multiple className="hidden"
          onChange={e=>{ addPhotos(e.target.files); e.target.value=''; }} />
        <div className="flex flex-wrap items-center gap-2">
          {photos.map(p=>(
            <div key={p.id} className="relative shrink-0" style={{ width:72, height:72 }}>
              <img src={p.preview} alt="" className="w-full h-full object-cover rounded-xl"
                style={{ border:'1px solid var(--border)' }} />
              <button type="button" onClick={()=>removePhoto(p.id)}
                className="absolute -top-1.5 -right-1.5 grid place-items-center rounded-full"
                style={{ width:22, height:22, background:'var(--wine)', color:'#fff' }}
                aria-label="Remove photo">
                <Icon name="x" size={12} stroke={2.4} />
              </button>
            </div>
          ))}
          {photos.length < REVIEW_MAX_PHOTOS && (
            <button type="button" onClick={()=>fileRef.current?.click()} disabled={disabled || uploading}
              className="inline-flex items-center gap-2 text-sm px-3 py-2 rounded-xl transition-colors hover:brightness-110"
              style={{ border:'1px dashed var(--border)', color:'var(--ink-2)', background:'var(--surface-2)' }}>
              <Icon name="camera" size={16} style={{ color:'var(--gold)' }} />{t('rev_add_photo')}
            </button>
          )}
        </div>
        <div className="text-xs mt-2" style={{ color:'var(--ink-3)' }}>{t('rev_photos_hint')}</div>
      </div>
      <div className={`flex gap-3 ${prominent?'flex-col sm:flex-row':''}`}>
        <button type="button" className={`btn btn-primary ${prominent?'w-full sm:w-auto':''}`}
          onClick={submit} disabled={disabled || uploading || !text.trim()}>
          <span className="shine"></span>
          <Icon name={uploading?'loader':'send'} size={16} className={uploading?'spin':''} />
          {uploading ? t('rev_uploading') : t('rev_submit')}
        </button>
        {!prominent && <button type="button" className="btn btn-ghost" onClick={()=>setOpen(false)}>{t('back')}</button>}
      </div>
    </div>
  );
}

/* ---------- compact stars for product header ---------- */
function StoreRatingStat(){
  const { t } = useLang();
  const { summary, loading } = useReviewSummary('store');
  const n = loading ? '…' : (summary.count ? summary.rating.toFixed(1) : '—');
  return <Stat n={n} l={t('stat_rating')} star />;
}

function ReviewStars({ productHandle, className='' }){
  const { summary, loading } = useReviewSummary('product', productHandle);
  if(loading) return <span className={`text-xs tnum ${className}`} style={{ color:'var(--ink-3)' }}>…</span>;
  if(!summary.count) return null;
  return (
    <span className={`inline-flex items-center gap-2 ${className}`}>
      <Stars value={summary.rating} />
      <span className="text-xs tnum" style={{ color:'var(--ink-3)' }}>{summary.rating.toFixed(1)} · {summary.count}</span>
    </span>
  );
}

/* ---------- product reviews section ---------- */
function ProductReviews({ setId, setName, medusaProductId, plain=false }){
  const { t, lang } = useLang();
  const { summary, items, loading, patchItem } = useReviewBundle('product', setId);
  const [submitting,setSubmitting]=useStateR(false);

  const onSubmit = async (r)=>{
    if(!reviewsApiEnabled()) return;
    setSubmitting(true);
    try{
      const text = lang==='kz' ? (r.t.kz || r.t.ru) : (r.t.ru || r.t.kz);
      await submitReview({
        scope: 'product',
        product_handle: setId,
        product_id: medusaProductId || undefined,
        author_name: r.n,
        rating: r.s,
        text_ru: text,
        text_kz: r.t.kz || text,
        persons: r.p || undefined,
        images: r.images?.length ? r.images : undefined,
      });
    }catch(_){}
    finally{ setSubmitting(false); }
  };

  return (
    <div className="mt-16 pt-8 border-t border-[color-mix(in_srgb,var(--border-soft)_100%,transparent)]">
      <SectionHeader eyebrow={t('rev_eyebrow')} title={t('rev_title')} />
      <div className="grid lg:grid-cols-[minmax(0,260px)_1fr] gap-8 lg:gap-12 items-start">
        <div className="lg:sticky lg:top-24">
          {loading
            ? <div className="text-sm" style={{ color:'var(--ink-3)' }}><Icon name="loader" size={18} className="spin" /></div>
            : <RatingOverview rating={summary.rating} count={summary.count} dist={summary.dist} recommend={summary.recommend} />}
        </div>
        <div className="min-w-0 flex flex-col gap-8">
          <ReviewComposer prominent onSubmit={onSubmit} disabled={submitting || !reviewsApiEnabled()} />
          <div>
            <div className="text-sm font-semibold mb-4" style={{ color:'var(--ink)' }}>{t('rev_list_title')}</div>
            {loading
              ? <div className="text-sm py-6" style={{ color:'var(--ink-3)' }}><Icon name="loader" size={18} className="spin" /></div>
              : items.length
                ? <ReviewList items={items} scope={setId} withSort limit={4} plain={plain}
                    onHelpfulPatch={patchItem} />
                : <p className="text-sm py-4" style={{ color:'var(--ink-3)' }}>{t('rev_empty')}</p>}
          </div>
        </div>
      </div>
    </div>
  );
}

/* ---------- store-wide reviews section (home) ---------- */
function StoreReviews(){
  const { t } = useLang();
  const { summary, items, loading, patchItem } = useReviewBundle('store');
  return (
    <section className="px-5 py-14 md:py-20 max-w-6xl mx-auto">
      <Reveal><SectionHeader eyebrow={t('sec_reviews')} title={t('rev_store_t')} /></Reveal>
      <div className="grid lg:grid-cols-[340px_1fr] gap-8 lg:gap-12 items-start">
        <Reveal>
          {loading
            ? <div className="text-sm" style={{ color:'var(--ink-3)' }}><Icon name="loader" size={18} className="spin" /></div>
            : <RatingOverview rating={summary.rating} count={summary.count} dist={summary.dist} sources={STORE_SOURCES}
                recommend={summary.recommend} className="lg:sticky lg:top-24" />}
        </Reveal>
        <div className="min-w-0">
          {loading
            ? <div className="text-sm py-6" style={{ color:'var(--ink-3)' }}><Icon name="loader" size={18} className="spin" /></div>
            : <ReviewList items={items} scope="store" withSort limit={6} onHelpfulPatch={patchItem} />}
        </div>
      </div>
    </section>
  );
}

Object.assign(window, {
  STORE_SOURCES, reviewsFor,
  fetchReviewSummary, fetchReviews, submitReview,
  useReviewSummary, useReviewBundle,
  Avatar, RatingBars, RatingOverview, ReviewCard, ReviewList, ReviewComposer,
  StoreRatingStat, ReviewStars, ProductReviews, StoreReviews,
});
