import { renderHeader } from '../components/header.js';
import { directMessages } from '../mock-data.js';
import {
  addAppLogEntry,
  addChatMessage,
  addSystemChatMessage,
  addOutgoingPendingMessage,
  getChatMessages,
  markChatRead,
  markOutgoingSent,
  markReadReceiptSentByBaseKey,
  authService,
  setContacts,
  state,
} from '../state.js';
import { startOutgoingCall } from '../services/call-service.js';
import { openSpeechInputModal } from '../components/speech-input-modal.js';
import { isTextToSpeechConfigured, speakTextBySettings } from '../services/speech-tools-service.js';
import { showToast } from '../services/channels-ux.js';

export const pageMeta = { id: 'chat-view', title: 'Чат' };

function openMessageActionsModal({ messageText = '', onReadAloud }) {
  const root = document.getElementById('modal-root');
  if (!root) return;
  root.innerHTML = `
    <div class="modal" id="chat-message-actions-modal-overlay">
      <div class="modal-card stack dm-dialog-card dm-message-actions-menu" id="chat-message-actions-modal">
        <button class="secondary-btn dm-message-action-btn" type="button" id="msg-action-copy">Копировать</button>
        <button class="secondary-btn dm-message-action-btn" type="button" id="msg-action-read">Прочесть</button>
      </div>
    </div>
  `;

  const close = () => {
    root.innerHTML = '';
  };

  root.querySelector('#chat-message-actions-modal-overlay')?.addEventListener('click', (event) => {
    if (event.target?.id === 'chat-message-actions-modal-overlay') close();
  });
  root.querySelector('#msg-action-copy')?.addEventListener('click', async () => {
    try {
      if (navigator?.clipboard?.writeText) {
        await navigator.clipboard.writeText(String(messageText || ''));
      }
      showToast('Сообщение скопированно', { timeoutMs: 1000 });
    } catch {
      showToast('Не удалось скопировать сообщение', { kind: 'error', timeoutMs: 1200 });
    } finally {
      close();
    }
  });
  root.querySelector('#msg-action-read')?.addEventListener('click', async () => {
    close();
    if (typeof onReadAloud === 'function') await onReadAloud();
  });
}

function showTtsMissingConfigDialog(navigate) {
  const root = document.getElementById('modal-root');
  if (!root) return;
  root.innerHTML = `
    <div class="modal" id="chat-tts-missing-modal">
      <div class="modal-card stack dm-dialog-card">
        <h3 class="modal-title">Озвучка не настроена</h3>
        <p class="meta-muted">Перейти в настройки инструментов?</p>
        <div class="form-actions-grid">
          <button class="secondary-btn" type="button" id="chat-tts-no">Нет</button>
          <button class="primary-btn" type="button" id="chat-tts-yes">Да</button>
        </div>
      </div>
    </div>
  `;
  const close = () => { root.innerHTML = ''; };
  root.querySelector('#chat-tts-no')?.addEventListener('click', close);
  root.querySelector('#chat-tts-yes')?.addEventListener('click', () => {
    close();
    navigate('tools-settings-view');
  });
}

function autoResizeComposer(textarea) {
  if (!textarea) return;
  textarea.style.height = 'auto';
  textarea.style.height = `${Math.min(180, Math.max(42, textarea.scrollHeight))}px`;
}

function openConfirmContactModal(targetLogin = '') {
  const root = document.getElementById('modal-root');
  if (!root) return Promise.resolve(false);
  return new Promise((resolve) => {
    root.innerHTML = `
      <div class="modal" id="contact-confirm-modal">
        <div class="modal-card stack dm-dialog-card">
          <h3 class="modal-title">Добавить собеседника</h3>
          <p class="meta-muted">Добавить пользователя @${targetLogin} в контакты?</p>
          <div class="form-actions-grid">
            <button class="secondary-btn" type="button" id="contact-confirm-no">Нет</button>
            <button class="primary-btn" type="button" id="contact-confirm-yes">Да</button>
          </div>
        </div>
      </div>
    `;

    const close = (answer) => {
      root.innerHTML = '';
      resolve(!!answer);
    };
    root.querySelector('#contact-confirm-no')?.addEventListener('click', () => close(false));
    root.querySelector('#contact-confirm-yes')?.addEventListener('click', () => close(true));
  });
}

function parseBaseKey(baseKey) {
  const raw = String(baseKey || '').trim();
  const parts = raw.split('|');
  if (parts.length < 4) return null;
  const fromLogin = parts[0] || '';
  const toLogin = parts[1] || '';
  const timeMs = Number(parts[2] || 0);
  const nonce = Number(parts[3] || 0);
  if (!fromLogin || !toLogin || !Number.isFinite(timeMs) || !Number.isFinite(nonce)) return null;
  return { fromLogin, toLogin, timeMs, nonce };
}

function resolveMessageTimeMs(msg) {
  const base = parseBaseKey(msg?.baseKey);
  if (base?.timeMs && Number.isFinite(base.timeMs) && base.timeMs > 0) return base.timeMs;

  const messageKey = String(msg?.messageKey || '').trim();
  if (messageKey) {
    const parts = messageKey.split('|');
    const timeMs = Number(parts[2] || 0);
    if (parts.length >= 4 && Number.isFinite(timeMs) && timeMs > 0) return timeMs;
  }

  const tempId = String(msg?.tempId || '').trim();
  if (tempId.startsWith('tmp-')) {
    const ts = Number(tempId.split('-')[1] || 0);
    if (Number.isFinite(ts) && ts > 0) return ts;
  }

  const fallback = Number(msg?.createdAtMs || 0);
  if (Number.isFinite(fallback) && fallback > 0) return fallback;
  return 0;
}

function formatMessageTime(valueMs) {
  const timeMs = Number(valueMs || 0);
  if (!Number.isFinite(timeMs) || timeMs <= 0) return '';
  return new Intl.DateTimeFormat('ru-RU', {
    day: '2-digit',
    month: '2-digit',
    year: '2-digit',
    hour: '2-digit',
    minute: '2-digit',
  }).format(new Date(timeMs));
}

function resolveDeliveryStatus(msg) {
  if (msg?.from !== 'out') return '';
  if (msg?.secondTick) return '✓✓';
  if (msg?.firstTick) return '✓';
  return '…';
}

function scrollToLatestMessage(list) {
  if (!list) return;
  const apply = () => {
    list.scrollTop = list.scrollHeight;
  };
  apply();
  window.requestAnimationFrame(apply);
  window.requestAnimationFrame(() => window.requestAnimationFrame(apply));
  window.setTimeout(apply, 0);
  window.setTimeout(apply, 60);
  window.setTimeout(apply, 120);
  window.setTimeout(apply, 260);
}

function renderLog(list, chatId, { onOpenActions } = {}) {
  list.innerHTML = '';
  const messages = getChatMessages(chatId);
  let unreadSeparatorInserted = false;
  messages.forEach((msg) => {
    if (!unreadSeparatorInserted && msg?.from === 'in' && msg?.unread) {
      const sep = document.createElement('div');
      sep.className = 'chat-unread-separator';
      const label = document.createElement('span');
      label.textContent = 'Новые сообщения';
      sep.append(label);
      list.append(sep);
      unreadSeparatorInserted = true;
    }

    const bubble = document.createElement('div');
    const bubbleKind = String(msg?.kind || '').trim();
    bubble.className = `bubble ${msg.from}${bubbleKind ? ` ${bubbleKind}` : ''}`;

    const textNode = document.createElement('div');
    textNode.className = 'bubble-text';
    textNode.textContent = msg.text || '';

    const metaNode = document.createElement('div');
    metaNode.className = 'bubble-meta';

    const timeNode = document.createElement('span');
    timeNode.className = 'bubble-time';
    timeNode.textContent = formatMessageTime(resolveMessageTimeMs(msg));
    metaNode.append(timeNode);

    const status = resolveDeliveryStatus(msg);
    if (status) {
      const statusNode = document.createElement('span');
      statusNode.className = 'bubble-status';
      statusNode.textContent = status;
      metaNode.append(statusNode);
    }

    bubble.append(textNode, metaNode);
    bubble.addEventListener('click', () => {
      if (typeof onOpenActions === 'function') onOpenActions(msg);
    });
    list.append(bubble);
  });
  scrollToLatestMessage(list);
  markChatRead(chatId);
}

export function render({ navigate, route }) {
  const chatId = route.params.chatId || 'u1';
  const contact = directMessages.find((d) => d.id === chatId) || {
    id: chatId,
    name: chatId,
    initials: (chatId[0] || '?').toUpperCase(),
  };

  const screen = document.createElement('section');
  screen.className = 'stack dm-screen dm-chat-screen';
  const isKnownContact = (state.contacts || []).some((x) => String(x || '').toLowerCase() === String(chatId || '').toLowerCase());

  screen.append(
    renderHeader({
      title: `Чат с ${contact.name}`,
      leftAction: { label: '←', onClick: () => navigate('messages-list') },
      rightActions: [{
        label: 'Позвонить',
        onClick: async () => {
          try {
            await startOutgoingCall(chatId);
            renderLog(log, chatId, {
              onOpenActions: (msg) => openMessageActionsModal({
                messageText: msg?.text || '',
                onReadAloud: async () => {
                  if (!isTextToSpeechConfigured(state.entrySettings)) {
                    showTtsMissingConfigDialog(navigate);
                    return;
                  }
                  await speakTextBySettings(String(msg?.text || ''), state.entrySettings);
                },
              }),
            });
          } catch (e) {
            addSystemChatMessage(chatId, `[Звонок] Ошибка запуска: ${e.message || 'unknown'}`, {
              from: 'out',
              kind: 'call-tech',
            });
            renderLog(log, chatId, {
              onOpenActions: (msg) => openMessageActionsModal({
                messageText: msg?.text || '',
                onReadAloud: async () => {
                  if (!isTextToSpeechConfigured(state.entrySettings)) {
                    showTtsMissingConfigDialog(navigate);
                    return;
                  }
                  await speakTextBySettings(String(msg?.text || ''), state.entrySettings);
                },
              }),
            });
          }
        },
      }],
    })
  );

  if (!isKnownContact) {
    const card = document.createElement('div');
    card.className = 'card';
    const btn = document.createElement('button');
    btn.className = 'secondary-btn';
    btn.type = 'button';
    btn.textContent = 'Добавить собеседника в контакты';
    btn.addEventListener('click', async () => {
      try {
        const approved = await openConfirmContactModal(chatId);
        if (!approved) return;
        await authService.setUserRelation({
          login: state.session.login,
          toLogin: chatId,
          kind: 'contact',
          enabled: true,
          storagePwd: state.session.storagePwdInMemory,
        });
        const contactsPayload = await authService.listContacts();
        setContacts(contactsPayload?.contacts || []);
        addAppLogEntry({
          level: 'info',
          source: 'contacts',
          message: `Пользователь ${chatId} добавлен в контакты`,
        });
        card.remove();
      } catch (e) {
        addAppLogEntry({
          level: 'warn',
          source: 'contacts',
          message: 'Не удалось добавить пользователя в контакты',
          details: { login: chatId, error: e?.message || 'unknown' },
        });
      }
    });
    card.append(btn);
    screen.append(card);
  }

  const wrap = document.createElement('div');
  wrap.className = 'chat-wrap dm-chat-wrap';

  const log = document.createElement('div');
  log.className = 'messages-log dm-messages-log';

  const form = document.createElement('form');
  form.className = 'chat-input dm-chat-input';
  form.innerHTML = `
    <textarea class="input dm-input" name="message" rows="1" placeholder="Введите сообщение" maxlength="2000"></textarea>
    <div class="dm-actions-col">
      <button class="ghost-btn dm-voice-btn" type="button" id="chat-voice-input" title="Голосовой ввод">🎤</button>
      <button class="primary-btn dm-send-btn dm-send-icon-btn" type="submit" title="Отправить">➤</button>
    </div>
  `;

  const sendTextMessage = async (rawText) => {
    const text = String(rawText || '').trim();
    if (!text) return;
    const tempId = addOutgoingPendingMessage(chatId, text);
    renderLog(log, chatId, {
      onOpenActions: (msg) => openMessageActionsModal({
        messageText: msg?.text || '',
        onReadAloud: async () => {
          if (!isTextToSpeechConfigured(state.entrySettings)) {
            showTtsMissingConfigDialog(navigate);
            return;
          }
          await speakTextBySettings(String(msg?.text || ''), state.entrySettings);
        },
      }),
    });

    try {
      const result = await authService.sendDirectMessage({
        login: state.session.login,
        toLogin: chatId,
        text,
        storagePwd: state.session.storagePwdInMemory,
      });
      markOutgoingSent(tempId, {
        messageKey: result?.outgoingKey || '',
        baseKey: result?.baseKey || result?.localBaseKey || '',
      });
      renderLog(log, chatId, {
        onOpenActions: (msg) => openMessageActionsModal({
          messageText: msg?.text || '',
          onReadAloud: async () => {
            if (!isTextToSpeechConfigured(state.entrySettings)) {
              showTtsMissingConfigDialog(navigate);
              return;
            }
            await speakTextBySettings(String(msg?.text || ''), state.entrySettings);
          },
        }),
      });
      addAppLogEntry({
        level: 'info',
        source: 'outgoing-dm',
        message: `Сообщение отправлено для ${chatId}`,
        details: {
          toLogin: chatId,
          messageId: result?.outgoingKey || '',
          deliveredWsSessions: Number(result?.deliveredWsSessions || 0),
          deliveredWebPushSessions: Number(result?.deliveredWebPushSessions || 0),
        },
      });
    } catch (e) {
      addChatMessage(chatId, `Ошибка отправки: ${e.message || 'unknown'}`);
      addAppLogEntry({
        level: 'warn',
        source: 'outgoing-dm',
        message: 'Ошибка отправки личного сообщения',
        details: {
          toLogin: chatId,
          error: e?.message || 'unknown',
        },
      });
      renderLog(log, chatId, {
        onOpenActions: (msg) => openMessageActionsModal({
          messageText: msg?.text || '',
          onReadAloud: async () => {
            if (!isTextToSpeechConfigured(state.entrySettings)) {
              showTtsMissingConfigDialog(navigate);
              return;
            }
            await speakTextBySettings(String(msg?.text || ''), state.entrySettings);
          },
        }),
      });
    }
  };

  const input = form.elements.message;
  autoResizeComposer(input);
  input?.addEventListener('input', () => autoResizeComposer(input));
  input?.addEventListener('focus', () => {
    scrollToLatestMessage(log);
  });
  input?.addEventListener('keydown', async (event) => {
    if (event.key !== 'Enter') return;
    if (event.ctrlKey) {
      event.preventDefault();
      const start = Number(input.selectionStart ?? input.value.length);
      const end = Number(input.selectionEnd ?? input.value.length);
      const value = String(input.value || '');
      input.value = `${value.slice(0, start)}\n${value.slice(end)}`;
      const nextPos = start + 1;
      try {
        input.setSelectionRange(nextPos, nextPos);
      } catch {
        // ignore
      }
      autoResizeComposer(input);
      return;
    }
    event.preventDefault();
    const text = String(input.value || '').trim();
    if (!text) return;
    input.value = '';
    autoResizeComposer(input);
    await sendTextMessage(text);
  });

  form.querySelector('#chat-voice-input')?.addEventListener('click', async () => {
    await openSpeechInputModal({
      navigate,
      onTextReady: (text) => {
        const prev = String(input.value || '').trim();
        input.value = prev ? `${prev} ${text}` : text;
        autoResizeComposer(input);
      },
      onSendText: async (text) => sendTextMessage(text),
      onSendQueued: () => {
        showToast('Сообщение будет отправлено автоматически после распознавания', { timeoutMs: 1000 });
      },
    });
  });

  form.addEventListener('submit', async (event) => {
    event.preventDefault();
    const text = input.value.trim();
    if (!text) return;
    input.value = '';
    autoResizeComposer(input);
    await sendTextMessage(text);
  });

  wrap.append(log, form);
  screen.append(wrap);
  renderLog(log, chatId, {
    onOpenActions: (msg) => openMessageActionsModal({
      messageText: msg?.text || '',
      onReadAloud: async () => {
        if (!isTextToSpeechConfigured(state.entrySettings)) {
          showTtsMissingConfigDialog(navigate);
          return;
        }
        await speakTextBySettings(String(msg?.text || ''), state.entrySettings);
      },
    }),
  });
  window.requestAnimationFrame(() => scrollToLatestMessage(log));
  window.setTimeout(() => scrollToLatestMessage(log), 180);
  void sendReadReceiptsForVisible(chatId);
  return screen;
}
async function sendReadReceiptsForVisible(chatId) {
  const pending = getChatMessages(chatId)
      .filter((row) => row?.from === 'in' && Number(row?.messageType) === 1 && !row?.readReceiptSent)
      .slice(0, 50);
  for (const row of pending) {
    const ref = parseBaseKey(row.baseKey);
    if (!ref) continue;
    try {
      await authService.sendReadReceipt({
        login: state.session.login,
        toLogin: ref.fromLogin,
        storagePwd: state.session.storagePwdInMemory,
        refToLogin: ref.toLogin,
        refFromLogin: ref.fromLogin,
        refTimeMs: ref.timeMs,
        refNonce: ref.nonce,
        refType: 1,
      });
      if (row.baseKey) {
        markReadReceiptSentByBaseKey(row.baseKey);
      } else {
        row.readReceiptSent = true;
      }
    } catch (e) {
      addAppLogEntry({
        level: 'warn',
        source: 'read-receipt',
        message: 'Не удалось отправить подтверждение прочтения',
        details: { chatId, messageKey: row.messageKey || '', error: e?.message || 'unknown' },
      });
    }
  }
}
