const state = {
  user: 'admin',
  role: 'admin',
  token: null,
  authSource: 'local',
  fullName: null,
  dashboard: null,
  leads: [],
  deals: [],
  selectedDealId: '',
  workspaceById: {},
  logLines: [],
};

const SESSION_STORAGE_KEY = 'cc_session';
const STAGE_OPTIONS = [
  'new_qualified_lead',
  'warm_lead',
  'hot_lead',
  'enrichment_required',
  'active_text_communication',
  'active_voice_communication',
  'waiting_customer_reply',
  'offer_preparing',
  'offer_sent',
  'conditions_negotiation',
  'counterparty_data_requested',
  'counterparty_data_received',
  'document_preparing',
  'document_sent',
  'document_confirmed',
  'invoice_preparing',
  'invoice_sent',
  'payment_expected',
  'partially_paid',
  'paid',
  'payment_overdue',
  'won',
  'lost',
  'postponed',
  'follow_up_scheduled',
  'transferred_to_execution',
  'transferred_to_support',
];

const BOARD_GROUPS = [
  { key: 'inbound', title: 'Вход', note: 'Квалифицированный lead intake и дообогащение.', stages: ['new_qualified_lead', 'warm_lead', 'hot_lead', 'enrichment_required'] },
  { key: 'communication', title: 'Коммуникация', note: 'Text/voice сессии, вопросы и follow-up.', stages: ['active_text_communication', 'active_voice_communication', 'waiting_customer_reply'] },
  { key: 'commercial', title: 'Коммерция', note: 'Оффер, согласование условий, next step.', stages: ['offer_preparing', 'offer_sent', 'conditions_negotiation'] },
  { key: 'paperwork', title: 'Оформление', note: 'Реквизиты, документы, подтверждение.', stages: ['counterparty_data_requested', 'counterparty_data_received', 'document_preparing', 'document_sent', 'document_confirmed'] },
  { key: 'finance', title: 'Финансы', note: 'Счет, оплата, просрочка.', stages: ['invoice_preparing', 'invoice_sent', 'payment_expected', 'partially_paid', 'paid', 'payment_overdue'] },
  { key: 'outcome', title: 'Закрытие', note: 'Win/loss/post-sale handoff.', stages: ['won', 'lost', 'postponed', 'follow_up_scheduled', 'transferred_to_execution', 'transferred_to_support'] },
];

const STAGE_LABELS = {
  new_qualified_lead: 'Новый квалифицированный лид',
  warm_lead: 'Теплый лид',
  hot_lead: 'Горячий лид',
  enrichment_required: 'Нужно дообогащение',
  active_text_communication: 'Текстовая коммуникация',
  active_voice_communication: 'Голосовая коммуникация',
  waiting_customer_reply: 'Ждем ответ клиента',
  offer_preparing: 'Готовим оффер',
  offer_sent: 'Оффер отправлен',
  conditions_negotiation: 'Согласуем условия',
  counterparty_data_requested: 'Запрос реквизитов',
  counterparty_data_received: 'Реквизиты получены',
  document_preparing: 'Готовим документ',
  document_sent: 'Документ отправлен',
  document_confirmed: 'Документ подтвержден',
  invoice_preparing: 'Готовим счет',
  invoice_sent: 'Счет отправлен',
  payment_expected: 'Ждем оплату',
  partially_paid: 'Частичная оплата',
  paid: 'Оплачено',
  payment_overdue: 'Просрочка оплаты',
  won: 'Успешно',
  lost: 'Потеряно',
  postponed: 'Отложено',
  follow_up_scheduled: 'Follow-up',
  transferred_to_execution: 'Передано в исполнение',
  transferred_to_support: 'Передано человеку',
};

const $ = (id) => document.getElementById(id);

function log(message, payload) {
  const ts = new Date().toLocaleTimeString();
  const suffix = payload ? ` ${JSON.stringify(payload)}` : '';
  state.logLines.unshift(`[${ts}] ${message}${suffix}`);
  state.logLines = state.logLines.slice(0, 14);
  $('salesLog').textContent = state.logLines.join('\n');
}

function syncSessionFromInputs() {
  state.user = $('sessionUser').value.trim() || 'admin';
  state.role = $('sessionRole').value || 'admin';
}

function persistSession() {
  window.localStorage.setItem(
    SESSION_STORAGE_KEY,
    JSON.stringify({
      access_token: state.token,
      user: state.user,
      role: state.role,
      auth_source: state.authSource,
      full_name: state.fullName,
    }),
  );
}

function clearStoredSession() {
  window.localStorage.removeItem(SESSION_STORAGE_KEY);
}

function restoreStoredSession() {
  const raw = window.localStorage.getItem(SESSION_STORAGE_KEY);
  if (!raw) {
    return false;
  }
  try {
    const payload = JSON.parse(raw);
    if (!payload?.access_token) {
      clearStoredSession();
      return false;
    }
    state.token = payload.access_token;
    state.user = payload.user || state.user;
    state.role = payload.role || state.role;
    state.authSource = payload.auth_source || 'local';
    state.fullName = payload.full_name || null;
    $('sessionUser').value = state.user;
    $('sessionRole').value = state.role;
    $('authPanel').style.display = 'none';
    updateSessionInfo();
    updateProfile();
    return true;
  } catch {
    clearStoredSession();
    return false;
  }
}

function updateSessionInfo(extra = '') {
  $('sessionInfo').textContent = state.token
    ? `Токен активен | роль: ${state.role}${extra ? ` | ${extra}` : ''}`
    : 'Токен: отсутствует';
}

function updateProfile() {
  $('profileName').textContent = state.fullName || state.user || 'Экран продаж';
  $('profileRole').textContent = `Роль: ${state.role || 'unknown'}`;
}

async function api(path, options = {}) {
  syncSessionFromInputs();
  const headers = {
    'Content-Type': 'application/json',
    'X-User': state.user,
    'X-Role': state.role,
    ...(options.headers || {}),
  };
  if (state.token) {
    headers.Authorization = `Bearer ${state.token}`;
  }
  const response = await fetch(`/proxy/sales/${path}`, { ...options, headers });
  let data;
  try {
    data = await response.json();
  } catch {
    data = { error: 'Сервис вернул не JSON' };
  }
  if (!response.ok) {
    throw new Error(`${response.status}: ${JSON.stringify(data)}`);
  }
  return data;
}

async function login() {
  syncSessionFromInputs();
  try {
    const data = await fetch('/proxy/auth/auth/login', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'X-User': state.user,
        'X-Role': state.role,
      },
      body: JSON.stringify({
        username: state.user,
        password: $('sessionPassword').value,
      }),
    }).then((response) => response.json());
    state.token = data.access_token;
    state.role = data.role;
    state.authSource = data.auth_source || 'local';
    state.fullName = data.full_name || null;
    $('authPanel').style.display = 'none';
    updateSessionInfo();
    updateProfile();
    persistSession();
    log('Логин выполнен', { user: state.user, role: state.role });
    await refreshAll();
  } catch (error) {
    updateSessionInfo(`ошибка: ${error.message}`);
    log('Ошибка входа', { error: error.message });
  }
}

function logout() {
  clearStoredSession();
  window.location.href = '/';
}

async function checkGateway() {
  try {
    const data = await fetch('/health').then((response) => response.json());
    $('gatewayStatus').textContent = `Шлюз: ${data.status === 'ok' ? 'готов' : data.status}`;
  } catch {
    $('gatewayStatus').textContent = 'Шлюз: недоступен';
  }
}

function stageLabel(stageId) {
  return STAGE_LABELS[stageId] || stageId || 'Без этапа';
}

function boardGroupsWithItems() {
  const query = ($('salesSearch').value || '').trim().toLowerCase();
  return BOARD_GROUPS.map((group) => {
    const items = state.deals.filter((deal) => {
      const inGroup = group.stages.includes(deal.stage_id);
      if (!inGroup) {
        return false;
      }
      if (!query) {
        return true;
      }
      return [
        deal.title,
        deal.need_summary,
        deal.current_channel,
        deal.customer_id,
      ].some((value) => String(value || '').toLowerCase().includes(query));
    });
    return { ...group, items };
  });
}

function salesCard(deal) {
  const activeClass = deal.deal_id === state.selectedDealId ? 'active' : '';
  const amount = Number(deal.final_amount || deal.estimated_amount || 0);
  return `
    <button class="sales-card ${activeClass}" type="button" data-deal-id="${deal.deal_id}">
      <div class="sales-card-top">
        <div class="sales-card-title">${deal.title}</div>
        <div class="sales-card-priority">P${deal.priority}</div>
      </div>
      <div class="sales-card-body">${deal.need_summary || 'Потребность еще не уточнена.'}</div>
      <div class="sales-card-meta">
        <span class="sales-chip">${stageLabel(deal.stage_id)}</span>
        <span class="sales-chip">${deal.current_channel || 'канал не задан'}</span>
        <span class="sales-chip">${amount.toLocaleString('ru-RU')} ${deal.currency || 'KZT'}</span>
      </div>
    </button>
  `;
}

function renderBoard() {
  $('salesBoard').innerHTML = boardGroupsWithItems()
    .map(
      (group) => `
        <section class="sales-column">
          <div class="sales-column-head">
            <div class="sales-column-title">${group.title}</div>
            <div class="sales-column-count">${group.items.length}</div>
          </div>
          <div class="sales-column-note">${group.note}</div>
          <div class="sales-card-list">
            ${group.items.length ? group.items.map((deal) => salesCard(deal)).join('') : '<div class="sales-workspace-empty">Пусто.</div>'}
          </div>
        </section>
      `,
    )
    .join('');
}

function kpiCard(label, value, note) {
  return `
    <article class="sales-kpi-card">
      <div class="sales-kpi-label">${label}</div>
      <div class="sales-kpi-value">${value}</div>
      <div class="sales-kpi-note">${note}</div>
    </article>
  `;
}

function renderDashboard() {
  const data = state.dashboard;
  if (!data) {
    $('salesDashboard').innerHTML = '';
    return;
  }
  $('salesDashboard').innerHTML = [
    kpiCard('Лиды', Number(data.leads_total || 0), 'Сколько квалифицированных лидов уже в CRM'),
    kpiCard('Активные сделки', Number(data.deals_active || 0), 'Открытые кейсы в работе'),
    kpiCard('Выиграно', Number(data.deals_won || 0), 'Закрыто с оплатой'),
    kpiCard('Просрочка', Number(data.overdue_invoices || 0), 'Счета, которые зависли'),
    kpiCard('Ожидаем оплату', `${Number(data.payment_expected || 0).toLocaleString('ru-RU')} KZT`, 'Потенциальный cash-in'),
    kpiCard('Получено', `${Number(data.payment_received || 0).toLocaleString('ru-RU')} KZT`, 'Фактические оплаты'),
    kpiCard('Voice сессии', Number(data.voice_sessions || 0), 'Голосовой контур продаж'),
    kpiCard('Text сессии', Number(data.text_sessions || 0), 'Текстовый контур продаж'),
    kpiCard('Switch channel', Number(data.channel_switches || 0), 'Переходы между voice/text'),
    kpiCard('Эскалации', Number(data.human_escalations || 0), 'Передачи живому менеджеру'),
  ].join('');
}

function renderStageOptions() {
  $('dealStageSelect').innerHTML = STAGE_OPTIONS.map((value) => `<option value="${value}">${stageLabel(value)}</option>`).join('');
}

function workspaceMetric(label, value) {
  return `
    <div class="sales-metric">
      <div class="sales-metric-label">${label}</div>
      <div class="sales-metric-value">${value}</div>
    </div>
  `;
}

function kvItem(label, value) {
  return `
    <div class="sales-kv-item">
      <div class="sales-kv-label">${label}</div>
      <div class="sales-kv-value">${value || '—'}</div>
    </div>
  `;
}

function listRows(items, titleKey, bodyKey) {
  if (!items?.length) {
    return '<div class="sales-workspace-empty">Пока пусто.</div>';
  }
  return `<div class="sales-list">${items
    .map(
      (item) => `
        <div class="sales-list-row">
          <div>
            <strong>${item[titleKey]}</strong>
            <span>${item[bodyKey] || ''}</span>
          </div>
          <div>
            <span>${item.updated_at || item.created_at || item.started_at || ''}</span>
          </div>
        </div>
      `,
    )
    .join('')}</div>`;
}

function renderWorkspace() {
  if (!state.selectedDealId) {
    $('dealWorkspace').innerHTML = 'Выберите карточку на воронке, чтобы увидеть подробности.';
    $('dealMetrics').innerHTML = '';
    $('dealTitle').textContent = 'Выберите сделку';
    $('dealSubtitle').textContent = 'Справа будет единый контекст: text + voice, офферы, счета, оплата, timeline.';
    $('dealStageBadge').textContent = 'Нет данных';
    $('telegramThreadId').value = '';
    $('telegramChatId').value = '';
    $('voiceSessionId').value = '';
    return;
  }

  const workspace = state.workspaceById[state.selectedDealId];
  if (!workspace) {
    $('dealWorkspace').innerHTML = 'Загружаю карточку сделки...';
    return;
  }

  const { deal, lead, communications, offers, documents, invoices, payments, timeline, counterparty, escalations, tasks } = workspace;
  const bindings = workspaceBindings(workspace);
  $('dealTitle').textContent = deal.title;
  $('dealSubtitle').textContent = `${stageLabel(deal.stage_id)} • ${deal.current_channel || 'канал не задан'} • ${deal.status}`;
  $('dealStageBadge').textContent = stageLabel(deal.stage_id);
  $('dealStageSelect').value = deal.stage_id;
  $('telegramThreadId').value = bindings.telegramThreadId || '';
  $('telegramChatId').value = bindings.telegramChatId || '';
  $('voiceSessionId').value = bindings.voiceSessionId || '';

  $('dealMetrics').innerHTML = [
    workspaceMetric('Канал', deal.current_channel || '—'),
    workspaceMetric('Следующий шаг', deal.next_action_type || 'не задан'),
    workspaceMetric('Сумма', `${Number(deal.final_amount || deal.estimated_amount || 0).toLocaleString('ru-RU')} ${deal.currency || 'KZT'}`),
    workspaceMetric('Customer link', deal.customer_id || 'не привязан'),
  ].join('');

  $('dealWorkspace').innerHTML = `
    <div class="sales-workspace-grid">
      <section class="sales-section-card">
        <h3>Lead / Deal core</h3>
        <div class="sales-kv">
          ${kvItem('Lead', lead?.lead_id || '—')}
          ${kvItem('Имя', lead?.full_name || '—')}
          ${kvItem('Телефон', lead?.phone || '—')}
          ${kvItem('Предпочтительный канал', deal.preferred_channel || '—')}
          ${kvItem('Score', lead?.lead_score || '—')}
          ${kvItem('Потребность', deal.need_summary || lead?.initial_need_summary || '—')}
        </div>
      </section>

      <section class="sales-section-card">
        <h3>Counterparty</h3>
        <div class="sales-kv">
          ${kvItem('Компания', counterparty?.company_name || '—')}
          ${kvItem('Контакт', counterparty?.full_name || '—')}
          ${kvItem('BIN/IIN', counterparty?.bin_iin || '—')}
          ${kvItem('Email для документов', counterparty?.email_for_docs || '—')}
        </div>
      </section>

      <section class="sales-section-card">
        <h3>Коммуникации</h3>
        ${listRows(
          communications.map((item) => ({
            ...item,
            headline: `${item.channel_type === 'voice' ? 'Voice' : 'Text'} • ${item.direction}`,
            detail: item.summary || item.subject || item.result_code || 'Без summary',
          })),
          'headline',
          'detail',
        )}
      </section>

      <section class="sales-section-card">
        <h3>Коммерческий пакет</h3>
        ${listRows(
          offers.map((item) => ({
            ...item,
            headline: `${item.title} • ${item.status}`,
            detail: `${Number(item.total_amount || 0).toLocaleString('ru-RU')} ${item.currency}`,
          })),
          'headline',
          'detail',
        )}
      </section>

      <section class="sales-section-card">
        <h3>Документы и счета</h3>
        ${listRows(
          [...documents, ...invoices].map((item) => ({
            ...item,
            headline: item.document_id
              ? `${item.document_type} • ${item.status}`
              : `${item.invoice_number} • ${item.status}`,
            detail: item.document_id
              ? (item.file_url || 'Файл еще не прикреплен')
              : `${Number(item.amount || 0).toLocaleString('ru-RU')} ${item.currency}`,
          })),
          'headline',
          'detail',
        )}
      </section>

      <section class="sales-section-card">
        <h3>Оплаты, задачи, эскалации</h3>
        ${listRows(
          [
            ...payments.map((item) => ({
              ...item,
              headline: `Оплата • ${item.status}`,
              detail: `${Number(item.amount || 0).toLocaleString('ru-RU')} ${item.currency}`,
            })),
            ...tasks.map((item) => ({
              ...item,
              headline: `Task • ${item.task_type}`,
              detail: `${item.status} • ${item.run_at}`,
            })),
            ...escalations.map((item) => ({
              ...item,
              headline: `Эскалация • ${item.severity}`,
              detail: item.reason,
            })),
          ],
          'headline',
          'detail',
        )}
      </section>

      <section class="sales-section-card">
        <h3>Timeline</h3>
        <div class="sales-stream">
          ${timeline.length ? timeline
            .map(
              (item) => `
                <div class="sales-stream-item">
                  <div class="sales-stream-title">${item.title}</div>
                  <div class="sales-stream-time">${item.ts}</div>
                  <div class="sales-stream-body">${item.body}</div>
                </div>
              `,
            )
            .join('') : '<div class="sales-workspace-empty">Пока нет timeline событий.</div>'}
        </div>
      </section>
    </div>
  `;
}

function latestCommunication(workspace, channelType = '') {
  const items = workspace?.communications || [];
  if (!channelType) {
    return items[0] || null;
  }
  return items.find((item) => item.channel_type === channelType) || items[0] || null;
}

function workspaceBindings(workspace) {
  const bindings = {
    telegramThreadId: '',
    telegramChatId: '',
    voiceSessionId: '',
  };
  for (const item of workspace?.communications || []) {
    const metadata = item.metadata || {};
    if (!bindings.telegramThreadId && metadata.telegram_thread_id) {
      bindings.telegramThreadId = metadata.telegram_thread_id;
    }
    if (!bindings.telegramChatId && metadata.telegram_chat_id) {
      bindings.telegramChatId = metadata.telegram_chat_id;
    }
    if (!bindings.voiceSessionId && metadata.voice_session_id) {
      bindings.voiceSessionId = metadata.voice_session_id;
    }
  }
  return bindings;
}

async function loadDashboard() {
  state.dashboard = await api('api/v1/dashboard');
  renderDashboard();
}

async function loadDeals() {
  const query = ($('salesSearch').value || '').trim();
  const params = new URLSearchParams();
  if (query) {
    params.set('query', query);
  }
  const path = params.toString() ? `api/v1/deals?${params.toString()}` : 'api/v1/deals';
  state.deals = await api(path);
  renderBoard();
}

async function loadLeads() {
  state.leads = await api('api/v1/leads');
}

async function loadWorkspace(dealId) {
  state.workspaceById[dealId] = await api(`api/v1/deals/${encodeURIComponent(dealId)}/workspace`);
  renderWorkspace();
}

async function refreshAll() {
  await Promise.all([loadDashboard(), loadDeals(), loadLeads()]);
  if (state.selectedDealId) {
    await loadWorkspace(state.selectedDealId);
  }
}

async function selectDeal(dealId) {
  state.selectedDealId = dealId;
  renderBoard();
  renderWorkspace();
  await loadWorkspace(dealId);
}

function selectedWorkspace() {
  return state.workspaceById[state.selectedDealId] || null;
}

async function createLead() {
  try {
    const payload = {
      source_type: 'crm',
      source_channel: $('leadSourceChannel').value,
      full_name: $('leadName').value.trim(),
      company_name: $('leadCompany').value.trim() || null,
      phone: $('leadPhone').value.trim() || null,
      email: $('leadEmail').value.trim() || null,
      lead_temperature: $('leadTemperature').value,
      lead_score: Number($('leadScore').value || 68),
      initial_need_summary: $('leadNeedSummary').value.trim() || null,
      preferred_channel: $('leadPreferredChannel').value,
      assigned_agent_type: $('leadPreferredChannel').value === 'voice' ? 'voice_ai' : 'text_ai',
      status: 'new_qualified_lead',
      priority: 3,
      title: $('leadName').value.trim() ? `Лид: ${$('leadName').value.trim()}` : null,
    };
    await api('api/v1/leads', { method: 'POST', body: JSON.stringify(payload) });
    log('Лид создан', payload);
    await refreshAll();
  } catch (error) {
    log('Ошибка создания лида', { error: error.message });
  }
}

async function seedDemo() {
  $('leadName').value = 'Demo Buyer';
  $('leadCompany').value = 'KazTrade Labs';
  $('leadPhone').value = '+77015551234';
  $('leadEmail').value = 'buyer@kaztrade.test';
  $('leadNeedSummary').value = 'Нужен расчет и оффер на пакет услуг с возможностью быстро перейти из чата в звонок.';
  $('leadPreferredChannel').value = 'telegram';
  $('leadTemperature').value = 'hot';
  $('leadScore').value = '81';
  await createLead();
}

async function postQuickAction(handler, successLabel) {
  if (!state.selectedDealId) {
    log('Сначала выберите сделку.');
    return;
  }
  try {
    await handler();
    log(successLabel, { deal_id: state.selectedDealId });
    await refreshAll();
  } catch (error) {
    log('Ошибка действия', { error: error.message });
  }
}

async function startTextSession() {
  return postQuickAction(
    () => api(`api/v1/deals/${encodeURIComponent(state.selectedDealId)}/communications/text`, {
      method: 'POST',
      body: JSON.stringify({
        channel_type: 'text',
        direction: 'outbound',
        agent_type: 'text_ai',
        subject: 'Текстовый follow-up по сделке',
      }),
    }),
    'Текстовая сессия создана',
  );
}

async function startVoiceSession() {
  const workspace = selectedWorkspace();
  const phone = workspace?.lead?.phone || workspace?.counterparty?.phone_for_docs || '+77010000000';
  return postQuickAction(
    () => api('api/v1/calls/outbound', {
      method: 'POST',
      body: JSON.stringify({
        deal_id: state.selectedDealId,
        phone_number: phone,
        provider: 'voice_assistant',
        subject: 'Голосовой follow-up по сделке',
      }),
    }),
    'Голосовая сессия создана',
  );
}

async function switchToText() {
  const workspace = selectedWorkspace();
  const communication = workspace?.communications?.[0];
  if (!communication) {
    log('Нет коммуникации для channel switch.');
    return;
  }
  return postQuickAction(
    () => api(`api/v1/communications/${encodeURIComponent(communication.communication_id)}/switch-channel`, {
      method: 'POST',
      body: JSON.stringify({
        to_channel: 'telegram',
        reason_for_channel_switch: 'После звонка нужно зафиксировать условия письменно',
      }),
    }),
    'Сделка переведена в текст',
  );
}

async function switchToVoice() {
  const workspace = selectedWorkspace();
  const communication = workspace?.communications?.[0];
  if (!communication) {
    log('Нет коммуникации для channel switch.');
    return;
  }
  return postQuickAction(
    () => api(`api/v1/communications/${encodeURIComponent(communication.communication_id)}/switch-channel`, {
      method: 'POST',
      body: JSON.stringify({
        to_channel: 'voice',
        reason_for_channel_switch: 'Сложный кейс, удобнее перейти в звонок',
      }),
    }),
    'Сделка переведена в voice',
  );
}

async function createOffer() {
  const workspace = selectedWorkspace();
  const amount = Number(workspace?.deal?.estimated_amount || workspace?.deal?.final_amount || 150000);
  return postQuickAction(
    () => api(`api/v1/deals/${encodeURIComponent(state.selectedDealId)}/offers`, {
      method: 'POST',
      body: JSON.stringify({
        offer_type: 'offer',
        title: `Коммерческое предложение • ${workspace?.deal?.title || 'Сделка'}`,
        description: 'Автогенерированный оффер для быстрого запуска продажного цикла.',
        line_items: [{ name: 'Основной пакет', quantity: 1, price: amount }],
        pricing: { subtotal: amount, vat: 0, total: amount },
        total_amount: amount,
        currency: workspace?.deal?.currency || 'KZT',
      }),
    }),
    'Оффер создан',
  );
}

async function createInvoice() {
  const workspace = selectedWorkspace();
  const amount = Number(workspace?.deal?.final_amount || workspace?.deal?.estimated_amount || 150000);
  const firstDocument = workspace?.documents?.[0];
  return postQuickAction(
    () => api(`api/v1/deals/${encodeURIComponent(state.selectedDealId)}/invoices`, {
      method: 'POST',
      body: JSON.stringify({
        basis_document_id: firstDocument?.document_id || null,
        amount,
        currency: workspace?.deal?.currency || 'KZT',
        due_date: $('nextActionAt').value.trim() || null,
        line_items: [{ title: workspace?.deal?.title || 'Сделка', amount }],
        metadata: { generated_from: 'sales_ui' },
      }),
    }),
    'Счет создан',
  );
}

async function markPaid() {
  const workspace = selectedWorkspace();
  const invoice = workspace?.invoices?.[0];
  if (!invoice) {
    log('Сначала создайте счет.');
    return;
  }
  return postQuickAction(
    () => api('api/v1/payments/webhook', {
      method: 'POST',
      body: JSON.stringify({
        deal_id: state.selectedDealId,
        invoice_id: invoice.invoice_id,
        payment_provider: 'manual',
        amount: invoice.amount,
        currency: invoice.currency,
        status: 'success',
        payment_method: 'bank_transfer',
      }),
    }),
    'Оплата зафиксирована',
  );
}

async function saveStage() {
  return postQuickAction(
    () => api(`api/v1/deals/${encodeURIComponent(state.selectedDealId)}/change-stage`, {
      method: 'POST',
      body: JSON.stringify({
        stage_id: $('dealStageSelect').value,
        reason: 'Ручное обновление стадии из sales workspace',
      }),
    }),
    'Этап обновлен',
  );
}

async function saveNextAction() {
  return postQuickAction(
    () => api(`api/v1/deals/${encodeURIComponent(state.selectedDealId)}/schedule-next-action`, {
      method: 'POST',
      body: JSON.stringify({
        next_action_type: $('nextActionType').value.trim() || 'follow_up',
        next_action_at: $('nextActionAt').value.trim() || null,
        payload: { source: 'sales_ui' },
      }),
    }),
    'Next action сохранен',
  );
}

async function bindTelegramThread() {
  const workspace = selectedWorkspace();
  const communication = latestCommunication(workspace, 'text');
  const threadId = $('telegramThreadId').value.trim();
  if (!communication) {
    log('Сначала откройте text-сессию по сделке.');
    return;
  }
  if (!threadId) {
    log('Укажите telegram thread id.');
    return;
  }
  return postQuickAction(
    () => api(`api/v1/communications/${encodeURIComponent(communication.communication_id)}/bind-external`, {
      method: 'POST',
      body: JSON.stringify({
        channel_provider: 'telegram',
        telegram_thread_id: threadId,
        telegram_chat_id: $('telegramChatId').value.trim() || null,
        metadata: { source: 'sales_ui_binding' },
      }),
    }),
    'Telegram thread привязан к сделке',
  );
}

async function bindVoiceSession() {
  const workspace = selectedWorkspace();
  const communication = latestCommunication(workspace, 'voice');
  const voiceSessionId = $('voiceSessionId').value.trim();
  if (!communication) {
    log('Сначала откройте voice-сессию по сделке.');
    return;
  }
  if (!voiceSessionId) {
    log('Укажите voice session id.');
    return;
  }
  return postQuickAction(
    () => api(`api/v1/communications/${encodeURIComponent(communication.communication_id)}/bind-external`, {
      method: 'POST',
      body: JSON.stringify({
        channel_provider: 'voice',
        voice_session_id: voiceSessionId,
        metadata: { source: 'sales_ui_binding' },
      }),
    }),
    'Voice session привязана к сделке',
  );
}

async function sendTelegramReply() {
  const workspace = selectedWorkspace();
  const communication = latestCommunication(workspace, 'text');
  const threadId = $('telegramThreadId').value.trim();
  const body = $('telegramReplyText').value.trim();
  if (!threadId) {
    log('Сначала привяжите Telegram thread.');
    return;
  }
  if (!body) {
    log('Введите текст сообщения.');
    return;
  }
  return postQuickAction(
    () => api('api/v1/messages/outbound', {
      method: 'POST',
      body: JSON.stringify({
        deal_id: state.selectedDealId,
        communication_id: communication?.communication_id || null,
        channel_provider: 'telegram',
        sender_type: 'human',
        sender_id: state.user,
        body,
        metadata: {
          telegram_thread_id: threadId,
          telegram_chat_id: $('telegramChatId').value.trim() || null,
          source: 'sales_ui_temp_telegram',
        },
      }),
    }),
    'Сообщение поставлено в Telegram bridge',
  ).then(() => {
    $('telegramReplyText').value = '';
  });
}

function handleBoardClick(event) {
  const button = event.target.closest('[data-deal-id]');
  if (!button) {
    return;
  }
  selectDeal(button.dataset.dealId).catch((error) => {
    log('Ошибка загрузки сделки', { error: error.message });
  });
}

function bindEvents() {
  $('loginBtn').addEventListener('click', login);
  $('logoutBtn').addEventListener('click', logout);
  $('refreshSalesBtn').addEventListener('click', () => refreshAll().catch((error) => log('Ошибка обновления', { error: error.message })));
  $('salesSearch').addEventListener('input', renderBoard);
  $('salesBoard').addEventListener('click', handleBoardClick);
  $('createLeadBtn').addEventListener('click', createLead);
  $('seedDemoBtn').addEventListener('click', seedDemo);
  $('startTextBtn').addEventListener('click', startTextSession);
  $('startVoiceBtn').addEventListener('click', startVoiceSession);
  $('switchToTextBtn').addEventListener('click', switchToText);
  $('switchToVoiceBtn').addEventListener('click', switchToVoice);
  $('createOfferBtn').addEventListener('click', createOffer);
  $('createInvoiceBtn').addEventListener('click', createInvoice);
  $('markPaidBtn').addEventListener('click', markPaid);
  $('saveStageBtn').addEventListener('click', saveStage);
  $('saveNextActionBtn').addEventListener('click', saveNextAction);
  $('bindTelegramBtn').addEventListener('click', bindTelegramThread);
  $('bindVoiceSessionBtn').addEventListener('click', bindVoiceSession);
  $('sendTelegramReplyBtn').addEventListener('click', sendTelegramReply);
}

async function init() {
  renderStageOptions();
  bindEvents();
  updateProfile();
  await checkGateway();
  if (restoreStoredSession()) {
    log('Сессия восстановлена', { user: state.user, role: state.role });
    await refreshAll();
  }
}

init().catch((error) => {
  log('Ошибка инициализации', { error: error.message });
});
