import { readShineUserPda, updateServerOnSolana } from '../../js/services/shine-user-pda-service.js';
import {
  $,
  buildKeyBundleFromForm,
  clearGenMessage,
  clearStatus,
  compareExpectedPublicKeys,
  deriveKeyBundleFromPassword,
  fillKeyFields,
  formatBigInt,
  formatTimestamp,
  openDevnetTopup,
  parseLoginList,
  publicKeyBytesToBase58,
  refreshDeviceBalance,
  setGenMessage,
  setStatus,
  setText,
  setupPasswordEye,
  summarizeKeyComparison,
  updateSolAddress,
  validateLoginOrThrow,
  wireDeviceAddressPreview,
} from './server-ui-shared.js';

const fieldMap = {
  masterSecret: 'masterSecret',
  rootPub: 'rootPub',
  rootPriv: 'rootPriv',
  bchPub: 'bchPub',
  bchPriv: 'bchPriv',
  devPub: 'devPub',
  devPriv: 'devPriv',
  solBox: 'solBox',
  solAdr: 'solAdr',
};

let currentPda = null;

function resetExpectedKeysUi() {
  $('expectedKeysBox').style.display = 'none';
  setText('expectedRootPub', '');
  setText('expectedBchPub', '');
  setText('expectedDevPub', '');
  clearGenMessage($('expectedKeysStatus'));
  setText('deviceBalance', 'Баланс device ещё не запрашивался.');
}

function renderExpectedKeys(parsed) {
  $('expectedKeysBox').style.display = 'block';
  setText('expectedRootPub', publicKeyBytesToBase58(parsed.rootKey));
  setText('expectedBchPub', publicKeyBytesToBase58(parsed.blockchain.blockchainPublicKey));
  setText('expectedDevPub', publicKeyBytesToBase58(parsed.deviceKey));
  setGenMessage($('expectedKeysStatus'), 'После генерации ключей этот блок покажет, совпадают ли они с уже записанной PDA.', 'warn');
}

function compareCurrentFormKeysWithPda() {
  if (!currentPda) throw new Error('Сначала загрузите PDA');
  const blockchainActual = String($('bchPub').value || '').trim();
  return {
    resultMap: {
      root: compareExpectedPublicKeys(publicKeyBytesToBase58(currentPda.rootKey), $('rootPub').value),
      blockchain: blockchainActual
        ? compareExpectedPublicKeys(publicKeyBytesToBase58(currentPda.blockchain.blockchainPublicKey), blockchainActual)
        : { matches: true, expected: publicKeyBytesToBase58(currentPda.blockchain.blockchainPublicKey), actual: '' },
      device: compareExpectedPublicKeys(publicKeyBytesToBase58(currentPda.deviceKey), $('devPub').value),
    },
  };
}

function renderComparisonStatus() {
  if (!currentPda) return false;
  try {
    const { resultMap } = compareCurrentFormKeysWithPda();
    const summary = summarizeKeyComparison(resultMap);
    if (summary.allMatch) {
      setGenMessage($('expectedKeysStatus'), 'Ключи совпадают с загруженной PDA. Похоже, пароль верный.', 'ok');
      return true;
    }
    setGenMessage(
      $('expectedKeysStatus'),
      `Не совпали ключи: ${summary.mismatches.join(', ')}. Похоже, пароль неверный или введены не те ключи.`,
      'err',
    );
    return false;
  } catch (error) {
    setGenMessage($('expectedKeysStatus'), error?.message || String(error), 'err');
    return false;
  }
}

setupPasswordEye($('btnEye'), $('password'));
wireDeviceAddressPreview(fieldMap);
$('password').value = '';
resetExpectedKeysUi();

$('btnTopupDevnet').addEventListener('click', () => {
  try {
    openDevnetTopup($('devPub').value);
  } catch (error) {
    setStatus($('status'), error?.message || String(error), 'error');
  }
});

$('btnRefreshBalance').addEventListener('click', async () => {
  try {
    $('btnRefreshBalance').disabled = true;
    await refreshDeviceBalance({
      endpoint: $('endpoint').value,
      deviceAddress: $('devPub').value,
      targetNode: $('deviceBalance'),
    });
  } catch (error) {
    setStatus($('status'), error?.message || String(error), 'error');
  } finally {
    $('btnRefreshBalance').disabled = false;
  }
});

$('btnGen').addEventListener('click', async () => {
  clearGenMessage($('genMsg'));
  clearStatus($('status'));
  $('btnGen').disabled = true;
  try {
    const login = validateLoginOrThrow($('login').value);
    const password = $('password').value;
    const { masterSecret32, keyBundle } = await deriveKeyBundleFromPassword({ login, password });
    fillKeyFields(fieldMap, keyBundle, masterSecret32);
    updateSolAddress(fieldMap);
    $('deviceBalance').textContent = 'Теперь можно проверить баланс device-аккаунта.';
    const keysOk = renderComparisonStatus();
    setGenMessage(
      $('genMsg'),
      keysOk
        ? 'Ключи и master secret сгенерированы из логина и пароля. Device-ключ оплатит транзакцию.'
        : 'Ключи сгенерированы, но не совпали с уже загруженной PDA. Скорее всего, пароль неверный.',
      keysOk ? 'ok' : 'err',
    );
  } catch (error) {
    setGenMessage($('genMsg'), error?.message || String(error), 'err');
  } finally {
    $('btnGen').disabled = false;
  }
});

$('btnLoad').addEventListener('click', async () => {
  clearStatus($('status'));
  clearGenMessage($('genMsg'));
  $('btnLoad').disabled = true;
  currentPda = null;
  $('pdaInfo').style.display = 'none';
  $('updateForm').style.display = 'none';
  resetExpectedKeysUi();
  try {
    const login = validateLoginOrThrow($('login').value);
    const endpoint = String($('endpoint').value || '').trim();
    if (!endpoint) throw new Error('Укажите Solana endpoint');

    setStatus($('status'), 'Загрузка PDA из Solana...', 'info');
    const parsed = await readShineUserPda({ login, solanaEndpoint: endpoint });
    if (!parsed.isServer) throw new Error('Эта PDA не является серверной');
    currentPda = parsed;

    $('iAddr').textContent = parsed.pdaAddress;
    $('iVer').textContent = `#${parsed.recordNumber}`;
    $('iCreated').textContent = formatTimestamp(parsed.createdAtMs);
    $('iUpdated').textContent = formatTimestamp(parsed.updatedAtMs);
    $('iSrvAddr').textContent = parsed.serverAddress || '—';
    $('iSync').textContent = parsed.syncServers.length ? parsed.syncServers.join(', ') : '—';
    $('iBch').textContent = parsed.blockchain.blockchainName;
    $('iLimit').textContent = formatBigInt(parsed.blockchain.paidLimitBytes);

    $('password').value = '';
    $('serverAddress').value = parsed.serverAddress || '';
    $('syncServers').value = parsed.syncServers.join('\n');
    $('pdaInfo').style.display = 'block';
    $('updateForm').style.display = 'block';
    renderExpectedKeys(parsed);
    setStatus($('status'), 'PDA загружена. Можно менять адрес или sync_servers.', 'success');
  } catch (error) {
    setStatus($('status'), error?.message || String(error), 'error');
  } finally {
    $('btnLoad').disabled = false;
  }
});

$('btnUpdate').addEventListener('click', async () => {
  clearStatus($('status'));
  clearGenMessage($('genMsg'));
  $('btnUpdate').disabled = true;
  try {
    if (!currentPda) throw new Error('Сначала загрузите PDA');
    const endpoint = String($('endpoint').value || '').trim();
    if (!endpoint) throw new Error('Укажите Solana endpoint');
    const serverAddress = String($('serverAddress').value || '').trim();
    if (!serverAddress) throw new Error('Укажите адрес сервера');

    setStatus($('status'), 'Проверка и сборка keyBundle...', 'info');
    const { keyBundle, normalized } = await buildKeyBundleFromForm(fieldMap, { requireBlockchain: false });
    $('rootPub').value = normalized.rootPubB58;
    $('rootPriv').value = normalized.rootPrivB58;
    $('bchPub').value = normalized.bchPubB58;
    $('bchPriv').value = normalized.bchPrivB58;
    $('devPub').value = normalized.devPubB58;
    $('devPriv').value = normalized.devPrivB58;
    updateSolAddress(fieldMap);
    if (!renderComparisonStatus()) {
      throw new Error('Ключи не совпадают с загруженной PDA. Проверьте пароль или введённые ключи.');
    }

    setStatus($('status'), 'Отправка update_user_pda в Solana...', 'info');
    const result = await updateServerOnSolana({
      login: currentPda.login,
      keyBundle,
      serverAddress,
      addressFormatType: currentPda.addressFormatType ?? 1,
      addressFormatVersion: currentPda.addressFormatVersion ?? 0,
      syncServers: parseLoginList($('syncServers').value),
      solanaEndpoint: endpoint,
    });

    setStatus(
      $('status'),
      `✓ PDA обновлена!\n\nЛогин: ${currentPda.login}\nPDA: ${result.pdaAddress}\nТранзакция: ${result.signature}`,
      'success',
    );
    currentPda = null;
    $('pdaInfo').style.display = 'none';
    $('updateForm').style.display = 'none';
  } catch (error) {
    setStatus($('status'), error?.message || String(error), 'error');
  } finally {
    $('btnUpdate').disabled = false;
  }
});

document.body.dataset.ready = '1';
