

const { useState: useStateD, useEffect: useEffectD, useRef: useRefD, useMemo: useMemoD } = React;

const LEVEL_COLORS = {
  DEBUG: { tag:'var(--ink-4)' },
  INFO:  { tag:'var(--info)'  },
  WARN:  { tag:'var(--warn)'  },
  ERROR: { tag:'var(--bad)'   },
};

function fmtLogTime(ts) {
  if (typeof ts !== "number") return String(ts || "");
  const d = new Date(ts * 1000);
  return `${String(d.getHours()).padStart(2,'0')}:${String(d.getMinutes()).padStart(2,'0')}`;
}

function dayKey(ts) {
  const d = new Date(ts * 1000);
  return `${d.getFullYear()}-${String(d.getMonth()+1).padStart(2,'0')}-${String(d.getDate()).padStart(2,'0')}`;
}

function dayLabel(dk) {
  
  const [y, m, d] = dk.split("-").map(Number);
  const target = new Date(y, m - 1, d);
  const today = new Date();
  today.setHours(0, 0, 0, 0);
  const diff = Math.round((today - target) / 86400000);
  if (diff === 0) return "today";
  if (diff === 1) return "yesterday";
  return target.toLocaleDateString(undefined, { day: "numeric", month: "short" });
}

function InstanceDetail({ instance, codes, onClose, onLaunch, onStop, onReset }) {
  if (!instance) return null;
  const isRunning = instance.status === "running" || instance.status === "booting";

  
  const logs = useLiveLogs(instance.id, { limit: 500 });

  const tailRef = useRefD(null);
  const [autoscroll, setAutoscroll] = useStateD(true);
  
  const [filter, setFilter] = useStateD({ DEBUG: true, INFO: true, WARN: true, ERROR: true });
  const [levelOpen, setLevelOpen] = useStateD(false);
  
  const [tab, setTab] = useStateD("current");   
  const [selectedDay, setSelectedDay] = useStateD(null);

  useEffectD(() => {
    if (!autoscroll || !tailRef.current) return;
    tailRef.current.scrollTop = tailRef.current.scrollHeight;
  }, [logs, autoscroll]);

  const onScroll = () => {
    if (!tailRef.current) return;
    const el = tailRef.current;
    const atBottom = el.scrollHeight - el.scrollTop - el.clientHeight < 40;
    setAutoscroll(atBottom);
  };

  
  const runBoundary = useMemoD(() => {
    for (let i = logs.length - 1; i >= 0; i--) {
      const m = logs[i].msg || "";
      if (m.includes("command: launch") || m.includes("task=work_flow")) {
        return logs[i].ts;
      }
    }
    return null;
  }, [logs]);

  
  const days = useMemoD(() => {
    const s = new Set();
    logs.forEach(l => s.add(dayKey(l.ts)));
    return Array.from(s).sort().reverse();
  }, [logs]);

  
  useEffectD(() => {
    if (tab === "day" && !selectedDay && days.length > 0) {
      setSelectedDay(days[0]);
    }
  }, [tab, days, selectedDay]);

  const visibleLogs = useMemoD(() => logs.filter(l => {
    if (!filter[l.level]) return false;
    if (tab === "current") {
      return runBoundary !== null && l.ts >= runBoundary;
    }
    if (tab === "day") {
      return selectedDay && dayKey(l.ts) === selectedDay;
    }
    return true; 
  }), [logs, filter, tab, selectedDay, runBoundary]);

  const activeLevels = Object.entries(filter).filter(([_, v]) => v).map(([k]) => k);
  const levelLabel = activeLevels.length === 4 ? "all"
                     : activeLevels.length === 0 ? "none"
                     : activeLevels.join("·");

  const [shotOpen, setShotOpen] = useStateD(false);

  return (
    <aside key={instance.id} className="anim-slide-in" style={{
      width: 480, flexShrink: 0, background: 'var(--panel)', borderLeft: '1px solid var(--line)',
      display: 'flex', flexDirection: 'column', minHeight: 0,
    }}>
      {}
      <div style={{ padding:'14px 18px 12px', borderBottom:'1px solid var(--line)' }}>
        <div style={{ display:'flex', alignItems:'flex-start', justifyContent:'space-between', gap:10 }}>
          <div style={{ minWidth:0, flex:1 }}>
            <div style={{ display:'flex', alignItems:'center', gap:11, flexWrap:'wrap' }}>
              <span className="mono" style={{ fontSize:15, fontWeight:600, color:'var(--ink)' }}>{instance.name}</span>
              <StatusPill status={instance.status}/>
            </div>
            <div className="mono" style={{ fontSize:12.5, color:'var(--ink-4)', marginTop:5, display:'flex', alignItems:'center', gap:10, flexWrap:'wrap' }}>
              <span>{instance.id}</span>
              <span style={{ color:'var(--ink-5)' }}>·</span>
              <span>{instance.account}</span>
              {isRunning && instance.uptime !== "—" && (
                <>
                  <span style={{ color:'var(--ink-5)' }}>·</span>
                  <span>up {instance.uptime}</span>
                </>
              )}
            </div>
          </div>
          <button className="icon-btn" onClick={onClose}><I.X size={16}/></button>
        </div>

        {}
        <div style={{ display:'flex', alignItems:'center', gap:7, marginTop:13, flexWrap:'wrap' }}>
          {isRunning ? (
            <button className="btn btn-sm" onClick={() => onStop(instance.id)}>
              <I.Stop size={13}/> Stop
            </button>
          ) : (
            <button className="btn btn-sm btn-primary" onClick={() => onLaunch(instance.id)}>
              <I.Play size={12}/> Launch
            </button>
          )}
          <button className="btn btn-sm" onClick={() => setShotOpen(true)}>
            <I.Camera size={13}/> Screenshot
          </button>
          <button className="btn btn-sm btn-danger" onClick={() => onReset && onReset(instance.id)}>
            <I.Refresh size={13}/> Reset
          </button>
          <div style={{ flex: 1 }}/>
        </div>
      </div>

      {}
      <div style={{ flex:1, display:'flex', flexDirection:'column', minHeight:0 }}>
        {}
        <div style={{ padding:'8px 16px 4px', borderBottom:'1px dashed var(--line)', display:'flex', alignItems:'center', gap:8, background:'var(--panel-2)', flexWrap:'wrap' }}>
          {[
            ["current", "Текущий запуск"],
            ["all",     "Все"],
            ["day",     "По дням"],
          ].map(([key, label]) => (
            <button key={key} onClick={() => setTab(key)}
              className="mono" style={{
                fontSize: 11, padding:'4px 10px', borderRadius: 4,
                background: tab === key ? 'var(--card-hi)' : 'transparent',
                border: '1px solid ' + (tab === key ? 'var(--line-strong)' : 'var(--line)'),
                color: tab === key ? 'var(--ink)' : 'var(--ink-4)',
                letterSpacing: '.04em',
              }}>{label}</button>
          ))}
          {tab === "day" && (
            <select value={selectedDay || ""} onChange={(e) => setSelectedDay(e.target.value)}
              className="mono" style={{
                fontSize: 11, padding: '3px 6px', borderRadius: 4,
                background: 'var(--card-hi)', color: 'var(--ink)',
                border: '1px solid var(--line-strong)',
              }}>
              {days.length === 0 && <option value="">—</option>}
              {days.map(d => <option key={d} value={d}>{dayLabel(d)} ({d})</option>)}
            </select>
          )}
          <div style={{ flex: 1 }}/>
          <span className="mono" style={{ fontSize: 11.5, color:'var(--ink-4)' }}>{visibleLogs.length}/{logs.length}</span>

          {/* Level dropdown */}
          <div style={{ position: 'relative' }}>
            <button onClick={() => setLevelOpen(o => !o)}
              className="mono" style={{
                fontSize: 11, padding: '4px 9px', borderRadius: 4,
                background: 'var(--card-hi)', color: 'var(--ink)',
                border: '1px solid var(--line-strong)',
              }}>levels: {levelLabel} ▾</button>
            {levelOpen && (
              <>
                <div onClick={() => setLevelOpen(false)} style={{ position: 'fixed', inset: 0, zIndex: 60 }}/>
                <div style={{
                  position: 'absolute', right: 0, top: '100%', marginTop: 4, zIndex: 61,
                  background: 'var(--panel)', border: '1px solid var(--line-strong)',
                  borderRadius: 6, padding: '6px 0', minWidth: 130,
                  boxShadow: '0 8px 24px rgba(0,0,0,0.4)',
                }}>
                  {Object.keys(filter).map(lvl => (
                    <button key={lvl} onClick={() => setFilter(f => ({ ...f, [lvl]: !f[lvl] }))}
                      className="mono" style={{
                        display: 'flex', alignItems: 'center', gap: 8,
                        fontSize: 11, padding: '5px 12px', width: '100%',
                        background: 'transparent', border: 'none', textAlign: 'left',
                        color: filter[lvl] ? LEVEL_COLORS[lvl].tag : 'var(--ink-5)',
                        cursor: 'pointer',
                      }}>
                      <span style={{ width: 10, display:'inline-block' }}>{filter[lvl] ? '✓' : ''}</span>
                      {lvl}
                    </button>
                  ))}
                </div>
              </>
            )}
          </div>
        </div>

        <div ref={tailRef} onScroll={onScroll}
          className="logs-tail"
          style={{
            flex:1, overflow:'auto', background:'#0a0a0b',
            padding:'10px 0',
            fontFamily:'IBM Plex Mono, SF Mono, Menlo, monospace', fontSize:12.5, lineHeight:1.6,
            position:'relative',
        }}>
          {visibleLogs.length === 0 && <div style={{ padding:16, color:'var(--ink-5)', fontSize:13 }}>waiting for output…</div>}
          {visibleLogs.map((l, i) => <LogLine key={i + '-' + l.ts} line={l}/>)}
          {!autoscroll && isRunning && (
            <button className="btn btn-sm anim-fade-in" onClick={() => { setAutoscroll(true); tailRef.current.scrollTop = tailRef.current.scrollHeight; }}
              style={{ position:'sticky', float:'right', bottom: 8, marginRight: 14, marginTop: -28, zIndex: 5, background:'var(--card-hi)' }}>
              <I.ChevronDown size={12}/> jump to bottom
            </button>
          )}
        </div>
      </div>

      {shotOpen && <ScreenshotModal instance={instance} onClose={() => setShotOpen(false)}/>}
    </aside>
  );
}

function LogLine({ line }) {
  const c = LEVEL_COLORS[line.level] || LEVEL_COLORS.INFO;
  return (
    <div className="anim-log" style={{
      display:'grid', gridTemplateColumns:'72px 60px 1fr', gap:12,
      padding:'1.5px 16px',
      color:'var(--ink-2)',
    }}>
      <span style={{ color:'var(--ink-5)' }}>{fmtLogTime(line.ts)}</span>
      <span style={{ color: c.tag, fontWeight: 500 }}>{line.level}</span>
      <span style={{ color: line.level === 'ERROR' ? 'var(--bad)' : 'var(--ink-2)', whiteSpace:'pre-wrap', wordBreak:'break-all' }}>{line.msg}</span>
    </div>
  );
}

// Реальный скриншот: шлём команду боту через /api/control, ждём WS-событие

function ScreenshotModal({ instance, onClose }) {
  const [state, setState] = useStateD("requesting"); 
  const [imgUrl, setImgUrl] = useStateD(null);
  const padRef = useRefD(instance.id);

  const fetchShot = useRefD(async () => {
    try {
      const r = await fetch(`/api/screenshot/${encodeURIComponent(padRef.current)}?t=${Date.now()}`);
      if (!r.ok) throw new Error("no shot");
      const blob = await r.blob();
      setImgUrl((prev) => { if (prev) URL.revokeObjectURL(prev); return URL.createObjectURL(blob); });
      setState("ready");
    } catch {
      setState("error");
    }
  });

  const request = useRefD(async () => {
    setState("requesting");
    const ok = await Live.control([padRef.current], "screenshot");
    if (!ok) { setState("error"); return; }
  });

  useEffectD(() => {
    request.current();
    
    const off = Live.subscribe((m) => {
      if (m.type === "screenshot_ready" && m.pad_code === padRef.current) {
        fetchShot.current();
      }
    });
    
    const t = setTimeout(() => { fetchShot.current(); }, 12000);
    return () => { off(); clearTimeout(t); };
  }, [instance.id]);

  return (
    <>
      <div className="scrim" onClick={onClose}></div>
      <div className="anim-modal" style={{
        position:'fixed', left:'50%', top:'50%', transform:'translate(-50%, -50%)',
        width: 720, maxWidth:'92vw', maxHeight:'90vh',
        background:'var(--panel)', border:'1px solid var(--line-strong)', borderRadius:10, zIndex:95,
        display:'flex', flexDirection:'column', overflow:'hidden',
        boxShadow: '0 24px 60px rgba(0,0,0,.55)',
      }}>
        <div style={{ padding:'12px 18px', borderBottom:'1px solid var(--line)', display:'flex', alignItems:'center', gap:11 }}>
          <span style={{ fontSize:15, fontWeight:600 }}>Screenshot</span>
          <span className="mono" style={{ fontSize:13, color:'var(--ink-4)' }}>{instance.name}</span>
          <div style={{ flex:1 }}/>
          <button className="btn btn-sm" onClick={() => request.current()}><I.Refresh size={13}/> Recapture</button>
          {imgUrl && <a className="btn btn-sm" href={imgUrl} download={`${instance.id}.png`}><I.Download size={13}/> Save</a>}
          <button className="icon-btn" onClick={onClose}><I.X size={15}/></button>
        </div>
        <div style={{ flex:1, padding:18, background:'#0a0a0b', display:'flex', alignItems:'center', justifyContent:'center', minHeight:280 }}>
          {state === "ready" && imgUrl ? (
            <img className="anim-fade-in" src={imgUrl} alt="screenshot"
                 style={{ maxWidth:'100%', maxHeight:'70vh', borderRadius:7, border:'1px solid var(--line)' }}/>
          ) : (
            <div style={{ display:'flex', flexDirection:'column', alignItems:'center', gap:10, color:'var(--ink-4)' }}>
              {state === "error" ? (
                <>
                  <I.AlertTriangle size={36}/>
                  <span className="mono" style={{ fontSize:13 }}>не удалось получить скриншот</span>
                  <button className="btn btn-sm" onClick={() => request.current()}>Повторить</button>
                </>
              ) : (
                <span className="mono pulse-soft" style={{ fontSize:13 }}>capturing…</span>
              )}
            </div>
          )}
        </div>
      </div>
    </>
  );
}

Object.assign(window, { InstanceDetail });
