/* ============================================================
   Админка · иконки + поля формы (экспорт в window)
   ============================================================
   Главное отличие от handoff-прототипа: загрузка медиа идёт через
   POST /api/media (бэкенд: sharp ресайз + webp + ffmpeg-постер),
   а не FileReader → base64 в localStorage. Значения изображений
   хранятся в content как 'assets/file.jpg', а в UI отображаются
   через window.mediaUrl() как '/media/file.jpg'. */
const IC = {
  cog:"M10.3 2h3.4l.5 2.3 2 .8 2-1.2 2.4 2.4-1.2 2 .8 2 2.3.5v3.4l-2.3.5-.8 2 1.2 2-2.4 2.4-2-1.2-2 .8-.5 2.3h-3.4l-.5-2.3-2-.8-2 1.2L2 17.7l1.2-2-.8-2L.1 13.2V9.8l2.3-.5.8-2L2 5.3 4.4 2.9l2 1.2 2-.8z M12 9a3 3 0 100 6 3 3 0 000-6z",
  star:"M12 3.2l1.7 4.9 4.9 1.7-4.9 1.7L12 16.4l-1.7-4.9-4.9-1.7 4.9-1.7z",
  text:"M4 5.5h16M4 10h16M4 14.5h11M4 19h7",
  image:"M3.2 5.4h17.6v13.2H3.2zM3.6 15.5l4.6-4.3 3.4 3.2 3-2.7 5.8 5.2M8.4 9.6a1.4 1.4 0 100 .01",
  grid:"M4 4h7v7H4zM13 4h7v7h-7zM4 13h7v7H4zM13 13h7v7h-7z",
  tag:"M4 4h7l9 9-7 7-9-9zM8 8h.01",
  list:"M8 6h12M8 12h12M8 18h12M3.5 6h.01M3.5 12h.01M3.5 18h.01",
  user:"M12 12a4 4 0 100-8 4 4 0 000 8zM4.5 20a7.5 7.5 0 0115 0",
  mail:"M3.5 5.5h17v13h-17zM3.8 6.2l8.2 6 8.2-6",
  plus:"M12 5v14M5 12h14", x:"M6 6l12 12M18 6L6 18",
  check:"M4 12.5l5 5 11-11", clock:"M12 7.4V12l3.2 2 M12 3.8a8.2 8.2 0 100 16.4 8.2 8.2 0 000-16.4z",
  drag:"M9 5h.01M9 12h.01M9 19h.01M15 5h.01M15 12h.01M15 19h.01",
  eye:"M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7S2 12 2 12zM12 9a3 3 0 100 6 3 3 0 000-6z",
  rocket:"M5 15c-1.5 1.5-2 5-2 5s3.5-.5 5-2M9 11a14 14 0 018-8c2 0 3 1 3 3a14 14 0 01-8 8l-3-3zM14 8.5a1.5 1.5 0 100 .01",
  history:"M3 12a9 9 0 109-9 9 9 0 00-7.5 4M3 4v4h4M12 7.5V12l3 2",
  menu:"M4 6h16M4 12h16M4 18h16", back:"M14 6l-6 6 6 6",
  tg:"M21.9 4.3 18.7 19.6c-.2 1-.9 1.3-1.8.8l-4.9-3.6-2.4 2.3c-.3.3-.5.5-1 .5l.3-5 9.2-8.3c.4-.4-.1-.6-.6-.2L6.1 13.1l-4.9-1.5c-1-.3-1-1 .2-1.6l19.2-7.4c.9-.3 1.6.2 1.4 1.7z"
};
function Icon({ n, w }) {
  return (<svg width={w||18} height={w||18} viewBox="0 0 24 24" fill={n==="tg"?"currentColor":"none"} stroke={n==="tg"?"none":"currentColor"} strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><path d={IC[n]} /></svg>);
}

/* ---- API upload helper ----
   POST multipart /api/media → { name, src, url, type }. На время загрузки
   рисуем спиннер. На ошибке зовём cbError если он есть, иначе alert. */
async function uploadMedia(file, onProgress) {
  const fd = new FormData();
  fd.append('file', file);
  if (onProgress) onProgress(true);
  try {
    const r = await fetch('/api/media', { method: 'POST', body: fd, credentials: 'same-origin' });
    const j = await r.json();
    if (!r.ok) throw new Error(j.error || ('HTTP ' + r.status));
    return j;  // { name, src: 'assets/...', url: '/media/...', type, poster? }
  } finally {
    if (onProgress) onProgress(false);
  }
}

/* ---- helpers ---- */
function Counter({ v, max }) {
  if (!max) return null;
  const len = (typeof v === 'string' ? v : '').length;
  const over = len > max;
  return <span className={"counter"+(over?" over":"")}>{len}/{max}</span>;
}

/* ---- basic fields ---- */
function Field({ label, hint, counter, children }) {
  return (<div className="field">
    <div className="field-top"><span className="field-label">{label}</span>{counter}</div>
    {hint && <div className="field-hint">{hint}</div>}
    {children}
  </div>);
}
function TextField({ f, val, on }) {
  const over = f.max && (val||"").length > f.max;
  return (<Field label={f.label} hint={f.hint} counter={<Counter v={val} max={f.max} />}>
    <input className={"inp"+(f.type==="url"?" url":"")+(over?" over":"")} value={val||""} placeholder={f.type==="url"?"https://…":""} onChange={e=>on(e.target.value)} />
  </Field>);
}
function TextArea({ f, val, on }) {
  const over = f.max && (val||"").length > f.max;
  return (<Field label={f.label} hint={f.hint} counter={<Counter v={val} max={f.max} />}>
    <textarea className={"ta"+(over?" over":"")} value={val||""} onChange={e=>on(e.target.value)} />
  </Field>);
}

/* ---- list (strings, reorderable + touch ←→) ---- */
function ListField({ f, val, on }) {
  const arr = val||[];
  const [drag, setDrag] = React.useState(-1);
  const move = (from,to)=>{ if(to<0||to>=arr.length||from===to)return; const a=arr.slice(); const [x]=a.splice(from,1); a.splice(to,0,x); on(a); };
  return (<Field label={f.label} hint={f.hint}>
    <div className="rows">
      {arr.map((s,i)=>(
        <div className="row" key={i} draggable onDragStart={()=>setDrag(i)} onDragOver={e=>e.preventDefault()} onDrop={()=>{if(drag>-1)move(drag,i);setDrag(-1);}}>
          <span className="row-handle"><Icon n="drag" w={16}/></span>
          <input className="inp" value={s} maxLength={f.max?f.max+20:undefined} onChange={e=>{const a=arr.slice();a[i]=e.target.value;on(a);}} />
          <button className="row-del" onClick={()=>on(arr.filter((_,j)=>j!==i))}><Icon n="x" w={15}/></button>
        </div>
      ))}
    </div>
    <button className="addbtn" onClick={()=>on(arr.concat(["Новый пункт"]))}><Icon n="plus" w={15}/> Добавить</button>
  </Field>);
}
function ParasField({ f, val, on }) {
  const arr = val||[];
  return (<Field label={f.label} hint={"До 3 абзацев · до "+f.max+" симв. каждый"}>
    <div className="rows">
      {arr.map((s,i)=>(
        <div key={i}>
          <div className="field-top" style={{marginBottom:6}}><span className="sub-label">Абзац {i+1}</span><span style={{display:"flex",gap:10,alignItems:"center"}}><Counter v={s} max={f.max}/><button className="row-del" onClick={()=>on(arr.filter((_,j)=>j!==i))}><Icon n="x" w={15}/></button></span></div>
          <textarea className={"ta"+((s||"").length>f.max?" over":"")} value={s} onChange={e=>{const a=arr.slice();a[i]=e.target.value;on(a);}} />
        </div>
      ))}
    </div>
    {arr.length<3 && <button className="addbtn" onClick={()=>on(arr.concat([""]))}><Icon n="plus" w={15}/> Добавить абзац</button>}
  </Field>);
}
function ChipsField({ f, val, on }) {
  const arr = val||[]; const [t,setT]=React.useState("");
  const add=()=>{const v=t.trim();if(v){on(arr.concat([v]));setT("");}};
  return (<Field label={f.label} hint={f.hint}>
    <div className="chips">{arr.map((c,i)=>(<span className="chip" key={i}>{c}<button onClick={()=>on(arr.filter((_,j)=>j!==i))}><Icon n="x" w={13}/></button></span>))}</div>
    <div className="chip-add"><input className="inp" placeholder="Новый тег…" value={t} maxLength={f.max} onChange={e=>setT(e.target.value)} onKeyDown={e=>e.key==="Enter"&&add()} /><button className="btn btn--sm" onClick={add}>Добавить</button></div>
  </Field>);
}

/* ---- image / video uploaders (API upload) ---- */
function ImageField({ f, val, on, wide }) {
  const [over,setOver]=React.useState(false);
  const [loading,setLoading]=React.useState(false);
  const [err,setErr]=React.useState("");
  const pick = async (files) => {
    if (!files || !files[0]) return;
    setErr("");
    try {
      const r = await uploadMedia(files[0], setLoading);
      on(r.src); // 'assets/<name>'
    } catch (e) { setErr(e.message || 'Ошибка загрузки'); }
  };
  return (<Field label={f.label} hint={f.hint || "Загрузи фото — система сама сожмёт и сделает webp"}>
    <div className="uploader">
      <div className={"thumb"+(wide?" thumb--wide":"")+(loading?" thumb--loading":"")}>
        {val && <img src={window.mediaUrl(val)} alt="" />}
        {loading && <span className="spin"></span>}
      </div>
      <div>
        <label className={"drop"+(over?" over":"")} onDragOver={e=>{e.preventDefault();setOver(true);}} onDragLeave={()=>setOver(false)} onDrop={e=>{e.preventDefault();setOver(false);pick(e.dataTransfer.files);}}>
          <b>{loading ? 'Загружаем…' : 'Перетащи фото или нажми, чтобы выбрать'}</b>
          <small>JPG/PNG · авто-ресайз до 2000px, webp-сосед</small>
          <input type="file" accept="image/*" hidden disabled={loading} onChange={e=>{pick(e.target.files); e.target.value='';}} />
        </label>
        <div className="opt-badge"><Icon n="check" w={14}/> авто-ресайз · webp · сжатие</div>
        {err && <div className="err-line">{err}</div>}
      </div>
    </div>
  </Field>);
}
function VideoField({ f, val, on }) {
  const [over,setOver]=React.useState(false);
  const [loading,setLoading]=React.useState(false);
  const [err,setErr]=React.useState("");
  const pick = async (files) => {
    if (!files || !files[0]) return;
    setErr("");
    try {
      const r = await uploadMedia(files[0], setLoading);
      on(r.src); // 'assets/<name.mp4>'. Постер автоматически рядом: <name>-poster.jpg
    } catch (e) { setErr(e.message || 'Ошибка загрузки'); }
  };
  return (<Field label={f.label} hint={f.hint || "mp4 · авто-постер из первого кадра + сжатие"}>
    <div className="uploader">
      <div className={"thumb"+(loading?" thumb--loading":"")}>
        {val && <video src={window.mediaUrl(val)} muted autoPlay loop playsInline />}
        {loading && <span className="spin"></span>}
      </div>
      <div>
        <label className={"drop"+(over?" over":"")} onDragOver={e=>{e.preventDefault();setOver(true);}} onDragLeave={()=>setOver(false)} onDrop={e=>{e.preventDefault();setOver(false);pick(e.dataTransfer.files);}}>
          <b>{loading ? 'Загружаем…' : 'Перетащи видео или нажми, чтобы выбрать'}</b>
          <small>mp4 · рекомендуем вертикальное, до ~50 МБ</small>
          <input type="file" accept="video/*" hidden disabled={loading} onChange={e=>{pick(e.target.files); e.target.value='';}} />
        </label>
        <div className="opt-badge"><Icon n="check" w={14}/> авто-постер · сжатие · до 200 МБ</div>
        {err && <div className="err-line">{err}</div>}
      </div>
    </div>
  </Field>);
}

/* ---- gallery (drag reorder + ←→ кнопки + add + delete) ---- */
function GalleryField({ f, val, on }) {
  const arr = val||[];
  const [drag,setDrag]=React.useState(-1);
  const [over,setOver]=React.useState(-1);
  const [loading,setLoading]=React.useState(false);
  const move=(from,to)=>{ if(to<0||to>=arr.length||from===to)return; const a=arr.slice(); const[x]=a.splice(from,1); a.splice(to,0,x); on(a); };
  const add = async (files) => {
    setLoading(true);
    let next = arr.slice();
    for (const file of files) {
      try {
        const r = await uploadMedia(file);
        next = next.concat([{ src: r.src, alt: '' }]);
        on(next); // обновляем по одному, чтобы UI был отзывчив
      } catch (e) { console.error('gallery upload failed', e); }
    }
    setLoading(false);
  };
  return (<Field label={f.label} hint="Перетаскивай для порядка · стрелки ‹ › работают и на телефоне">
    <div className="gal">
      {arr.map((p,i)=>(
        <div key={i} className={"gal-item"+(drag===i?" dragging":"")+(over===i?" over":"")}
          draggable onDragStart={()=>setDrag(i)} onDragEnter={()=>setOver(i)}
          onDragOver={e=>e.preventDefault()} onDrop={()=>{if(drag>-1)move(drag,i);setDrag(-1);setOver(-1);}} onDragEnd={()=>{setDrag(-1);setOver(-1);}}>
          <img src={window.mediaUrl(p.src)} alt="" />
          <span className="num">{i+1}</span>
          <button className="x" onClick={()=>on(arr.filter((_,j)=>j!==i))} title="Удалить"><Icon n="x" w={14}/></button>
          <button className="gal-move gal-move--prev" onClick={()=>move(i,i-1)} title="Сдвинуть назад">‹</button>
          <button className="gal-move gal-move--next" onClick={()=>move(i,i+1)} title="Сдвинуть вперёд">›</button>
        </div>
      ))}
      <label className={"gal-add"+(loading?" gal-add--loading":"")}>
        {loading ? <span className="spin"></span> : <Icon n="plus" w={20}/>}
        <span>{loading ? 'Загружаем…' : 'Добавить фото'}</span>
        <input type="file" accept="image/*" multiple hidden disabled={loading} onChange={e=>{add([...e.target.files]); e.target.value='';}} />
      </label>
    </div>
  </Field>);
}

/* ---- steps ---- */
function StepsField({ f, val, on }) {
  const arr = val||[];
  return (<Field label={f.label} hint={"Номер + текст (до "+f.max+" симв.)"}>
    <div className="rows">
      {arr.map((s,i)=>(
        <div className="step-row" key={i}>
          <input className="inp n mono" value={s.n} onChange={e=>{const a=window.deepClone(arr);a[i].n=e.target.value;on(a);}} />
          <input className={"inp"+((s.text||"").length>f.max?" over":"")} value={s.text} onChange={e=>{const a=window.deepClone(arr);a[i].text=e.target.value;on(a);}} />
          <button className="row-del" onClick={()=>on(arr.filter((_,j)=>j!==i))}><Icon n="x" w={15}/></button>
        </div>
      ))}
    </div>
    <button className="addbtn" onClick={()=>on(arr.concat([{n:String(arr.length+1).padStart(2,"0"),text:""}]))}><Icon n="plus" w={15}/> Добавить шаг</button>
  </Field>);
}

/* ---- packages ----
   Добавлено: image (фото пакета — есть на live-сайте, нужно редактировать) */
function PackagesField({ f, val, on }) {
  const arr = val||[];
  const upd=(i,k,v)=>{const a=window.deepClone(arr);a[i][k]=v;on(a);};
  const blank={name:"Новый пакет",badge:"",price:0,byRequest:false,note:"",image:"",features:["Пункт 1"],ctaText:"Обсудить съёмку",ctaLink:"https://t.me/trocalina"};
  return (<Field label={f.label} hint="Пакеты съёмок · цена числом или «по запросу»">
    {arr.map((p,i)=>{
      const moveUp = () => { if (i>0){ const a=arr.slice(); [a[i-1],a[i]]=[a[i],a[i-1]]; on(a); } };
      const moveDn = () => { if (i<arr.length-1){ const a=arr.slice(); [a[i+1],a[i]]=[a[i],a[i+1]]; on(a); } };
      return (
        <div className="pk-edit" key={i}>
          <div className="pk-edit__head">
            <input className="inp" value={p.name} placeholder="Название" onChange={e=>upd(i,"name",e.target.value)} />
            <button className="row-del" onClick={moveUp} title="Вверх">↑</button>
            <button className="row-del" onClick={moveDn} title="Вниз">↓</button>
            <button className="row-del" onClick={()=>on(arr.filter((_,j)=>j!==i))} title="Удалить пакет"><Icon n="x" w={15}/></button>
          </div>

          <div style={{marginBottom:10}}>
            <div className="sub-label">Фото пакета</div>
            <PkgImage val={p.image} on={(v)=>upd(i,"image",v)} />
          </div>

          <div className="pk-grid">
            <div><div className="sub-label">Бейдж</div><input className="inp" value={p.badge} placeholder="напр. чаще выбирают" onChange={e=>upd(i,"badge",e.target.value)} /></div>
            <div><div className="sub-label">Цена</div>
              <div style={{display:"flex",gap:10,alignItems:"center"}}>
                <input className="inp mono" type="number" disabled={p.byRequest} value={p.price} onChange={e=>upd(i,"price",+e.target.value)} style={{flex:1,opacity:p.byRequest?.5:1}} />
                <label className="toggle"><input type="checkbox" checked={p.byRequest} onChange={e=>upd(i,"byRequest",e.target.checked)} /><span className="tr"></span>по запросу</label>
              </div>
            </div>
          </div>

          <div style={{marginTop:10}}><div className="sub-label">Что входит</div>
            <div className="rows">
              {(p.features||[]).map((ft,fi)=>(
                <div className="row" key={fi}>
                  <input className="inp" value={ft} onChange={e=>{const a=window.deepClone(arr);a[i].features[fi]=e.target.value;on(a);}} />
                  <button className="row-del" onClick={()=>{const a=window.deepClone(arr);a[i].features.splice(fi,1);on(a);}}><Icon n="x" w={15}/></button>
                </div>
              ))}
            </div>
            <button className="addbtn" onClick={()=>{const a=window.deepClone(arr);a[i].features.push("Новый пункт");on(a);}}><Icon n="plus" w={15}/> Пункт</button>
          </div>

          <div className="pk-grid" style={{marginTop:10}}>
            <div><div className="sub-label">Кнопка — текст</div><input className="inp" value={p.ctaText||""} onChange={e=>upd(i,"ctaText",e.target.value)} /></div>
            <div><div className="sub-label">Кнопка — ссылка</div><input className="inp url" value={p.ctaLink||""} onChange={e=>upd(i,"ctaLink",e.target.value)} /></div>
          </div>
        </div>
      );
    })}
    <button className="addbtn" onClick={()=>on(arr.concat([window.deepClone(blank)]))}><Icon n="plus" w={15}/> Добавить пакет</button>
  </Field>);
}

/* Компактный image-pickup внутри пакета (без отдельной field-обёртки) */
function PkgImage({ val, on }) {
  const [loading,setLoading]=React.useState(false);
  const [err,setErr]=React.useState("");
  const pick = async (files) => {
    if (!files || !files[0]) return;
    setErr("");
    try { const r = await uploadMedia(files[0], setLoading); on(r.src); }
    catch (e) { setErr(e.message || 'Ошибка загрузки'); }
  };
  return (<div className="uploader">
    <div className={"thumb"+(loading?" thumb--loading":"")}>
      {val && <img src={window.mediaUrl(val)} alt="" />}
      {loading && <span className="spin"></span>}
    </div>
    <label className="drop" style={{flex:1}}>
      <b>{loading ? 'Загружаем…' : 'Заменить фото'}</b>
      <small>JPG/PNG/WebP · авто-оптимизация</small>
      <input type="file" accept="image/*" hidden disabled={loading} onChange={e=>{pick(e.target.files); e.target.value='';}} />
    </label>
    {err && <div className="err-line">{err}</div>}
  </div>);
}

/* ---- dispatcher ---- */
function FieldRenderer({ f, val, on }) {
  switch (f.type) {
    case "textarea": return <TextArea f={f} val={val} on={on} />;
    case "list": return <ListField f={f} val={val} on={on} />;
    case "paras": return <ParasField f={f} val={val} on={on} />;
    case "chips": return <ChipsField f={f} val={val} on={on} />;
    case "image": return <ImageField f={f} val={val} on={on} wide={f.key==="image"||f.key==="ogImage"} />;
    case "video": return <VideoField f={f} val={val} on={on} />;
    case "gallery": return <GalleryField f={f} val={val} on={on} />;
    case "steps": return <StepsField f={f} val={val} on={on} />;
    case "packages": return <PackagesField f={f} val={val} on={on} />;
    default: return <TextField f={f} val={val} on={on} />;
  }
}

Object.assign(window, { Icon, FieldRenderer });
