/* global React */
(function () {
  const { useState, useEffect, useRef, useCallback } = React;
  const { mapRow, mapJob, parseStats } = window.SC_Utils;
  const SRC_MAP = window.SC_SrcMap;
  const Api = window.SC_Api;

  // ── localStorage helpers ──────────────────────────────────────
  const SK = {
    seeds:     'sc_seeds',
    manual:    'sc_manual',
    siteUrls:  'sc_site_urls',
    questions: 'sc_q_state',   // {phrases, questions, index, context, site_profile}
    jobId:     'sc_job_id',
  };
  const lsGet  = (key)      => { try { return JSON.parse(localStorage.getItem(key)); } catch { return null; } };
  const lsSet  = (key, val) => { try { localStorage.setItem(key, JSON.stringify(val)); } catch {} };
  const lsDel  = (key)      => { try { localStorage.removeItem(key); } catch {} };

  function MainPage() {
    const [seeds, setSeeds]       = useState(() => lsGet(SK.seeds) || '');
    const [siteUrls, setSiteUrls] = useState(() => lsGet(SK.siteUrls) || '');
    const [manual, setManual]     = useState(() => lsGet(SK.manual) ?? true);
    const [runState, setRunState] = useState('idle');
    const [activeStep, setActiveStep]       = useState(0);
    const [currentAction, setCurrentAction] = useState('');
    const [errorMsg, setErrorMsg]           = useState('');
    const [stats, setStats]                 = useState({ phrases: 0, sites: 0, suggest: 0, wordstatTotal: 0 });
    const [rows, setRows]                   = useState([]);
    const [totalCount, setTotalCount]       = useState(0);
    const [currentJobId, setCurrentJobId]   = useState(null);
    const [liveItems, setLiveItems]         = useState([]);
    const [sitesList, setSitesList]         = useState([]);
    const [suggestPhrases, setSuggestPhrases]   = useState([]);
    const [wordstatPhrases, setWordstatPhrases] = useState([]);
    const [cookieStatus, setCookieStatus]   = useState({ ok: false, count: 0 });
    const [history, setHistory]             = useState([]);
    const [questionsList, setQuestionsList]     = useState([]);
    const [questionIndex, setQuestionIndex]     = useState(0);
    const [questionOpen, setQuestionOpen]       = useState(false);
    const [questionLoading, setQuestionLoading] = useState(false);
    const [businessContext, setBusinessContext] = useState('');
    const [pendingPhrases, setPendingPhrases]   = useState([]);
    const [siteProfile, setSiteProfile]         = useState('');
    const [reviewPhrase, setReviewPhrase] = useState('');
    const [reviewIndex, setReviewIndex]   = useState(0);
    const [reviewTotal, setReviewTotal]   = useState(0);
    const [reviewOpen, setReviewOpen]     = useState(false);
    const [toast, setToast]               = useState(null);
    const wsRef = useRef(null);

    // ── Persist seeds / manual / siteUrls ───────────────────────
    useEffect(() => { lsSet(SK.seeds, seeds); }, [seeds]);
    useEffect(() => { lsSet(SK.manual, manual); }, [manual]);
    useEffect(() => { lsSet(SK.siteUrls, siteUrls); }, [siteUrls]);

    // ── Persist questions state ──────────────────────────────────
    useEffect(() => {
      if (questionOpen && questionsList.length > 0) {
        lsSet(SK.questions, { phrases: pendingPhrases, questions: questionsList, index: questionIndex, context: businessContext, site_profile: siteProfile });
      } else if (!questionOpen) {
        lsDel(SK.questions);
      }
    }, [questionOpen, questionsList, questionIndex, businessContext, pendingPhrases, siteProfile]);

    // ── Mount: restore state ─────────────────────────────────────
    useEffect(() => {
      loadCookieStatus();
      loadHistory();

      const savedQ = lsGet(SK.questions);
      if (savedQ?.questions?.length > 0) {
        // Восстанавливаем вопросы — пользователь не успел ответить
        setPendingPhrases(savedQ.phrases || []);
        setQuestionsList(savedQ.questions);
        setQuestionIndex(savedQ.index || 0);
        setBusinessContext(savedQ.context || '');
        setSiteProfile(savedQ.site_profile || '');
        setQuestionOpen(true);
        return; // Если есть вопросы — job ещё не запущен, ждём ответов
      }

      const savedJobId = lsGet(SK.jobId);
      if (savedJobId) {
        // Тихое восстановление задания без тоста
        resumeJobSilent(savedJobId);
      }
    }, []);

    // ── Helpers ──────────────────────────────────────────────────
    const showToast = useCallback((kind, msg) => {
      setToast({ kind, msg });
      setTimeout(() => setToast(null), 2800);
    }, []);

    const resetRunState = useCallback(() => {
      lsDel(SK.jobId);
      lsDel(SK.questions);
      setRunState('idle'); setActiveStep(0); setCurrentAction('');
      setStats({ phrases: 0, sites: 0, suggest: 0, wordstatTotal: 0 });
      setLiveItems([]); setSitesList([]); setSuggestPhrases([]); setWordstatPhrases([]);
      setRows([]); setTotalCount(0); setCurrentJobId(null); setErrorMsg('');
      if (wsRef.current) { wsRef.current.close(); wsRef.current = null; }
    }, []);

    const loadCookieStatus = async () => {
      try {
        const r = await Api.getJson('/api/cookies');
        setCookieStatus({ ok: r.ok, count: r.count || 0 });
      } catch {}
    };

    const saveCookies = async (str) => {
      try {
        const r = await Api.postJson('/api/cookies', { cookie_string: str });
        if (r.ok) { showToast('ok', `Куки сохранены: ${r.count} шт.`); loadCookieStatus(); }
        else showToast('err', r.error || 'Ошибка сохранения');
      } catch { showToast('err', 'Ошибка'); }
    };

    const loadHistory = async () => {
      try {
        const jobs = await Api.getJson('/api/jobs');
        setHistory(jobs.slice(0, 5).map(mapJob));
      } catch {}
    };

    // Загрузка задания с тостом (по клику из истории)
    const resumeJob = async (jobId) => {
      await _loadJob(jobId, true);
    };

    // Тихое восстановление при перезагрузке страницы (без тоста)
    const resumeJobSilent = async (jobId) => {
      await _loadJob(jobId, false);
    };

    const _loadJob = async (jobId, withToast) => {
      try {
        const j = await Api.getJson(`/api/job/${jobId}`);
        setCurrentJobId(jobId);
        lsSet(SK.jobId, jobId);
        setLiveItems([]); setSitesList([]); setSuggestPhrases([]); setWordstatPhrases([]);
        if (j.status === 'done') {
          if (j.result?.length) {
            const mapped = j.result.map(mapRow);
            setRows(mapped);
            setTotalCount(j.phrase_count || mapped.length);
            // Считаем по реальным строкам — mapRow уже применяет SRC_MAP,
            // поэтому 'похожие' → 'wordstat', 'вордстат' → 'wordstat' и т.д.
            const bySrc = {};
            mapped.forEach((r) => { bySrc[r.src] = (bySrc[r.src] || 0) + 1; });
            setStats({
              phrases:      j.phrase_count || mapped.length,
              seed:         bySrc.seed     || 0,
              ai:           bySrc.ai       || 0,
              suggest:      bySrc.suggest  || 0,
              wordstat:     bySrc.wordstat || 0,
              sites:        0,
              wordstatTotal: 0,
            });
          } else {
            // Результат не в памяти (после рестарта сервера, старая запись без result)
            setTotalCount(j.phrase_count || 0);
            setStats({ phrases: j.phrase_count || 0, seed: 0, ai: 0, suggest: 0, wordstat: 0, sites: 0, wordstatTotal: 0 });
          }
          setRunState('done');
          if (withToast) showToast('ok', `Задача #${jobId}`);
        } else if (j.status === 'running') {
          setRunState('running'); connectWS(jobId);
          if (withToast) showToast('ok', `Задача #${jobId} — переподключаемся…`);
        } else if (j.status === 'error') {
          if (j.result?.length) {
            // Задача упала (перезапуск сервера), но есть данные из чекпоинта — показываем как done
            const mapped = j.result.map(mapRow);
            setRows(mapped);
            setTotalCount(j.phrase_count || mapped.length);
            const bySrc = {};
            mapped.forEach((r) => { bySrc[r.src] = (bySrc[r.src] || 0) + 1; });
            setStats({ phrases: j.phrase_count || mapped.length, seed: bySrc.seed || 0, ai: bySrc.ai || 0, suggest: bySrc.suggest || 0, wordstat: bySrc.wordstat || 0, sites: 0, wordstatTotal: 0 });
            setRunState('done');
            if (withToast) showToast('warn', `Задача #${jobId} — данные из чекпоинта (шаг ${j.checkpoint_step ?? '?'} из 4)`);
          } else {
            setErrorMsg(j.error || 'Ошибка'); setRunState('error');
            lsDel(SK.jobId);
            if (withToast) showToast('err', `Задача #${jobId} завершилась с ошибкой`);
          }
        } else {
          // pending или неизвестный статус — очищаем
          lsDel(SK.jobId);
        }
      } catch {
        lsDel(SK.jobId);
        if (withToast) showToast('err', 'Не удалось загрузить задачу');
      }
    };

    const connectWS = useCallback((jobId) => {
      if (wsRef.current) wsRef.current.close();
      const ws = new WebSocket(Api.wsUrl(`/api/ws/${jobId}`));
      wsRef.current = ws;

      ws.onmessage = (e) => {
        let msg; try { msg = JSON.parse(e.data); } catch { return; }

        if (msg.type === 'log') {
          const text = msg.text || '';
          setStats((cur) => parseStats(text, cur));
          const m = text.match(/Фраза[:\s]+«([^»]+)»/);
          if (m) {
            const phrase = m[1].trim();
            const src = text.includes('suggest') ? 'suggest' : text.includes('Wordstat') ? 'wordstat' : text.includes('ИИ') ? 'ai' : 'seed';
            setLiveItems((prev) => [...prev.slice(-20), { phrase, src }]);
          }
        }
        if (msg.type === 'site_data') {
          const ph = msg.phrases || [];
          setSitesList((prev) => [...prev, { url: msg.url, phrases: ph }]);
          setStats((cur) => ({ ...cur, sites: cur.sites + 1, phrases: cur.phrases + ph.length }));
          if (ph.length > 0) setLiveItems((prev) => [...prev, ...ph.slice(0, 3).map((p) => ({ phrase: p, src: 'ai' }))].slice(-20));
        }
        if (msg.type === 'suggest_data') { setSuggestPhrases(msg.phrases || []); setStats((cur) => ({ ...cur, suggest: (msg.phrases || []).length })); }
        if (msg.type === 'wordstat_data') setWordstatPhrases(msg.phrases || []);
if (msg.type === 'progress') { setActiveStep(msg.step - 1); if (msg.label) setCurrentAction(msg.label); }
        if (msg.type === 'status') { if (msg.status === 'running') setRunState('running'); if (msg.status === 'error') setRunState('error'); }
        if (msg.type === 'result') {
          const mapped = (msg.data || []).map(mapRow);
          setRows(mapped); setTotalCount(msg.phrase_count || mapped.length);
          // source_counts содержит русские ключи («затравка», «ИИ», «suggest», «вордстат», «похожие»)
          // Надёжнее считать по уже маппированным строкам (mapRow применяет SRC_MAP)
          const bySrc = {};
          mapped.forEach((r) => { bySrc[r.src] = (bySrc[r.src] || 0) + 1; });
          // Для полного phrase_count (может быть > 500 переданных строк) доверяем source_counts
          const byEng = {};
          for (const [k, v] of Object.entries(msg.source_counts || {})) { const e = SRC_MAP[k] || k; byEng[e] = (byEng[e] || 0) + v; }
          setStats({
            phrases:      msg.phrase_count || mapped.length,
            seed:         byEng.seed     || bySrc.seed     || 0,
            ai:           byEng.ai       || bySrc.ai       || 0,
            suggest:      byEng.suggest  || bySrc.suggest  || 0,
            wordstat:     byEng.wordstat || bySrc.wordstat || 0,
            sites:        0,
            wordstatTotal: 0,
          });
          setActiveStep(4); setRunState('done');
          showToast('ok', `Готово — ${msg.phrase_count || mapped.length} фраз`);
          loadHistory();
        }
        if (msg.type === 'review_phrase') { setReviewPhrase(msg.phrase || ''); setReviewIndex(msg.index ?? 0); setReviewTotal(msg.total ?? 1); setReviewOpen(true); }
        if (msg.type === 'review_complete') setReviewOpen(false);
        if (msg.type === 'error') { setErrorMsg(msg.text || 'Ошибка'); setRunState('error'); lsDel(SK.jobId); }
      };
      ws.onerror = () => {}; ws.onclose = () => {};
    }, [showToast]);

    const doStartRun = useCallback(async (phrases, ctx, sp = '') => {
      lsDel(SK.questions); // Вопросы пройдены — очищаем
      const fullCtx = [sp, ctx].filter(Boolean).join('\n\n');
      setRunState('running'); setActiveStep(0); setCurrentAction('Запуск...');
      setStats({ phrases: 0, sites: 0, suggest: 0, wordstatTotal: 0 });
      setLiveItems([]); setRows([]); setTotalCount(0); setErrorMsg('');
      try {
        const resp = await Api.post('/api/run', { phrases, interactive_review: manual, business_context: fullCtx });
        if (!resp.ok) { const err = await resp.json(); setErrorMsg(err.detail || 'Ошибка сервера'); setRunState('error'); return; }
        const { job_id } = await resp.json();
        lsSet(SK.jobId, job_id); // Сохраняем для восстановления
        setCurrentJobId(job_id); connectWS(job_id); loadHistory();
      } catch { setErrorMsg('Не удалось подключиться к серверу'); setRunState('error'); }
    }, [manual, connectWS]);

    const handleQuestionAnswer = useCallback((answer) => {
      const newCtx = answer ? businessContext + `\nВопрос: ${questionsList[questionIndex]}\nОтвет: ${answer}` : businessContext;
      if (questionIndex + 1 < questionsList.length) {
        setBusinessContext(newCtx); setQuestionIndex(questionIndex + 1);
      } else {
        setQuestionOpen(false); setBusinessContext(''); setQuestionsList([]); setQuestionIndex(0);
        doStartRun(pendingPhrases, newCtx, siteProfile);
      }
    }, [questionsList, questionIndex, businessContext, pendingPhrases, siteProfile, doStartRun]);

    const startRun = async () => {
      const phrases = seeds.split('\n').map((p) => p.trim()).filter(Boolean);
      if (!phrases.length) { showToast('err', 'Введите хотя бы одну фразу'); return; }
      if (phrases.length > 10) { showToast('err', 'Максимум 10 фраз'); return; }
      const urls = siteUrls.split('\n').map((u) => u.trim()).filter(Boolean);
      setPendingPhrases(phrases); setQuestionLoading(true);
      try {
        const data = await Api.postJson('/api/questions', { phrases, site_urls: urls });
        const qs = data.questions || [];
        const sp = data.site_profile || '';
        setSiteProfile(sp);
        if (qs.length > 0) {
          setQuestionsList(qs); setQuestionIndex(0); setBusinessContext('');
          setQuestionOpen(true); // useEffect сохранит в localStorage
        } else {
          doStartRun(phrases, '', sp);
        }
      } catch { doStartRun(phrases, '', ''); }
      finally { setQuestionLoading(false); }
    };

    const submitRating = useCallback((rating) => {
      if (wsRef.current && wsRef.current.readyState === WebSocket.OPEN)
        wsRef.current.send(JSON.stringify({ type: 'phrase_rating', rating }));
    }, []);

    const exportExcel = async () => {
      if (!currentJobId) { showToast('err', 'Файл не найден'); return; }
      try {
        const resp = await Api.get(`/api/download/${currentJobId}`);
        if (!resp.ok) { showToast('err', 'Не удалось скачать файл'); return; }
        const blob = await resp.blob();
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        const cd = resp.headers.get('content-disposition') || '';
        const m = cd.match(/filename[^;=\n]*=["']?([^"'\n;]+)/);
        a.href = url;
        a.download = m ? m[1] : `semantic_core_${currentJobId}.xlsx`;
        document.body.appendChild(a);
        a.click();
        document.body.removeChild(a);
        URL.revokeObjectURL(url);
      } catch { showToast('err', 'Ошибка при скачивании'); }
    };

    const loadAllRows = useCallback(async () => {
      if (!currentJobId) return;
      try {
        const j = await Api.getJson(`/api/job/${currentJobId}?limit=0`);
        setRows((j.result || []).map(mapRow));
        setTotalCount(j.phrase_count || j.result?.length || 0);
      } catch {}
    }, [currentJobId]);

    const seedCount     = stats.seed     ?? rows.filter((r) => r.src === 'seed').length;
    const aiCount       = stats.ai       ?? rows.filter((r) => r.src === 'ai').length;
    const suggestCount  = stats.suggest  ?? rows.filter((r) => r.src === 'suggest').length;
    const wordstatCount = stats.wordstat ?? rows.filter((r) => r.src === 'wordstat').length;
    const T = window.SC_T;

    return (
      <div style={{ width: '100%', height: '100%', display: 'flex', background: T.bg, color: T.ink, fontFamily: '"Inter", system-ui, sans-serif', position: 'relative', overflow: 'hidden' }}>
        <Sidebar
          seeds={seeds} setSeeds={setSeeds}
          siteUrls={siteUrls} setSiteUrls={setSiteUrls}
          manual={manual} setManual={setManual}
          state={runState} onRun={startRun} questionLoading={questionLoading}
          cookieStatus={cookieStatus} onSaveCookies={saveCookies}
          history={history} onResume={resumeJob}
        />

        <main style={{ flex: 1, display: 'flex', flexDirection: 'column', background: T.bg2, minWidth: 0 }}>
          <TopBar state={runState} total={totalCount} onExport={exportExcel} onNewRun={resetRunState} />
          {runState === 'idle'    && <IdleScreen />}
          {runState === 'running' && <RunningScreen activeStep={activeStep} currentAction={currentAction} stats={stats} liveItems={liveItems} wordstatCount={wordstatPhrases.length} sitesList={sitesList} suggestPhrases={suggestPhrases} wordstatPhrases={wordstatPhrases} />}
          {runState === 'done'    && <ResultsScreen rows={rows} totalCount={totalCount} seedCount={seedCount} aiCount={aiCount} suggestCount={suggestCount} wordstatCount={wordstatCount} allLoaded={rows.length >= totalCount} onLoadAll={loadAllRows} />}
          {runState === 'error'   && <ErrorScreen message={errorMsg} onRetry={resetRunState} />}
        </main>

        <Modal open={questionOpen} onClose={() => handleQuestionAnswer('')} title="Расскажите о вашем бизнесе" subtitle="Ответы помогут ИИ точнее отфильтровать поисковые запросы">
          {questionsList.length > 0 && <QuestionCard question={questionsList[questionIndex]} index={questionIndex} total={questionsList.length} onAnswer={handleQuestionAnswer} />}
        </Modal>

        <Modal open={reviewOpen} onClose={() => submitRating(2)} title="Оцените фразу" subtitle="Система подбирает новые запросы — скажите, подходят ли они">
          <PhraseRatingCard phrase={reviewPhrase} index={reviewIndex} total={reviewTotal} onRate={submitRating} />
        </Modal>

        <Toast show={!!toast} kind={toast?.kind}>{toast?.msg}</Toast>
      </div>
    );
  }

  window.MainPage = MainPage;
})();
