import { renderHeader } from '../components/header.js';
import {
  authService,
  refreshSessions,
  setAuthError,
  setAuthInfo,
  state,
} from '../state.js';
import { formatRelativeTime, showToast } from '../services/channels-ux.js';
import {
  buildSecretsPayload,
  deriveEspPairingPasswordHash,
  encryptPairingPayloadForRequester,
} from '../services/device-pairing-service.js';
import { loadEncryptedUserSecrets } from '../services/key-vault.js';
import { toUserMessage } from '../services/ui-error-texts.js';

export const pageMeta = { id: 'device-pairing-view', title: 'Подключить по коду' };

function setStatus(statusEl, message, kind = 'info') {
  statusEl.classList.toggle('is-unavailable', kind === 'error');
  statusEl.classList.toggle('is-available', kind !== 'error');
  statusEl.textContent = message;
  statusEl.style.display = message ? '' : 'none';
}

function normalizeCode(value) {
  return String(value || '').replace(/\D+/g, '').slice(0, 7);
}

function buildTransferKeys(savedKeys, { withExtras = false }) {
  const keys = {
    deviceKey: String(savedKeys?.deviceKey || '').trim(),
    blockchainKey: '',
    rootKey: '',
  };
  if (!keys.deviceKey) {
    throw new Error('На этом устройстве нет сохранённого device key для передачи.');
  }
  if (withExtras) {
    if (state.deviceConnect.blockchain && savedKeys?.blockchainKey) {
      keys.blockchainKey = String(savedKeys.blockchainKey || '').trim();
    }
    if (state.deviceConnect.root && savedKeys?.rootKey) {
      keys.rootKey = String(savedKeys.rootKey || '').trim();
    }
  }
  return keys;
}

function requestCardHtml(request) {
  const shortCode = String(request?.shortCode || '').trim() || '0000000';
  const client = String(request?.requesterClientPlatform || 'unknown');
  const expiresText = request?.expiresAtMs ? formatRelativeTime(request.expiresAtMs) : '—';
  return `
    <div class="card stack" data-pairing-id="${String(request?.pairingId || '')}">
      <div class="row" style="align-items:flex-start;">
        <div class="stack" style="gap:4px;">
          <div style="font-size:28px; font-weight:700; letter-spacing:0.14em;">${shortCode}</div>
          <span class="meta-muted">Платформа: ${client}</span>
          <span class="meta-muted">Тип payload: ${Number(request?.payloadType || 0)}</span>
          <span class="meta-muted">Истекает: ${expiresText}</span>
        </div>
      </div>
      <div class="row" style="flex-wrap:wrap;">
        <button class="ghost-btn" type="button" data-action="approve-device">Подключить без доп. ключей</button>
        <button class="primary-btn" type="button" data-action="approve-full">Подключить и передать ключи</button>
        <button class="text-btn" type="button" data-action="reject">Отклонить</button>
      </div>
    </div>
  `;
}

export function render({ navigate }) {
  const screen = document.createElement('section');
  screen.className = 'stack';
  let savedKeys = null;
  let requests = [];
  let cleanupEvent = () => {};
  let disposed = false;

  screen.append(
    renderHeader({
      title: 'Подключить по коду',
      leftAction: { label: '←', onClick: () => navigate('connect-device-view') },
    }),
  );

  const settingsCard = document.createElement('div');
  settingsCard.className = 'card stack';
  settingsCard.innerHTML = `
    <p class="field-label">Пароль подключения</p>
    <label class="stack">
      <span class="meta-muted">Задайте пароль, который новое устройство введёт перед получением кода.</span>
      <input class="input" id="pairing-password" type="password" autocomplete="new-password" placeholder="Новый pairing-пароль" />
    </label>
    <div class="row">
      <button class="primary-btn" type="button" id="enable-pairing-btn">Включить / обновить</button>
      <button class="ghost-btn" type="button" id="disable-pairing-btn">Выключить</button>
    </div>
    <p class="meta-muted">Пароль хранится на сервере только в виде hash. После включения можно переходить к заявкам ниже.</p>
  `;

  const keySummaryCard = document.createElement('div');
  keySummaryCard.className = 'card stack';
  keySummaryCard.innerHTML = `
    <p class="field-label">Что передаётся при расширенном подключении</p>
    <p class="meta-muted" id="pairing-key-summary">Проверяем локальные ключи...</p>
  `;

  const requestsCard = document.createElement('div');
  requestsCard.className = 'card stack';
  requestsCard.innerHTML = `
    <div class="row" style="align-items:flex-end; gap:10px; flex-wrap:wrap;">
      <label class="stack" style="flex:1 1 180px;">
        <span class="field-label">Код нового устройства</span>
        <input class="input" id="pairing-code-filter" inputmode="numeric" maxlength="7" placeholder="7 цифр" />
      </label>
      <button class="ghost-btn" type="button" id="refresh-pairing-requests">Обновить заявки</button>
    </div>
    <p class="meta-muted">Если код не введён, показываются все активные заявки. Для подключения без доп. ключей передаётся только device key.</p>
    <div class="stack" id="pairing-requests-list"></div>
  `;

  const status = document.createElement('p');
  status.className = 'status-line is-unavailable';
  status.style.display = 'none';

  const passwordInput = settingsCard.querySelector('#pairing-password');
  const enableBtn = settingsCard.querySelector('#enable-pairing-btn');
  const disableBtn = settingsCard.querySelector('#disable-pairing-btn');
  const keySummaryEl = keySummaryCard.querySelector('#pairing-key-summary');
  const codeFilterInput = requestsCard.querySelector('#pairing-code-filter');
  const refreshBtn = requestsCard.querySelector('#refresh-pairing-requests');
  const requestsListEl = requestsCard.querySelector('#pairing-requests-list');

  const renderRequests = () => {
    const filterCode = normalizeCode(codeFilterInput.value);
    const filtered = filterCode
      ? requests.filter((item) => normalizeCode(item?.shortCode) === filterCode)
      : requests;
    requestsListEl.innerHTML = '';

    if (!filtered.length) {
      const empty = document.createElement('p');
      empty.className = 'meta-muted';
      empty.textContent = filterCode
        ? 'Заявка с таким кодом пока не найдена.'
        : 'Активных заявок сейчас нет.';
      requestsListEl.append(empty);
      return;
    }

    filtered.forEach((request) => {
      const wrapper = document.createElement('div');
      wrapper.innerHTML = requestCardHtml(request);
      requestsListEl.append(wrapper.firstElementChild);
    });
  };

  const loadSavedKeys = async () => {
    savedKeys = await loadEncryptedUserSecrets(state.session.login, state.session.storagePwdInMemory);
    const available = [];
    if (savedKeys?.deviceKey) available.push('device');
    if (savedKeys?.blockchainKey && state.deviceConnect.blockchain) available.push('blockchain');
    if (savedKeys?.rootKey && state.deviceConnect.root) available.push('root');
    keySummaryEl.textContent = available.length
      ? `При расширенном подключении будут переданы: ${available.join(', ')}.`
      : 'На этом устройстве доступен только device key.';
  };

  const reloadRequests = async ({ silent = false } = {}) => {
    try {
      requests = await authService.listEspPairingRequests();
      renderRequests();
      if (!silent) {
        setStatus(status, 'Список pairing-заявок обновлён.', 'info');
      }
    } catch (error) {
      const message = toUserMessage(error, 'Не удалось загрузить pairing-заявки.');
      setAuthError(message);
      setStatus(status, message, 'error');
    }
  };

  const setButtonsBusy = (flag) => {
    enableBtn.disabled = flag;
    disableBtn.disabled = flag;
    refreshBtn.disabled = flag;
  };

  const approveRequest = async (request, mode) => {
    const withExtras = mode === 'with-extras';
    const keys = buildTransferKeys(savedKeys, { withExtras });
    const payload = buildSecretsPayload({
      login: state.session.login,
      keys,
      mode: withExtras ? 'with-extras' : 'device-only',
    });
    const encryptedPayload = await encryptPairingPayloadForRequester(request?.requesterSessionKey, payload);
    await authService.approveEspPairing(request?.pairingId, encryptedPayload);
    showToast(withExtras ? 'Ключи переданы на новое устройство' : 'Новое устройство подключено');
    setAuthInfo(withExtras ? 'Заявка подтверждена, ключи переданы.' : 'Заявка подтверждена без передачи доп. ключей.');
    await refreshSessions().catch(() => {});
    await reloadRequests({ silent: true });
  };

  settingsCard.addEventListener('click', async (event) => {
    const target = event.target;
    if (!(target instanceof HTMLElement)) return;

    if (target.id === 'enable-pairing-btn') {
      const password = String(passwordInput.value || '');
      if (!password) {
        setStatus(status, 'Введите pairing-пароль.', 'error');
        return;
      }
      setButtonsBusy(true);
      try {
        const passwordHash = await deriveEspPairingPasswordHash(state.session.login, password);
        const payload = await authService.upsertEspPairingSettings({
          enabled: true,
          passwordHash,
          ttlSeconds: 180,
        });
        setAuthInfo(`Подключение по коду включено. TTL: ${payload?.ttlSeconds || 180} сек.`);
        setStatus(status, 'Подключение по коду включено или обновлено.', 'info');
        passwordInput.value = '';
      } catch (error) {
        const message = toUserMessage(error, 'Не удалось включить pairing.');
        setAuthError(message);
        setStatus(status, message, 'error');
      } finally {
        setButtonsBusy(false);
      }
      return;
    }

    if (target.id === 'disable-pairing-btn') {
      setButtonsBusy(true);
      try {
        await authService.upsertEspPairingSettings({
          enabled: false,
          passwordHash: '',
          ttlSeconds: 180,
        });
        setAuthInfo('Подключение по коду выключено.');
        setStatus(status, 'Подключение по коду выключено.', 'info');
      } catch (error) {
        const message = toUserMessage(error, 'Не удалось выключить pairing.');
        setAuthError(message);
        setStatus(status, message, 'error');
      } finally {
        setButtonsBusy(false);
      }
    }
  });

  refreshBtn.addEventListener('click', () => {
    void reloadRequests();
  });
  codeFilterInput.addEventListener('input', () => {
    codeFilterInput.value = normalizeCode(codeFilterInput.value);
    renderRequests();
  });

  requestsListEl.addEventListener('click', async (event) => {
    const target = event.target;
    if (!(target instanceof HTMLElement)) return;
    const action = String(target.dataset.action || '');
    if (!action) return;
    const card = target.closest('[data-pairing-id]');
    if (!(card instanceof HTMLElement)) return;
    const pairingId = String(card.dataset.pairingId || '');
    const request = requests.find((item) => String(item?.pairingId || '') === pairingId);
    if (!request) return;

    const buttons = [...card.querySelectorAll('button')];
    buttons.forEach((btn) => { btn.disabled = true; });
    try {
      if (action === 'approve-device') {
        await approveRequest(request, 'device-only');
      } else if (action === 'approve-full') {
        await approveRequest(request, 'with-extras');
      } else if (action === 'reject') {
        await authService.rejectEspPairing(pairingId, 'rejected_by_user');
        showToast('Заявка отклонена', { kind: 'error' });
        await reloadRequests({ silent: true });
      }
    } catch (error) {
      const message = toUserMessage(error, 'Не удалось обработать pairing-заявку.');
      setAuthError(message);
      setStatus(status, message, 'error');
      buttons.forEach((btn) => { btn.disabled = false; });
    }
  });

  void (async () => {
    try {
      await loadSavedKeys();
      await reloadRequests({ silent: true });
      cleanupEvent = authService.onEvent('IncomingEspPairingRequest', () => {
        if (disposed) return;
        showToast('Пришла новая заявка на подключение устройства');
        void reloadRequests({ silent: true });
      });
    } catch (error) {
      const message = toUserMessage(error, 'Не удалось подготовить экран pairing.');
      setAuthError(message);
      setStatus(status, message, 'error');
    }
  })();

  screen.cleanup = () => {
    disposed = true;
    cleanupEvent();
  };

  screen.append(settingsCard, keySummaryCard, requestsCard, status);
  return screen;
}
