Загрузка данных


async function calculateConversion(source = 'from') {
    const requestId = ++conversionRequestId;

    const from = getCurrencyValue(fromSelect);
    const to = getCurrencyValue(toSelect);

    if (!from || !to) {
        return;
    }

    let amount;
    let apiFrom;
    let apiTo;

    if (source === 'from') {
        amount = Number(amountInput.value);
        apiFrom = from;
        apiTo = to;
    } else {
        amount = Number(toAmountDisplay.value.replace(/\s/g, '').replace(',', '.'));
        apiFrom = to;
        apiTo = from;
    }

    // Если поле пустое или введено некорректное значение
    if (!Number.isFinite(amount) || amount <= 0) {
        if (source === 'from') {
            toAmountDisplay.value = '';
            mainResultEl.textContent = '—';
        } else {
            amountInput.value = '';
            mainResultEl.textContent = '—';
        }

        mainCurrencyEl.textContent = getCurrencyShortLabel(to);

        if (mainChangeEl) {
            mainChangeEl.textContent = '';
        }

        return;
    }

    // Если выбраны одинаковые валюты
    if (from === to) {
        if (source === 'from') {
            toAmountDisplay.value = formatter.format(amount);
        } else {
            amountInput.value = formatter.format(amount);
        }

        mainResultEl.textContent = formatNumber(amount, 4);
        mainCurrencyEl.textContent = getCurrencyShortLabel(to);

        if (mainChangeEl) {
            mainChangeEl.textContent =
                `1 ${getCurrencyShortLabel(from)} = 1 ${getCurrencyShortLabel(to)}`;
            mainChangeEl.className = 'result-change';
        }

        return;
    }

    const targetInput = source === 'from'
        ? toAmountDisplay
        : amountInput;

    targetInput.classList.add('loading');

    try {
        const data = await apiFetch(
            `/convert?from_curr=${encodeURIComponent(apiFrom)}&to_curr=${encodeURIComponent(apiTo)}&amount=${encodeURIComponent(amount)}`
        );

        // Пока запрос выполнялся, пользователь мог изменить поле.
        // Старый ответ в таком случае игнорируем.
        if (requestId !== conversionRequestId) {
            return;
        }

        const result = Number(data.result);
        const rate = Number(data.rate);

        if (!Number.isFinite(result) || !Number.isFinite(rate)) {
            throw new Error('Сервер вернул некорректный результат');
        }

        if (source === 'from') {
            toAmountDisplay.value = formatter.format(result);
        } else {
            amountInput.value = formatter.format(result);
        }

        mainResultEl.textContent = formatNumber(
            source === 'from' ? result : amount,
            4
        );

        mainCurrencyEl.textContent = getCurrencyShortLabel(to);

        if (mainChangeEl) {
            mainChangeEl.textContent =
                `1 ${getCurrencyShortLabel(from)} = ${formatNumber(
                    source === 'from' ? rate : 1 / rate,
                    6
                )} ${getCurrencyShortLabel(to)}`;

            mainChangeEl.className = 'result-change';
        }

    } catch (error) {
        if (requestId !== conversionRequestId) {
            return;
        }

        console.error(error);

        if (source === 'from') {
            toAmountDisplay.value = 'Ошибка';
        } else {
            amountInput.value = 'Ошибка';
        }

        mainResultEl.textContent = '—';

        if (mainChangeEl) {
            mainChangeEl.textContent = error.message;
        }

    } finally {
        if (requestId === conversionRequestId) {
            targetInput.classList.remove('loading');
        }
    }
}