const { useState, useCallback, useEffect, useMemo, useRef } = React;
const { createRoot } = ReactDOM;

const defaultCategories = [
  {
    label: "по вопросу: найти таблицу в HR контуре",
    endpoint: "/api/hr/table-search",
  },
  {
    label: "по вопросу: найти код в HR контуре",
    endpoint: "/api/hr/code-search",
  },
  {
    label: "по введённым таблицам найти все связки",
    endpoint: "/api/hr/table-links",
  },
  {
    label: "по запросу сгенерировать sql-vip",
    endpoint: "/api/hr/sql-vip",
  },
];

const normalizeCategoryItem = (category) => {
  if (!category) return { label: "", endpoint: null };
  if (typeof category === "string") {
    return { label: category, endpoint: null };
  }
  return {
    label: category.label || "",
    endpoint: category.endpoint || null,
  };
};

const normalizeCategoryList = (categories) => (Array.isArray(categories) ? categories.map(normalizeCategoryItem) : []);

const ratingOptions = [
  { value: 1, label: "Плохо", color: "rgba(220, 38, 38, 0.5)" },
  { value: 2, label: "Средне", color: "rgba(245, 158, 11, 0.5)" },
  { value: 3, label: "Хорошо", color: "rgba(16, 185, 129, 0.5)" },
];

function App() {
  const [token, setToken] = useState(null);
  const [username, setUsername] = useState("");
  const [loginForm, setLoginForm] = useState({ username: "", password: "" });
  const [authError, setAuthError] = useState("");
  const [isAuthenticating, setIsAuthenticating] = useState(false);

  const [chatList, setChatList] = useState([]);
  const [activeChatId, setActiveChatId] = useState(null);
  const [input, setInput] = useState("");
  const [isSending, setIsSending] = useState(false);
  const [isRatingOpen, setIsRatingOpen] = useState(false);
  const [availableCategories, setAvailableCategories] = useState(() => normalizeCategoryList(defaultCategories));
  const [isSelectingCategories, setIsSelectingCategories] = useState(false);
  const [analytics, setAnalytics] = useState(null);
  const [view, setView] = useState("chat");
  const [historyPage, setHistoryPage] = useState(0);
  const [historyPageSizeSelection, setHistoryPageSizeSelection] = useState(10);
  const [historyUsernameFilter, setHistoryUsernameFilter] = useState("");
  const [historyChatTypeFilter, setHistoryChatTypeFilter] = useState("");
  const messagesContainerRef = useRef(null);
  const overallMetrics = analytics?.overall ?? null;
  const ratingReport = overallMetrics?.ratingReport;
  const summaryRatingBreakdown = ratingReport?.breakdown ?? [];
  const overallMessageCount = Object.values(overallMetrics?.messageCounts ?? {}).reduce((sum, value) => sum + value, 0);
  const totalChats = overallMetrics?.totalChats ?? 0;
  const openChats = overallMetrics?.openChats ?? 0;
  const closedChats = overallMetrics?.closedChats ?? 0;
  const userSummaries = analytics?.userSummaries ?? {};
  const availableUsers = analytics?.availableUsers ?? [];
  const availableChatTypes = (analytics?.availableChatTypes ?? []).filter(Boolean);
  const messageHistoryPayload = analytics?.messageHistory ?? {};
  const historyItems = messageHistoryPayload.items ?? [];
  const historyPageIndex = messageHistoryPayload.page ?? 0;
  const historyPageCount = Math.max(messageHistoryPayload.pageCount ?? 1, 1);
  const historyTotal = messageHistoryPayload.total ?? historyItems.length;
  const historyPageSize = messageHistoryPayload.pageSize ?? historyPageSizeSelection;
  const historyStartIndex = historyTotal ? historyPageIndex * historyPageSize + 1 : 0;
  const historyEndIndex = historyTotal ? Math.min(historyTotal, historyStartIndex + historyItems.length - 1) : 0;
  const canHistoryPrev = historyPageIndex > 0;
  const canHistoryNext = historyPageIndex < historyPageCount - 1;
  const historyRangeLabel = historyTotal ? `${historyStartIndex}-${historyEndIndex} из ${historyTotal}` : "Нет записей";
  const overallCategoryUsage = overallMetrics?.categoryUsage ?? [];
  const recentEvents = analytics?.recentEvents ?? [];
  const topChats = analytics?.topChats ?? [];
  const userSummaryEntries = Object.entries(userSummaries);
  const isAdmin = username === "vip-admin";
  const pagedMessageHistory = historyItems;
  const showMessageHistory = historyItems.length > 0;
  const showHistoryControls = historyPageCount > 1;

  const headers = useMemo(() => (token ? { Authorization: `Bearer ${token}` } : {}), [token]);
  const activeChat = useMemo(() => chatList.find((chat) => chat.id === activeChatId) ?? chatList[0], [chatList, activeChatId]);
  const chatHistory = activeChat?.messages ?? [];
  const chatHistoryLength = chatHistory.length;
  const isChatWritable = Boolean(activeChat && !activeChat.closed);

  const fetchCategories = useCallback(async () => {
    if (!token) return;
    try {
      const response = await fetch("/api/categories", { headers });
      if (!response.ok) throw new Error("Не удалось загрузить категории");
      const data = await response.json();
      const normalized = normalizeCategoryList(data.categories);
      setAvailableCategories(normalized.length ? normalized : normalizeCategoryList(defaultCategories));
    } catch (error) {
      console.error(error);
      setAvailableCategories(normalizeCategoryList(defaultCategories));
    }
  }, [headers, token]);

  const fetchChats = useCallback(async () => {
    if (!token) return;
    try {
      const response = await fetch("/api/chat/list", { headers });
      if (!response.ok) throw new Error("Не удалось загрузить чаты");
      const data = await response.json();
      setChatList(data.chats);
      setActiveChatId(data.chats.find((chat) => !chat.closed)?.id ?? data.chats[0]?.id ?? null);
    } catch (error) {
      console.error(error);
    }
  }, [headers, token]);

  const fetchAnalytics = useCallback(async () => {
    if (!token || !isAdmin) return;
    try {
      const query = new URLSearchParams();
      query.set("history_page", historyPage);
      query.set("history_page_size", historyPageSizeSelection);
      if (historyUsernameFilter) query.set("history_username", historyUsernameFilter);
      if (historyChatTypeFilter) query.set("history_chat_type", historyChatTypeFilter);
      const response = await fetch(`/api/analytics?${query.toString()}`, { headers });
      if (!response.ok) throw new Error("Не удалось загрузить аналитику");
      const data = await response.json();
      setAnalytics(data);
    } catch (error) {
      console.error(error);
      setAnalytics(null);
    }
  }, [headers, historyPage, historyPageSizeSelection, historyUsernameFilter, historyChatTypeFilter, isAdmin, token]);

  useEffect(() => {
    if (!token) return;
    fetchCategories();
    fetchChats();
    if (isAdmin) {
      fetchAnalytics();
    }
  }, [token, fetchCategories, fetchChats, fetchAnalytics, isAdmin]);

  useEffect(() => {
    if (!isAdmin && view === "analytics") {
      setView("chat");
    }
  }, [isAdmin, view]);

  useEffect(() => {
    setHistoryPage(0);
  }, [historyPageSizeSelection, historyUsernameFilter, historyChatTypeFilter]);

  useEffect(() => {
    if (historyPage !== historyPageIndex) {
      setHistoryPage(historyPageIndex);
    }
  }, [historyPageIndex, historyPage]);

  useEffect(() => {
    setHistoryPage((prev) => Math.min(prev, historyPageCount - 1));
  }, [historyPageCount]);

  useEffect(() => {
    if (!isAdmin) {
      setAnalytics(null);
    }
  }, [isAdmin]);

  useEffect(() => {
    if (view !== "chat") return;
    const container = messagesContainerRef.current;
    if (!container) return;
    window.requestAnimationFrame(() => {
      container.scrollTop = container.scrollHeight;
    });
  }, [chatHistoryLength, isSending, activeChatId, view]);

  const handleLogin = useCallback(
    async (event) => {
      event.preventDefault();
      setIsAuthenticating(true);
      setAuthError("");
      try {
        const response = await fetch("/api/auth/login", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify(loginForm),
        });
        if (!response.ok) {
          const data = await response.json();
          throw new Error(data.detail || "Неверные данные");
        }
        const data = await response.json();
        setToken(data.token);
        setUsername(data.username);
        setLoginForm({ username: "", password: "" });
      } catch (error) {
        setAuthError(error.message);
        console.error(error);
      } finally {
        setIsAuthenticating(false);
      }
    },
    [loginForm],
  );

  const handleLogout = useCallback(() => {
    setToken(null);
    setUsername("");
    setChatList([]);
    setActiveChatId(null);
    setAnalytics(null);
  }, []);

  const handleCreateChat = useCallback(
    async (category) => {
      const selected = normalizeCategoryItem(category);
      if (!selected.label || !token) return;
      setIsSelectingCategories(false);
      const resolvedEndpoint = selected.endpoint || defaultCategories[0]?.endpoint || null;
      const payload = {
        chat_id: Date.now(),
        title: `Сеанс ${new Date().toLocaleTimeString()}`,
        categories: [selected.label],
        endpoint: resolvedEndpoint,
      };
      try {
        const response = await fetch("/api/chat/create", {
          method: "POST",
          headers: { "Content-Type": "application/json", ...headers },
          body: JSON.stringify(payload),
        });
        if (!response.ok) throw new Error("Не удалось создать чат");
        const data = await response.json();
        setChatList((prev) => [data.chat, ...(prev.filter((chat) => chat.id !== data.chat.id))]);
        setActiveChatId(data.chat.id);
        fetchAnalytics();
      } catch (error) {
        console.error(error);
      }
    },
    [headers, token, fetchAnalytics],
  );

  const handleSend = useCallback(
    async (event) => {
      event.preventDefault();
      if (!input.trim() || !activeChat || !isChatWritable) return;
      const messageContent = input.trim();
      setInput("");
      setIsSending(true);
      try {
        const response = await fetch("/api/chat/respond", {
          method: "POST",
          headers: { "Content-Type": "application/json", ...headers },
          body: JSON.stringify({
            chat_id: activeChat.id,
            message: messageContent,
            categories: activeChat.categories,
            endpoint: activeChat.endpoint,
          }),
        });
        if (!response.ok) throw new Error("Не удалось отправить сообщение");
        await response.json();
        fetchChats();
        fetchAnalytics();
      } catch (error) {
        console.error(error);
      } finally {
        setIsSending(false);
      }
    },
    [activeChat, fetchChats, fetchAnalytics, headers, input, isChatWritable],
  );

  const handleRateChat = useCallback(
    async (value) => {
      if (!activeChat) return;
      try {
        const response = await fetch("/api/chat/rate", {
          method: "POST",
          headers: { "Content-Type": "application/json", ...headers },
          body: JSON.stringify({ chat_id: activeChat.id, rating: value }),
        });
        if (!response.ok) throw new Error("Не удалось оценить чат");
        await response.json();
        setIsRatingOpen(false);
        fetchChats();
        fetchAnalytics();
      } catch (error) {
        console.error(error);
      }
    },
    [activeChat, fetchChats, fetchAnalytics, headers],
  );

  if (!token) {
    return (
      <div className="auth-shell">
        <div className="auth-card">
          <h1>VIP AI (experimental)</h1>
          <form onSubmit={handleLogin}>
            <label>
              Логин
              <input
                value={loginForm.username}
                onChange={(event) => setLoginForm((prev) => ({ ...prev, username: event.target.value }))}
                required
                autoComplete="username"
              />
            </label>
            <label>
              Пароль
              <input
                type="password"
                value={loginForm.password}
                onChange={(event) => setLoginForm((prev) => ({ ...prev, password: event.target.value }))}
                required
                autoComplete="current-password"
              />
            </label>
            {authError && <p className="auth-error">{authError}</p>}
            <button type="submit" disabled={isAuthenticating}>
              {isAuthenticating ? "Входим..." : "Войти"}
            </button>
          </form>
        </div>
      </div>
    );
  }

  const ratingBadgeColor = activeChat?.rating
    ? ratingOptions.find((option) => option.value === activeChat.rating)?.color
    : "rgba(37, 99, 235, 0.15)";

  return (
    <div className="app-shell">
      <aside className="sidebar">
        <div className="brand">
          <span>VIP AI (experimental)</span>
        </div>
        <button type="button" className="new-chat" onClick={() => setIsSelectingCategories(true)}>
          + Новый чат
        </button>
        <div className="chat-list">
          {chatList.map((chat) => {
            const closed = !!chat.closed;
            const isActive = chat.id === activeChatId;
            const ratingColor = ratingOptions.find((option) => option.value === chat.rating)?.color || "rgba(37, 99, 235, 0.15)";
            return (
              <button
                key={chat.id}
                type="button"
                className={`chat-item ${isActive ? "active" : ""} ${closed ? "closed" : ""}`}
                onClick={() => !closed && setActiveChatId(chat.id)}
                disabled={closed}
              >
                <strong>{chat.title}</strong>
                <div className="chat-categories">
                  {chat.categories.map((category) => (
                    <span key={`${chat.id}-${category}`}>{category}</span>
                  ))}
                </div>
                <small style={{ backgroundColor: ratingColor }}>{
                  closed ? "Завершён" : chat.rating ? `Оценка ${chat.rating}/3` : "Открыт"
                }</small>
              </button>
            );
          })}
        </div>
      </aside>

      <section className="chat-area">
        <header className="chat-header">
          <div>
            <p className="chat-title"></p>
            <span></span>
          </div>
          <div className="header-controls">
            <button type="button" className={`tab ${view === "chat" ? "active" : ""}`} onClick={() => setView("chat")}>
              Чаты
            </button>
            {isAdmin && (
              <button
                type="button"
                className={`tab ${view === "analytics" ? "active" : ""}`}
                onClick={() => {
                  setView("analytics");
                  fetchAnalytics();
                }}
              >
                Аналитика
              </button>
            )}
            <button type="button" className="ghost" onClick={handleLogout}>
              Выйти ({username})
            </button>
          </div>
        </header>

        {view === "analytics" && isAdmin ? (
        <div className="analytics-view">
          <div className="analytics-header">
            <h2>Обзор по данным</h2>
            <div className="analytics-actions">
              <button type="button" onClick={fetchAnalytics}>
                Обновить
              </button>
            </div>
          </div>
          {analytics ? (
            <>
              <div className="metrics-grid">
                <article>
                  <p className="label">Всего сеансов</p>
                  <strong>{totalChats}</strong>
                </article>
                <article>
                  <p className="label">Открытые</p>
                  <strong>{openChats}</strong>
                </article>
                <article>
                  <p className="label">Завершённые</p>
                  <strong>{closedChats}</strong>
                </article>
                <article>
                  <p className="label">Сообщения</p>
                  <strong>{overallMessageCount}</strong>
                </article>
              </div>
              <div className="analytics-panels">
                <section>
                  <h3>Категории</h3>
                  {overallCategoryUsage.length ? (
                    <ul>
                      {overallCategoryUsage.map((entry) => (
                        <li key={entry.category}>
                          <span>{entry.category}</span>
                          <small>{entry.count}</small>
                        </li>
                      ))}
                    </ul>
                  ) : (
                    <p className="placeholder">Категории пока не используются</p>
                  )}
                </section>
                <section>
                  <h3>Недавние события</h3>
                  {recentEvents.length ? (
                    <ul>
                      {recentEvents.map((event) => (
                        <li key={`${event.timestamp}-${event.type}-${event.username || "global"}`}>
                          <span>
                            {event.type}
                            {event.username ? ` · ${event.username}` : ""}
                          </span>
                          <small>{new Date(event.timestamp).toLocaleString()}</small>
                        </li>
                      ))}
                    </ul>
                  ) : (
                    <p className="placeholder">Событий пока нет</p>
                  )}
                </section>
                <section>
                  <h3>Лучшие чаты</h3>
                  {topChats.length ? (
                    <ul>
                      {topChats.map((chat) => (
                        <li key={`${chat.username}-${chat.title}`}>
                          <span>
                            {chat.title} · {chat.username}
                          </span>
                          <small>{chat.messages} сообщений</small>
                        </li>
                      ))}
                    </ul>
                  ) : (
                    <p className="placeholder">Пока нет активных чатов</p>
                  )}
                </section>
                <section>
                  <h3>Отчёт по оценке</h3>
                  {ratingReport && summaryRatingBreakdown.length ? (
                    <div className="rating-report">
                      <p>
                        Средняя оценка: <strong>{ratingReport.average?.toFixed(1) ?? "—"}</strong>
                      </p>
                      <ul>
                        {summaryRatingBreakdown.map((entry) => (
                          <li key={entry.rating}>
                            <span>Оценка {entry.rating}/3</span>
                            <small>
                              {entry.count} раз · {entry.share}%
                            </small>
                          </li>
                        ))}
                      </ul>
                    </div>
                  ) : (
                    <p className="placeholder">Оценок пока нет</p>
                  )}
                </section>
              </div>
              <section className="user-summary">
                <h3>Данные по каждому пользователю</h3>
                {userSummaryEntries.length ? (
                  <ul>
                    {userSummaryEntries.map(([user, summary]) => (
                      <li key={user}>
                        <strong>{user}</strong>
                        <p>
                          Сеансов: {summary.totalChats} · Открытых: {summary.openChats} · Завершённых: {summary.closedChats}
                        </p>
                        <p>
                          Сообщений: {Object.values(summary.messageCounts || {}).reduce((sum, value) => sum + value, 0)}
                        </p>
                      </li>
                    ))}
                  </ul>
                ) : (
                  <p className="placeholder">Нет данных по пользователям</p>
                )}
              </section>
              
            </>
          ) : (
            <p className="placeholder">Данные ещё не получены</p>
          )}
        </div>
        ) : (
          <>
            <div className="messages" ref={messagesContainerRef}>
              {chatHistory.map((message) => (
                <article key={message.id} className={`message ${message.role}`}>
                  <div className="avatar" aria-hidden>
                    <span>{message.role === "assistant" ? "AI" : "Вы"}</span>
                  </div>
                  <p style={{ whiteSpace: "pre-wrap" }}>
                    {message.content.split('\n').map((line, i) => (
                      <span key={i}>{line}<br/></span>
                    ))}
                  </p>
                </article>
              ))}
              {isSending && (
                <article className="message assistant typing">
                  <div className="avatar">
                    <span>AI</span>
                  </div>
                  <div className="typing-dots">
                    <span></span>
                    <span></span>
                    <span></span>
                  </div>
                </article>
              )}
            </div>

            <form className="composer" onSubmit={handleSend}>
              <textarea
                aria-label="Введите сообщение"
                value={input}
                onChange={(event) => setInput(event.target.value)}
                rows={1}
                placeholder={activeChat ? "Напишите сообщение..." : "Выберите чат"}
                disabled={!activeChat || !isChatWritable}
              />
              <div className="composer-actions">
                <button
                  type="button"
                  className="close-chat"
                  onClick={() => setIsRatingOpen(true)}
                  disabled={!activeChat || activeChat.closed}
                >
                  Закрыть чат
                </button>
                <button type="submit" className="submit" disabled={!input.trim() || !isChatWritable || isSending}>
                  Отправить
                </button>
              </div>
            </form>

            {isRatingOpen && (
              <div className="rating-panel">
                <p>Оцените завершённый чат</p>
                <div className="rating-options">
                  {ratingOptions.map(({ value, label, color }) => (
                    <button
                      key={value}
                      type="button"
                      style={{ backgroundColor: color }}
                      onClick={() => handleRateChat(value)}
                    >
                      <span>{value}</span>
                      <small>{label}</small>
                    </button>
                  ))}
                </div>
              </div>
            )}
          </>
        )}
      </section>

      {isSelectingCategories && (
        <div className="category-overlay" role="dialog" aria-modal="true">
          <div className="category-modal">
            <h3>Выберите категорию</h3>
            <p>Нажмите категорию — чат создаётся автоматически</p>
            <div className="category-grid">
              {availableCategories.map((category) => (
                <button
                  key={`${category.label}-${category.endpoint || ""}`}
                  type="button"
                  className="category-chip"
                  onClick={() => handleCreateChat(category)}
                >
                  {category.label}
                </button>
              ))}
            </div>
            <button type="button" className="ghost" onClick={() => setIsSelectingCategories(false)}>
              Отмена
            </button>
          </div>
        </div>
      )}
    </div>
  );
}

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