// App.jsx — main shell tying chat + map + detail + tweaks together.
const { useState: useState_a, useEffect: useEffect_a, useRef: useRef_a, useMemo: useMemo_a } = React;

// Backend API. Same origin: FastAPI serves the frontend statically at /.
const API_BASE = "";

function getOrCreateSessionId() {
  let sid = null;
  try {
    sid = localStorage.getItem("mesto_session_id");
  } catch (_) {}
  if (!sid) {
    sid = (typeof crypto !== "undefined" && crypto.randomUUID)
      ? crypto.randomUUID()
      : `sid-${Math.random().toString(36).slice(2)}-${Date.now()}`;
    try {
      localStorage.setItem("mesto_session_id", sid);
    } catch (_) {}
  }
  return sid;
}

function decorateListing(l) {
  if (l && l.image_hue == null) {
    let h = 0;
    for (const c of (l.id || "")) h = (h * 31 + c.charCodeAt(0)) % 360;
    return { ...l, image_hue: h };
  }
  return l;
}

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "palette": "terracotta",
  "mapStyle": "warm",
  "cardLayout": "vertical",
  "showTrace": true,
  "mobile": false
}/*EDITMODE-END*/;

const PALETTES = {
  terracotta: { accent: "#C8553D", accentSoft: "#F2D7CD", accentInk: "#7A2A18", bg: "#FAF7F2", panel: "#FFFFFF", ink: "#1A1A1A", muted: "#6B6660", line: "rgba(26,26,26,0.08)" },
  forest:     { accent: "#3F6B4A", accentSoft: "#D4E2D5", accentInk: "#1F3D27", bg: "#F7F5EE", panel: "#FFFFFF", ink: "#1A1A1A", muted: "#6B6660", line: "rgba(26,26,26,0.08)" },
  navy:       { accent: "#234A8A", accentSoft: "#D4DEEF", accentInk: "#0F2752", bg: "#F6F4EF", panel: "#FFFFFF", ink: "#1A1A1A", muted: "#6B6660", line: "rgba(26,26,26,0.08)" },
  mono:       { accent: "#1A1A1A", accentSoft: "#E8E5DF", accentInk: "#1A1A1A", bg: "#FAF7F2", panel: "#FFFFFF", ink: "#1A1A1A", muted: "#6B6660", line: "rgba(26,26,26,0.08)" },
};

function applyPalette(name) {
  const p = PALETTES[name] || PALETTES.terracotta;
  const r = document.documentElement;
  Object.entries(p).forEach(([k, v]) => r.style.setProperty(`--${k}`, v));
}

function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const [messages, setMessages] = useState_a([]); // {role, content, listings?, trace?}
  const [activeListings, setActiveListings] = useState_a([]); // currently shown on map
  const [activeId, setActiveId] = useState_a(null);
  const [hoverId, setHoverId] = useState_a(null);
  const [input, setInput] = useState_a("");
  const [pending, setPending] = useState_a(null); // {trace: [{name,args,ms,done}]}
  const [detail, setDetail] = useState_a(null);
  const [showResetConfirm, setShowResetConfirm] = useState_a(false);
  const chatScrollRef = useRef_a(null);
  const inputRef = useRef_a(null);
  const sessionId = useMemo_a(getOrCreateSessionId, []);

  // Apply palette
  useEffect_a(() => { applyPalette(t.palette); }, [t.palette]);

  // Autoscroll chat
  useEffect_a(() => {
    const el = chatScrollRef.current;
    if (el) el.scrollTop = el.scrollHeight;
  }, [messages, pending]);

  const send = (text) => {
    const trimmed = text.trim();
    if (!trimmed || pending) return;
    setMessages((m) => [...m, { role: "user", content: trimmed }]);
    setInput("");
    runAgent(trimmed);
  };

  const runAgent = async (userText) => {
    setPending({ trace: [] });
    try {
      const res = await fetch(`${API_BASE}/api/chat`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ session_id: sessionId, message: userText }),
      });
      if (!res.ok) throw new Error(`HTTP ${res.status}`);
      const data = await res.json();
      const listings = (data.listings || []).map(decorateListing);
      setMessages((m) => [
        ...m,
        {
          role: "assistant",
          content: data.response || "(пустой ответ)",
          listings,
          trace: data.tool_calls || [],
        },
      ]);
      if (listings.length > 0) {
        setActiveListings(listings);
      }
    } catch (err) {
      setMessages((m) => [
        ...m,
        {
          role: "assistant",
          content: `Ошибка связи с сервером: ${err.message}`,
          listings: [],
          trace: [],
        },
      ]);
    } finally {
      setPending(null);
    }
  };

  const handleReset = async () => {
    try {
      await fetch(`${API_BASE}/api/chat/reset`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ session_id: sessionId }),
      });
    } catch (_) {
      // best-effort: историю UI всё равно чистим
    }
    setMessages([]);
    setActiveListings([]);
    setActiveId(null);
    setDetail(null);
    setPending(null);
    setShowResetConfirm(false);
  };

  const onDetails = (listing) => {
    setDetail(listing);
    send(`Расскажи подробнее про ${listing.id}`);
  };

  const onCardClick = (id) => {
    setActiveId(id === activeId ? null : id);
  };

  const isEmpty = messages.length === 0 && !pending;

  return (
    <div className={`app ${t.mobile ? "is-mobile" : ""} ${detail ? "has-detail" : ""}`} data-screen-label="Real estate agent">
      {/* LEFT: Chat */}
      <aside className="chat-pane" data-comment-anchor="chat-pane">
        <header className="chat-header">
          <div className="brand">
            <div className="brand-mark" aria-hidden="true">
              <svg viewBox="0 0 24 24" width="20" height="20" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
                <path d="M3 11l9-7 9 7" />
                <path d="M5 10v9h14v-9" />
                <path d="M10 19v-5h4v5" />
              </svg>
            </div>
            <div className="brand-text">
              <div className="brand-name">Mesto</div>
              <div className="brand-sub">Поиск квартир в Москве</div>
            </div>
          </div>
          <button className="header-btn" onClick={() => setShowResetConfirm(true)} title="Начать сначала">
            <svg viewBox="0 0 16 16" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round">
              <path d="M2 8a6 6 0 1 0 1.7-4.2" />
              <path d="M2 2v3h3" />
            </svg>
          </button>
        </header>

        <div className="chat-scroll" ref={chatScrollRef}>
          {isEmpty && (
            <div className="onboard">
              <div className="onboard-eyebrow">Помощник по недвижимости</div>
              <h1 className="onboard-title">Расскажите, какую квартиру вы ищете.</h1>
              <p className="onboard-body">
                Спрашивайте свободно — про бюджет, район, метро, время до работы или близость к парку.
                Я подберу варианты из каталога и покажу их на карте. Можно уточнять и сужать поиск по ходу диалога.
              </p>
              <div className="onboard-chip-label">Попробуйте</div>
              <div className="quick-chips">
                {QUICK_PROMPTS.map((q) => (
                  <button key={q} className="chip" onClick={() => send(q)}>
                    {q}
                  </button>
                ))}
              </div>
            </div>
          )}

          {messages.map((m, i) => (
            <Message key={i} m={m} showTrace={t.showTrace} onDetails={onDetails} />
          ))}

          {pending && (
            <TypingIndicator traceItems={pending.trace} showTrace={t.showTrace} />
          )}
        </div>

        <div className="composer">
          <div className="composer-inner">
            <textarea
              ref={inputRef}
              className="composer-input"
              placeholder="Например: 2-комнатная до 18 млн рядом с метро…"
              value={input}
              onChange={(e) => setInput(e.target.value)}
              onKeyDown={(e) => {
                if (e.key === "Enter" && !e.shiftKey) {
                  e.preventDefault();
                  send(input);
                }
              }}
              rows={1}
            />
            <button
              className="composer-send"
              disabled={!input.trim() || !!pending}
              onClick={() => send(input)}
              aria-label="Отправить"
            >
              <svg viewBox="0 0 16 16" width="16" height="16" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
                <path d="M2 8h11" />
                <path d="M9 4l4 4-4 4" />
              </svg>
            </button>
          </div>
          <div className="composer-hint">
            <kbd>↵</kbd> отправить · <kbd>⇧↵</kbd> новая строка
          </div>
        </div>
      </aside>

      {/* RIGHT: Map + cards */}
      <main className="map-pane" data-comment-anchor="map-pane">
        <MapView
          listings={activeListings}
          activeId={activeId}
          hoverId={hoverId}
          onMarkerClick={setActiveId}
          onMarkerHover={setHoverId}
          mapStyle={t.mapStyle}
          accent={PALETTES[t.palette].accent}
        />

        {activeListings.length > 0 && !detail && (
          <div className={`results-overlay layout-${t.cardLayout}`}>
            <div className="results-header">
              <span className="results-count">{activeListings.length} {pluralize(activeListings.length, "вариант", "варианта", "вариантов")}</span>
              <span className="results-sort">по релевантности</span>
            </div>
            <div className={`results-list results-list--${t.cardLayout}`}>
              {activeListings.map((l) => (
                <ListingCard
                  key={l.id}
                  listing={l}
                  layout={t.cardLayout}
                  isActive={l.id === activeId}
                  isHover={l.id === hoverId}
                  onClick={onCardClick}
                  onHover={setHoverId}
                  onDetails={onDetails}
                />
              ))}
            </div>
          </div>
        )}

        {activeListings.length === 0 && (
          <div className="map-empty">
            <div className="map-empty-card">
              <div className="map-empty-title">Москва · обзор</div>
              <div className="map-empty-sub">Задайте вопрос, и здесь появятся подходящие объекты.</div>
            </div>
          </div>
        )}

        {detail && (
          <ListingDetail
            listing={detail}
            onClose={() => setDetail(null)}
            onAsk={(q) => { setDetail(null); send(q); }}
          />
        )}
      </main>

      {/* Reset confirmation */}
      {showResetConfirm && (
        <div className="modal-backdrop" onClick={() => setShowResetConfirm(false)}>
          <div className="modal" onClick={(e) => e.stopPropagation()}>
            <h3 className="modal-title">Начать сначала?</h3>
            <p className="modal-body">История диалога будет очищена. Это действие нельзя отменить.</p>
            <div className="modal-actions">
              <button className="btn-ghost" onClick={() => setShowResetConfirm(false)}>Отмена</button>
              <button className="btn-primary" onClick={handleReset}>Очистить</button>
            </div>
          </div>
        </div>
      )}

      <TweaksPanel>
        <TweakSection label="Палитра" />
        <TweakRadio
          label="Акцент"
          value={t.palette}
          options={[
            { value: "terracotta", label: "Терракота" },
            { value: "forest", label: "Лес" },
            { value: "navy", label: "Морской" },
            { value: "mono", label: "Моно" },
          ]}
          onChange={(v) => setTweak("palette", v)}
        />
        <TweakSection label="Карта" />
        <TweakRadio
          label="Стиль"
          value={t.mapStyle}
          options={[
            { value: "warm", label: "Тёплый" },
            { value: "muted", label: "Приглушённый" },
            { value: "stylized", label: "Стилизованный" },
          ]}
          onChange={(v) => setTweak("mapStyle", v)}
        />
        <TweakSection label="Карточки" />
        <TweakRadio
          label="Лейаут"
          value={t.cardLayout}
          options={[
            { value: "horizontal", label: "Гориз." },
            { value: "vertical", label: "Верт." },
            { value: "minimal", label: "Мин." },
          ]}
          onChange={(v) => setTweak("cardLayout", v)}
        />
        <TweakSection label="Отладка" />
        <TweakToggle
          label="Trace tool calls"
          value={t.showTrace}
          onChange={(v) => setTweak("showTrace", v)}
        />
        <TweakToggle
          label="Mobile preview"
          value={t.mobile}
          onChange={(v) => setTweak("mobile", v)}
        />
      </TweaksPanel>
    </div>
  );
}

function pluralize(n, one, few, many) {
  const mod10 = n % 10, mod100 = n % 100;
  if (mod10 === 1 && mod100 !== 11) return one;
  if (mod10 >= 2 && mod10 <= 4 && (mod100 < 10 || mod100 >= 20)) return few;
  return many;
}

function Message({ m, showTrace, onDetails }) {
  if (m.role === "user") {
    return (
      <div className="msg msg--user">
        <div className="msg-bubble">{m.content}</div>
      </div>
    );
  }
  return (
    <div className="msg msg--assistant">
      <div className="msg-avatar">
        <span className="msg-avatar-dot" />
      </div>
      <div className="msg-bubble">
        <div className="msg-md">{renderMarkdown(m.content)}</div>
        {showTrace && m.trace && m.trace.length > 0 && (
          <TraceBlock items={m.trace} />
        )}
        {m.listings && m.listings.length > 0 && (
          <div className="msg-listings">
            {m.listings.map((l) => (
              <button
                key={l.id}
                className="msg-listing-pill"
                onClick={() => onDetails(l)}
              >
                <span className="msg-listing-name">{l.name}</span>
                <span className="msg-listing-price">{formatPriceShort(l.price)}</span>
              </button>
            ))}
          </div>
        )}
      </div>
    </div>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
