const { useEffect, useMemo, useState } = React;

async function api(path, options = {}) {
  const res = await fetch(path, {
    cache: "no-store",
    credentials: "include",
    headers: { "Content-Type": "application/json", ...(options.headers || {}) },
    ...options,
  });
  if (!res.ok) {
    let detail = "Ошибка запроса";
    try { detail = (await res.json()).detail || detail; } catch (_) {}
    throw new Error(Array.isArray(detail) ? detail.map(x => x.msg).join(", ") : detail);
  }
  return res.json();
}

function fmtMoney(value) {
  return new Intl.NumberFormat("ru-RU", { style: "currency", currency: "RUB", maximumFractionDigits: 2 }).format(Number(value || 0));
}
function fmtDate(value) {
  return value ? new Intl.DateTimeFormat("ru-RU", { dateStyle: "short", timeStyle: "short" }).format(new Date(value)) : "";
}
function fmtDateOnly(value) {
  if (!value) return "";
  const text = String(value);
  const match = text.match(/^(\d{4})-(\d{2})-(\d{2})/);
  if (match) return `${match[3]}.${match[2]}.${match[1]}`;
  return new Intl.DateTimeFormat("ru-RU", { dateStyle: "short" }).format(new Date(value));
}
function prettyJson(value) {
  return JSON.stringify(value ?? null, null, 2);
}
function paymentLabel(value) {
  return ({ unpaid: "Не оплачен", partially_paid: "Оплачен частично", paid: "Оплачен", canceled: "Отменен", unknown: "Неизвестно" })[value] || value;
}
function shipmentLabel(value) {
  return ({ not_shipped: "Не отгружен", partially_shipped: "Отгружен частично", shipped: "Отгружен", unknown: "Неизвестно" })[value] || value;
}
function signatureLabel(value) {
  return ({ not_signed: "Не подписан", signed: "Подписан", unknown: "Неизвестно" })[value] || value;
}

function Login({ onLogin }) {
  const [login, setLogin] = useState("");
  const [password, setPassword] = useState("");
  const [error, setError] = useState("");
  async function submit(e) {
    e.preventDefault();
    setError("");
    try { onLogin(await api("/api/auth/login", { method: "POST", body: JSON.stringify({ login, password }) })); }
    catch (err) { setError(err.message); }
  }
  return <main className="login">
    <form onSubmit={submit}>
      <div className="brand">Score</div>
      {error && <div className="toast">{error}</div>}
      <input placeholder="Логин" value={login} onChange={e => setLogin(e.target.value)} autoFocus />
      <input placeholder="Пароль" type="password" value={password} onChange={e => setPassword(e.target.value)} />
      <button className="primary">Войти</button>
    </form>
  </main>;
}

function Shell({ user, setUser }) {
  const [path, setPath] = useState(location.pathname === "/" ? "/dashboard" : location.pathname);
  useEffect(() => {
    const onPop = () => setPath(location.pathname);
    addEventListener("popstate", onPop);
    return () => removeEventListener("popstate", onPop);
  }, []);
  function nav(to) { history.pushState(null, "", to); setPath(to); }
  async function logout() { await api("/api/auth/logout", { method: "POST" }); setUser(null); }
  const page = path.startsWith("/invoices") ? <Invoices user={user} /> :
    path.startsWith("/suppliers") ? <Suppliers /> :
    path.startsWith("/shipping") ? <Shipping /> :
    path.startsWith("/ai/questions") ? <AiQuestions /> :
    path.startsWith("/admin/users") ? <Users /> :
    path.startsWith("/admin/organizations") ? <Organizations /> :
    path.startsWith("/admin/sync") ? <Sync /> : <Dashboard />;
  return <div className="shell">
    <aside className="sidebar">
      <div className="brand">Score</div>
      <nav className="nav">
        <a href="/dashboard" className={path.startsWith("/dashboard") ? "active" : ""} onClick={e => { e.preventDefault(); nav("/dashboard"); }}>Dashboard</a>
        <a href="/invoices" className={path.startsWith("/invoices") ? "active" : ""} onClick={e => { e.preventDefault(); nav("/invoices"); }}>Счета</a>
        <a href="/shipping" className={path.startsWith("/shipping") ? "active" : ""} onClick={e => { e.preventDefault(); nav("/shipping"); }}>Отгрузка</a>
        <a href="/suppliers" className={path.startsWith("/suppliers") ? "active" : ""} onClick={e => { e.preventDefault(); nav("/suppliers"); }}>Поставщики</a>
        {user.role === "admin" && <a href="/ai/questions" className={path.startsWith("/ai/questions") ? "active" : ""} onClick={e => { e.preventDefault(); nav("/ai/questions"); }}>AI вопросы</a>}
        {user.role === "admin" && <a href="/admin/organizations" className={path.startsWith("/admin/organizations") ? "active" : ""} onClick={e => { e.preventDefault(); nav("/admin/organizations"); }}>Организации</a>}
        {user.role === "admin" && <a href="/admin/users" className={path.startsWith("/admin/users") ? "active" : ""} onClick={e => { e.preventDefault(); nav("/admin/users"); }}>Пользователи</a>}
        {user.role === "admin" && <a href="/admin/sync" className={path.startsWith("/admin/sync") ? "active" : ""} onClick={e => { e.preventDefault(); nav("/admin/sync"); }}>Синхронизация</a>}
      </nav>
      <div className="userbox">
        <div>{user.login} · {user.role}</div>
        <button onClick={logout}>Выйти</button>
      </div>
    </aside>
    <main className="main">{page}</main>
  </div>;
}

function Dashboard() {
  const [data, setData] = useState(null);
  const [error, setError] = useState("");
  useEffect(() => { api("/api/dashboard/summary").then(setData).catch(e => setError(e.message)); }, []);
  if (error) return <div className="toast">{error}</div>;
  if (!data) return <div>Загрузка...</div>;
  return <>
    <div className="topbar"><h1>Dashboard</h1></div>
    <section className="grid metrics">
      <div className="metric"><div className="label">Неоплаченных счетов</div><div className="value">{data.total_unpaid_count}</div></div>
      <div className="metric"><div className="label">Сумма неоплаченных</div><div className="value">{fmtMoney(data.total_unpaid_amount)}</div></div>
      <div className="metric"><div className="label">Без номера заказа</div><div className="value">{data.without_order_number_count}</div></div>
      <div className="metric"><div className="label">Сумма без номера</div><div className="value">{fmtMoney(data.without_order_number_amount)}</div></div>
    </section>
    <section className="grid" style={{marginTop: 14, gridTemplateColumns: "1fr 1fr"}}>
      <div className="panel"><h2>По организациям</h2><SimpleTable rows={data.by_organization} columns={[["name","Организация"],["count","Счетов"],["amount","Сумма"]]} money="amount" /></div>
      <div className="panel"><h2>Синхронизация</h2><SimpleTable rows={data.sync_statuses} columns={[["name","Организация"],["last_success_sync_at","Успешно"],["last_sync_error","Ошибка"]]} /></div>
    </section>
  </>;
}

function SimpleTable({ rows, columns, money, footerRows = [] }) {
  const moneyColumns = Array.isArray(money) ? money : [money];
  function cellValue(value) {
    if (typeof value === "boolean") return value ? "Да" : "Нет";
    return String(value ?? "");
  }
  function cells(row) {
    return columns.map(c => <td key={c[0]} className={moneyColumns.includes(c[0]) ? "money" : ""}>{moneyColumns.includes(c[0]) ? fmtMoney(row[c[0]]) : cellValue(row[c[0]])}</td>);
  }
  return <div className="table-wrap"><table><thead><tr>{columns.map(c => <th key={c[0]}>{c[1]}</th>)}</tr></thead><tbody>
    {rows.map((row, i) => <tr key={i}>{cells(row)}</tr>)}
  </tbody>{footerRows.length > 0 && <tfoot>{footerRows.map((row, i) => <tr key={i}>{cells(row)}</tr>)}</tfoot>}</table></div>;
}

function Invoices({ user }) {
  const [rows, setRows] = useState([]);
  const [orgs, setOrgs] = useState([]);
  const [selected, setSelected] = useState(null);
  const [aiInvoice, setAiInvoice] = useState(null);
  const [filters, setFilters] = useState({ organization_id: "", order_number: "" });
  const [error, setError] = useState("");
  async function load() {
    const qs = new URLSearchParams(Object.entries(filters).filter(([,v]) => v));
    setRows(await api(`/api/invoices?${qs}`));
  }
  useEffect(() => { load().catch(e => setError(e.message)); }, [filters]);
  useEffect(() => { api("/api/organizations").then(setOrgs).catch(() => setOrgs([])); }, []);
  return <>
    <div className="topbar"><h1>Счета</h1><div className="row"><button onClick={() => location.href="/api/invoices/export/xlsx"}>XLSX</button><button onClick={() => location.href="/api/invoices/export/pdf"}>PDF</button></div></div>
    {error && <div className="toast">{error}</div>}
    <div className="toolbar">
      <select value={filters.organization_id} onChange={e => setFilters({...filters, organization_id: e.target.value})}><option value="">Все организации</option>{orgs.map(o => <option key={o.id} value={o.id}>{o.name}</option>)}</select>
      <select value={filters.order_number} onChange={e => setFilters({...filters, order_number: e.target.value})}><option value="">Все номера заказа</option><option value="missing">Нет номера</option><option value="present">Есть номер</option></select>
      <button className="icon" title="Обновить" onClick={load}>↻</button>
    </div>
    <div className="table-wrap"><table><thead><tr><th>Организация</th><th>Номер</th><th>Дата</th><th className="money">Сумма</th><th>Оплата</th><th>Ожидаемая оплата</th><th>Контрагент</th><th>Комментарий 1С</th><th>Номер заказа</th><th>Б24</th><th>AI</th><th>Комментарии</th><th>Синхронизация</th></tr></thead><tbody>
      {rows.map(r => <tr key={r.id} onClick={() => setSelected(r)}><td>{r.organization_name}</td><td>{r.number}</td><td>{fmtDate(r.date)}</td><td className="money">{fmtMoney(r.amount)}</td><td>{paymentLabel(r.payment_status)}</td><td>{r.expected_payment_date ? fmtDateOnly(r.expected_payment_date) : <span className="muted">нет</span>}</td><td>{r.counterparty_name}</td><td>{r.one_c_comment}</td><td>{r.order_number || <span className="muted">нет</span>}</td><td>{r.bitrix_deal_url ? <a href={r.bitrix_deal_url} target="_blank" rel="noreferrer" onClick={e => e.stopPropagation()}>#{r.bitrix_deal_id}</a> : <span className="muted">нет</span>}</td><td>{user.role === "admin" ? <button onClick={e => { e.stopPropagation(); setAiInvoice(r); }}>AI</button> : <span className="muted">-</span>}</td><td>{r.comments_count}</td><td>{fmtDate(r.last_seen_at)}</td></tr>)}
    </tbody></table></div>
    {selected && <InvoiceDrawer invoice={selected} close={() => { setSelected(null); load(); }} />}
    {aiInvoice && <AiAnswersModal invoice={aiInvoice} close={() => setAiInvoice(null)} />}
  </>;
}

function Shipping() {
  const [data, setData] = useState(null);
  const [error, setError] = useState("");
  async function load() {
    setError("");
    try { setData(await api("/api/shipping")); }
    catch (e) { setError(e.message); }
  }
  useEffect(() => { load(); }, []);
  const rows = data?.rows || [];
  return <>
    <div className="topbar"><h1>Отгружено без подписи</h1><button className="icon" title="Обновить" onClick={load}>↻</button></div>
    {error && <div className="toast">{error}</div>}
    {!data ? <div>Загрузка...</div> : <>
      <section className="grid metrics">
        {data.summary.map(item => <div className="metric" key={item.status}>
          <div className="label">{item.label}</div>
          <div className="value">{item.count}</div>
          <div className="muted">{fmtMoney(item.amount)}</div>
        </div>)}
      </section>
      {data.by_organization?.length > 0 && <section className="panel" style={{marginTop: 14}}>
        <h2>По фирмам</h2>
        <SimpleTable rows={data.by_organization} columns={[["organization","Фирма"],["count","Отгрузок"],["amount","Сумма"]]} money="amount" />
      </section>}
      <div className="table-wrap" style={{marginTop: 14}}><table><thead><tr><th>Фирма</th><th>Счет</th><th>Дата</th><th className="money">Сумма</th><th>Оплата</th><th>Отгрузка</th><th>Подпись</th><th>Номер отгрузки</th><th>Контрагент</th><th>Номер заказа</th><th>Комментарий 1С</th><th>Синхронизация</th></tr></thead><tbody>
        {rows.map(row => <tr key={row.id}><td>{row.organization_name}</td><td>{row.number}</td><td>{fmtDate(row.date)}</td><td className="money">{fmtMoney(row.amount)}</td><td>{paymentLabel(row.payment_status)}</td><td>{row.shipment_status_label || shipmentLabel(row.shipment_status)}</td><td>{row.signature_status_label || signatureLabel(row.signature_status)}</td><td>{((row.shipment_numbers || row.realization_numbers || []).join(", ")) || <span className="muted">нет</span>}</td><td>{row.counterparty_name}</td><td>{row.order_number || <span className="muted">нет</span>}</td><td>{row.one_c_comment}</td><td>{fmtDate(row.last_seen_at)}</td></tr>)}
      </tbody></table></div>
    </>}
  </>;
}

function matchLabel(value) {
  return ({ advance_offset: "Зачет аванса", invoice_number: "Номер счета", comment_invoice_number: "Комментарий + счет", counterparty_amount: "Поставщик + сумма", not_found: "Не найдено" })[value] || value;
}

function Suppliers() {
  const [data, setData] = useState(null);
  const [error, setError] = useState("");
  const [syncing, setSyncing] = useState(false);
  const [organizationId, setOrganizationId] = useState("");
  async function load() {
    setError("");
    try { setData(await api("/api/suppliers")); }
    catch (e) { setError(e.message); }
  }
  async function sync() {
    setError("");
    setSyncing(true);
    try { setData(await api("/api/suppliers/sync", { method: "POST" })); }
    catch (e) { setError(e.message); }
    finally { setSyncing(false); }
  }
  useEffect(() => { load(); }, []);
  const rows = data?.rows || [];
  const organizationOptions = useMemo(() => {
    return (data?.by_organization || [])
      .map(row => {
        const source = (data?.by_supplier || []).find(item => item.organization_name === row.organization);
        return { id: String(source?.organization_id || ""), name: row.organization };
      })
      .filter(org => org.id)
      .sort((a, b) => a.name.localeCompare(b.name, "ru"));
  }, [data]);
  const selectedOrganization = organizationOptions.find(org => org.id === organizationId);
  const filteredRows = organizationId ? rows.filter(row => String(row.organization_id) === organizationId) : rows;
  const filteredAmount = filteredRows.reduce((sum, row) => sum + Number(row.amount || 0), 0);
  const bySupplier = useMemo(() => {
    const rows = data?.by_supplier || [];
    return (organizationId ? rows.filter(row => String(row.organization_id) === organizationId) : rows)
      .slice()
      .sort((a, b) => Number(b.open_amount || 0) - Number(a.open_amount || 0));
  }, [data, organizationId]);
  const bySupplierTotals = useMemo(() => {
    return bySupplier.reduce((total, row) => ({
      supplier: "ИТОГО",
      open_count: total.open_count + Number(row.open_count || 0),
      open_amount: total.open_amount + Number(row.open_amount || 0),
      closed_count: total.closed_count + Number(row.closed_count || 0),
      closed_amount: total.closed_amount + Number(row.closed_amount || 0),
      total_count: total.total_count + Number(row.total_count || 0),
      total_amount: total.total_amount + Number(row.total_amount || 0),
    }), {
      supplier: "ИТОГО",
      open_count: 0,
      open_amount: 0,
      closed_count: 0,
      closed_amount: 0,
      total_count: 0,
      total_amount: 0,
    });
  }, [bySupplier]);
  const filteredByOrganization = organizationId
    ? (data?.by_organization || []).filter(row => row.organization === selectedOrganization?.name)
    : (data?.by_organization || []);
  return <>
    <div className="topbar"><h1>Поставщики</h1><div className="row"><button className="icon" title="Обновить" onClick={load}>↻</button><button className="primary" onClick={sync} disabled={syncing}>{syncing ? "Синхронизация..." : "Обновить из 1С"}</button></div></div>
    {error && <div className="toast">{error}</div>}
    {!data ? <div>Загрузка...</div> : <>
      <section className="grid metrics">
        <div className="metric"><div className="label">Требуют закрывающих</div><div className="value">{filteredRows.length}</div><div className="muted">{fmtMoney(filteredAmount)}</div></div>
        <div className="metric"><div className="label">Год оплат</div><div className="value">{data.year}</div><div className="muted">обновлено {fmtDate(data.generated_at)}</div></div>
      </section>
      <div className="toolbar" style={{marginTop: 14}}>
        <select value={organizationId} onChange={e => setOrganizationId(e.target.value)}>
          <option value="">Все фирмы</option>
          {organizationOptions.map(org => <option key={org.id} value={org.id}>{org.name}</option>)}
        </select>
      </div>
      {filteredByOrganization.length > 0 && <section className="panel" style={{marginTop: 14}}>
        <h2>По фирмам</h2>
        <SimpleTable rows={filteredByOrganization} columns={[["organization","Фирма"],["total_payments","Всего проплат"],["posted_payments","Проведено"],["count","Проблем"],["amount","Сумма"]]} money="amount" />
      </section>}
      <div className="table-wrap" style={{marginTop: 14}}><table><thead><tr><th>Фирма</th><th>Дата оплаты</th><th>Платеж</th><th className="money">Сумма</th><th>Поставщик</th><th>Статус</th><th>Закрывающий</th><th>Вх. номер</th><th>Связь</th><th>Назначение</th></tr></thead><tbody>
        {filteredRows.map((row, index) => <tr key={`${row.organization_id}-${row.payment_ref_key}-${index}`}><td>{row.organization_name}</td><td>{fmtDate(row.payment_date)}</td><td>{row.payment_number}</td><td className="money">{fmtMoney(row.amount)}</td><td>{row.supplier_name}</td><td>{row.closing_status_label}</td><td>{row.closing_number ? `${row.closing_number} от ${fmtDate(row.closing_date)}` : <span className="muted">нет</span>}</td><td>{row.closing_incoming_number || <span className="muted">нет</span>}</td><td>{matchLabel(row.match_method)}</td><td>{row.purpose}</td></tr>)}
      </tbody></table></div>
      {bySupplier.length > 0 && <section className="panel" style={{marginTop: 14}}>
        <h2>По контрагентам</h2>
        <SimpleTable
          rows={bySupplier}
          footerRows={[bySupplierTotals]}
          columns={[["supplier","Контрагент"],["open_count","Не закрыто кол-во"],["open_amount","Не закрыто сумма"],["closed_count","Закрыто кол-во"],["closed_amount","Закрыто сумма"],["total_count","Всего кол-во"],["total_amount","Всего сумма"]]}
          money={["open_amount","closed_amount","total_amount"]}
        />
      </section>}
      {data.diagnostics?.length > 0 && <section className="panel" style={{marginTop: 14}}>
        <h2>Диагностика</h2>
        <SimpleTable rows={data.diagnostics} columns={[["organization","Фирма"],["ok","OK"],["total_payments","Всего проплат"],["posted_payments","Проведено"],["unposted_payments","Не проведено"],["problem_rows","Проблем"],["receipts","Поступлений"],["message","Ошибка"]]} />
      </section>}
    </>}
  </>;
}

function InvoiceDrawer({ invoice, close }) {
  const [detail, setDetail] = useState(invoice);
  const [comments, setComments] = useState([]);
  const [orderNumber, setOrderNumber] = useState(invoice.order_number || "");
  const [comment, setComment] = useState("");
  const [error, setError] = useState("");
  const [bitrixDeals, setBitrixDeals] = useState(null);
  const [bitrixLoading, setBitrixLoading] = useState(false);
  const [bitrixError, setBitrixError] = useState("");
  async function load() {
    setDetail(await api(`/api/invoices/${invoice.id}`));
    setComments(await api(`/api/invoices/${invoice.id}/comments`));
  }
  useEffect(() => { load().catch(e => setError(e.message)); }, []);
  async function saveOrder() {
    setError("");
    try { setDetail(await api(`/api/invoices/${invoice.id}/order-number`, { method: "PATCH", body: JSON.stringify({ order_number: orderNumber }) })); }
    catch (e) { setError(e.message); }
  }
  async function addComment() {
    setError("");
    try { await api(`/api/invoices/${invoice.id}/comments`, { method: "POST", body: JSON.stringify({ comment }) }); setComment(""); await load(); }
    catch (e) { setError(e.message); }
  }
  async function findBitrixDeal() {
    const normalized = orderNumber.replace(/\D/g, "");
    if (!normalized) {
      setBitrixError("Укажите номер заказа");
      setBitrixDeals(null);
      return;
    }
    setBitrixLoading(true);
    setBitrixError("");
    try {
      setBitrixDeals(await api(`/api/bitrix/deals/by-order/${encodeURIComponent(normalized)}`));
    } catch (e) {
      setBitrixError(e.message);
      setBitrixDeals(null);
    } finally {
      setBitrixLoading(false);
    }
  }
  return <>
    <div className="drawer-backdrop" onClick={close}></div>
    <aside className="drawer">
      <div className="topbar"><h1>{detail.number}</h1><button className="icon" onClick={close}>×</button></div>
      {error && <div className="toast">{error}</div>}
      <div className="stack">
        <div><b>{detail.organization_name}</b></div>
        <div>{fmtDate(detail.date)} · {fmtMoney(detail.amount)}</div>
        <div>{detail.counterparty_name}</div>
        <div className="muted">{detail.one_c_comment}</div>
        <label>Номер заказа<input value={orderNumber} onChange={e => setOrderNumber(e.target.value.replace(/\D/g, "").slice(0, 32))} /></label>
        <button className="primary" onClick={saveOrder}>Сохранить</button>
        <h2>Bitrix24</h2>
        {detail.bitrix_deal_url && <div className="comment">
          <b><a href={detail.bitrix_deal_url} target="_blank" rel="noreferrer">#{detail.bitrix_deal_id} {detail.bitrix_deal_title}</a></b>
          <div className="muted">Сохраненная привязка · {fmtDate(detail.bitrix_deal_date)}</div>
        </div>}
        <button onClick={findBitrixDeal} disabled={bitrixLoading || !orderNumber}>{bitrixLoading ? "Ищу..." : "Найти сделку"}</button>
        {bitrixError && <div className="toast">{bitrixError}</div>}
        {bitrixDeals && <div className="stack">
          <div className="muted">
            Найдено: {bitrixDeals.count}
            {bitrixDeals.fallback_to_all_years ? " · за год счета не найдено, показаны все годы" : ""}
          </div>
          {bitrixDeals.deals.length === 0 && <div className="muted">Сделка не найдена</div>}
          {bitrixDeals.deals.map(deal => <div className="comment" key={deal.id}>
            <b><a href={deal.url} target="_blank" rel="noreferrer">#{deal.id} {deal.title}</a></b>
            <div className="muted">{deal.category} · {deal.stage_id} · {fmtDate(deal.date_create)}</div>
          </div>)}
        </div>}
        <h2>Комментарии</h2>
        {comments.map(c => <div className="comment" key={c.id}><b>{c.author}</b> <span className="muted">{fmtDate(c.created_at)}</span><div>{c.comment}</div></div>)}
        <textarea value={comment} onChange={e => setComment(e.target.value)} placeholder="Комментарий" />
        <button onClick={addComment}>Добавить</button>
        <h2>Технические данные</h2>
        <div className="muted">Ref_Key: {detail.ref_key}</div>
        <div className="muted">DataVersion: {detail.data_version}</div>
      </div>
    </aside>
  </>;
}

function AiAnswerPayload({ value }) {
  if (!value || typeof value !== "object" || Array.isArray(value)) {
    return <pre className="json-preview">{prettyJson(value)}</pre>;
  }
  const evidence = Array.isArray(value.evidence) ? value.evidence : [];
  return <div className="stack">
    {Object.entries(value).filter(([key]) => key !== "evidence").map(([key, val]) => <div key={key} className="answer-line">
      <span className="muted">{key}</span>
      <strong>{typeof val === "object" ? prettyJson(val) : String(val ?? "")}</strong>
    </div>)}
    {evidence.length > 0 && <div>
      <h2>Источники</h2>
      {evidence.map((item, index) => <div className="comment" key={index}>
        <b>{item.source_type || "Источник"}</b> <span className="muted">{item.source_date || ""}</span>
        <div>{item.quote || prettyJson(item)}</div>
      </div>)}
    </div>}
  </div>;
}

function AiAnswersModal({ invoice, close }) {
  const [answers, setAnswers] = useState([]);
  const [loading, setLoading] = useState(Boolean(invoice.bitrix_deal_id));
  const [error, setError] = useState("");
  useEffect(() => {
    if (!invoice.bitrix_deal_id) return;
    api(`/api/invoices/${invoice.id}/ai-answers`)
      .then(setAnswers)
      .catch(e => setError(e.message))
      .finally(() => setLoading(false));
  }, [invoice.id, invoice.bitrix_deal_id]);
  return <>
    <div className="drawer-backdrop" onClick={close}></div>
    <aside className="drawer ai-modal">
      <div className="topbar"><h1>AI анализ</h1><button className="icon" onClick={close}>×</button></div>
      <div className="stack">
        <div><b>Счет {invoice.number}</b> · {fmtMoney(invoice.amount)}</div>
        <div>{invoice.counterparty_name || <span className="muted">контрагент не указан</span>}</div>
        {invoice.bitrix_deal_url
          ? <a href={invoice.bitrix_deal_url} target="_blank" rel="noreferrer">Открыть сделку #{invoice.bitrix_deal_id}</a>
          : <div className="toast">Нет данных по сделке</div>}
        {error && <div className="toast">{error}</div>}
        {loading && <div>Загрузка...</div>}
        {!loading && invoice.bitrix_deal_id && answers.length === 0 && <div className="muted">Ответов пока нет. Запустите анализ на странице AI вопросы или дождитесь расписания.</div>}
        {answers.map(answer => <section className="panel stack" key={answer.id}>
          <div className="row spaced">
            <h2>{answer.question_title || "Вопрос"}</h2>
            <span className="muted">{fmtDate(answer.generated_at)}</span>
          </div>
          {answer.confidence && <div className="muted">Уверенность: {answer.confidence}</div>}
          {answer.answer_text && <div>{answer.answer_text}</div>}
          <AiAnswerPayload value={answer.answer_json} />
          {answer.sources_json && <details>
            <summary>Технические источники</summary>
            <pre className="json-preview">{prettyJson(answer.sources_json)}</pre>
          </details>}
        </section>)}
      </div>
    </aside>
  </>;
}

function AiQuestions() {
  const empty = {
    id: null,
    title: "",
    question: "",
    response_schema: "",
    is_active: true,
    interval_minutes: 120,
  };
  const [rows, setRows] = useState([]);
  const [form, setForm] = useState(empty);
  const [message, setMessage] = useState("");
  const [error, setError] = useState("");
  const [saving, setSaving] = useState(false);
  const [running, setRunning] = useState(false);
  async function load() {
    setRows(await api("/api/admin/ai/questions"));
  }
  useEffect(() => { load().catch(e => setError(e.message)); }, []);
  function edit(question) {
    setForm({
      id: question.id,
      title: question.title,
      question: question.question,
      response_schema: question.response_schema ? prettyJson(question.response_schema) : "",
      is_active: question.is_active,
      interval_minutes: question.interval_minutes,
    });
    setError("");
    setMessage("");
  }
  function parseSchema() {
    const text = form.response_schema.trim();
    if (!text) return null;
    try { return JSON.parse(text); }
    catch (e) { throw new Error(`JSON-схема не читается: ${e.message}`); }
  }
  async function save(e) {
    e.preventDefault();
    setSaving(true);
    setError("");
    setMessage("");
    try {
      const payload = {
        title: form.title,
        question: form.question,
        response_schema: parseSchema(),
        is_active: form.is_active,
        interval_minutes: Number(form.interval_minutes || 120),
      };
      if (form.id) {
        await api(`/api/admin/ai/questions/${form.id}`, { method: "PATCH", body: JSON.stringify(payload) });
        setMessage("Вопрос сохранен");
      } else {
        await api("/api/admin/ai/questions", { method: "POST", body: JSON.stringify(payload) });
        setMessage("Вопрос создан");
        setForm(empty);
      }
      await load();
    } catch (e) {
      setError(e.message);
    } finally {
      setSaving(false);
    }
  }
  async function runNow() {
    setRunning(true);
    setError("");
    setMessage("");
    try {
      const result = await api("/api/admin/ai/run", { method: "POST" });
      setMessage(prettyJson(result));
    } catch (e) {
      setError(e.message);
    } finally {
      setRunning(false);
    }
  }
  return <>
    <div className="topbar">
      <h1>AI вопросы</h1>
      <button className="primary" onClick={runNow} disabled={running}>{running ? "Анализ..." : "Запустить анализ"}</button>
    </div>
    {error && <div className="toast">{error}</div>}
    {message && <pre className="notice">{message}</pre>}
    <div className="forms ai-forms">
      <form className="panel stack" onSubmit={save}>
        <h2>{form.id ? "Редактировать вопрос" : "Новый вопрос"}</h2>
        <label>Название<input value={form.title} onChange={e => setForm({...form, title: e.target.value})} required /></label>
        <label>Вопрос<textarea value={form.question} onChange={e => setForm({...form, question: e.target.value})} required /></label>
        <label>JSON-схема ответа<textarea className="schema-editor" value={form.response_schema} onChange={e => setForm({...form, response_schema: e.target.value})} placeholder='{"type":"object","properties":{"answer":{"type":"string"}}}' /></label>
        <label>Интервал, минут<input type="number" min="15" max="10080" value={form.interval_minutes} onChange={e => setForm({...form, interval_minutes: e.target.value})} /></label>
        <label className="check-row"><input type="checkbox" checked={form.is_active} onChange={e => setForm({...form, is_active: e.target.checked})} /> Активен</label>
        <div className="row">
          <button className="primary" disabled={saving}>{saving ? "Сохранение..." : "Сохранить"}</button>
          {form.id && <button type="button" onClick={() => setForm(empty)}>Новый</button>}
        </div>
      </form>
      <section className="panel">
        <h2>Список вопросов</h2>
        <div className="table-wrap"><table><thead><tr><th>Название</th><th>Активен</th><th>Интервал</th><th>Изменен</th><th></th></tr></thead><tbody>
          {rows.map(row => <tr key={row.id}>
            <td><b>{row.title}</b><div className="muted">{row.question}</div></td>
            <td>{row.is_active ? "Да" : "Нет"}</td>
            <td>{row.interval_minutes}</td>
            <td>{fmtDate(row.updated_at)}</td>
            <td><button onClick={() => edit(row)}>Открыть</button></td>
          </tr>)}
          {rows.length === 0 && <tr><td colSpan="5" className="muted">Вопросов пока нет</td></tr>}
        </tbody></table></div>
      </section>
    </div>
  </>;
}

function Organizations() {
  const empty = { name: "", odata_base_url: "", invoice_entity_set: "Document_СчетНаОплатуПокупателю", one_c_username: "", one_c_password: "", is_active: true, include_in_dashboards: true, sync_interval_minutes: 5, payment_strategy: "metadata_unknown" };
  const [rows, setRows] = useState([]);
  const [form, setForm] = useState(empty);
  const [message, setMessage] = useState("");
  async function load() { setRows(await api("/api/admin/organizations")); }
  useEffect(() => { load(); }, []);
  async function submit(e) { e.preventDefault(); await api("/api/admin/organizations", { method: "POST", body: JSON.stringify(form) }); setForm(empty); load(); }
  async function test(id) { setMessage(JSON.stringify(await api(`/api/admin/organizations/${id}/test-connection`, { method: "POST" }), null, 2)); }
  async function sync(id) { setMessage(JSON.stringify(await api(`/api/admin/organizations/${id}/sync-now`, { method: "POST" }), null, 2)); load(); }
  async function toggleDashboards(org) {
    await api(`/api/admin/organizations/${org.id}`, { method: "PATCH", body: JSON.stringify({ include_in_dashboards: !org.include_in_dashboards }) });
    await load();
  }
  return <><div className="topbar"><h1>Организации</h1></div><div className="forms">
    <form className="panel stack" onSubmit={submit}>
      <h2>Новая организация</h2>
      {Object.keys(empty).map(k => ["is_active", "include_in_dashboards"].includes(k) ? null : <input key={k} placeholder={k} value={form[k]} onChange={e => setForm({...form, [k]: e.target.value})} />)}
      <button className="primary">Добавить</button>
    </form>
    <div className="panel"><SimpleTable rows={rows} columns={[["name","Название"],["invoice_entity_set","EntitySet"],["is_active","Активна"],["include_in_dashboards","В дашбордах"],["last_success_sync_at","Синхр."],["last_sync_error","Ошибка"]]} />
      <div className="stack" style={{marginTop: 12}}>{rows.map(o => <div className="row" key={o.id}><b>{o.name}</b><button onClick={() => test(o.id)}>Проверить</button><button onClick={() => sync(o.id)}>Синхронизировать</button><button onClick={() => toggleDashboards(o)}>{o.include_in_dashboards ? "Убрать из дашбордов" : "Вернуть в дашборды"}</button></div>)}</div>
      {message && <pre>{message}</pre>}
    </div>
  </div></>;
}

function Users() {
  const [rows, setRows] = useState([]);
  const [form, setForm] = useState({ login: "", password: "", role: "user", is_active: true });
  async function load() { setRows(await api("/api/admin/users")); }
  useEffect(() => { load(); }, []);
  async function submit(e) { e.preventDefault(); await api("/api/admin/users", { method: "POST", body: JSON.stringify(form) }); setForm({ login: "", password: "", role: "user", is_active: true }); load(); }
  return <><div className="topbar"><h1>Пользователи</h1></div><div className="forms">
    <form className="panel stack" onSubmit={submit}><h2>Новый пользователь</h2><input placeholder="Логин" value={form.login} onChange={e => setForm({...form, login: e.target.value})} /><input placeholder="Пароль" type="password" value={form.password} onChange={e => setForm({...form, password: e.target.value})} /><select value={form.role} onChange={e => setForm({...form, role: e.target.value})}><option value="user">user</option><option value="admin">admin</option></select><button className="primary">Создать</button></form>
    <div className="panel"><SimpleTable rows={rows} columns={[["login","Логин"],["role","Роль"],["is_active","Активен"],["last_login_at","Последний вход"]]} /></div>
  </div></>;
}

function Sync() {
  const [result, setResult] = useState("");
  async function syncAll() { setResult(JSON.stringify(await api("/api/admin/organizations/sync-all", { method: "POST" }), null, 2)); }
  return <><div className="topbar"><h1>Синхронизация</h1><button className="primary" onClick={syncAll}>Синхронизировать все</button></div><pre>{result}</pre></>;
}

function App() {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);
  useEffect(() => { api("/api/auth/me").then(setUser).catch(() => setUser(null)).finally(() => setLoading(false)); }, []);
  if (loading) return <div className="login">Загрузка...</div>;
  return user ? <Shell user={user} setUser={setUser} /> : <Login onLogin={setUser} />;
}

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