import $ from 'jquery';
import { JSONRPC } from '@/json-rpc.js';

const FIELD_IDS = {
    container: 'settings-config-container',
    status: 'settings-status-message',
    saveButton: 'save-settings-btn',
    changePasswordButton: 'settings-change-password-btn',
    updateSubscriptionsInterval: 'settings-update-subscriptions-interval',
    cachingAS: 'settings-caching-as',
    updateASInterval: 'settings-update-as-interval',
    host: 'settings-host',
    cacheDirectory: 'settings-cache-directory',
    httpPort: 'settings-http-port',
    mergeSubnets: 'settings-merge-subnets',
    displayDebuggingInfo: 'settings-display-debugging-info',
    mergeSubnetsWithUsage: 'settings-merge-subnets-with-usage',
    subscriptionsList: 'settings-subscriptions-list',
    addSubscriptionButton: 'settings-add-subscription',
    customASN: 'settings-custom-asn',
    customSubnets: 'settings-custom-subnets',
    customDomains: 'settings-custom-domains',
    filteredASN: 'settings-filtered-asn',
    filteredSubnets: 'settings-filtered-subnets',
    filteredDomains: 'settings-filtered-domains',
    cachingDomains: 'settings-caching-domains',
    domainResolvers: 'settings-domain-resolvers',
    domainLookupInterval: 'settings-domain-lookup-interval',
    domainsTimeToLive: 'settings-domains-time-to-live'
};

const CLASS_NAMES = {
    subscriptionEntry: 'settings-subscription-entry',
    subscriptionRemove: 'settings-subscription-remove',
    subscriptionName: 'settings-subscription-name',
    subscriptionType: 'settings-subscription-type',
    subscriptionSource: 'settings-subscription-source',
    subscriptionScript: 'settings-subscription-script'
};

let currentConfig = {};
let repositoryTypes = [];
let statusTimeoutId = null;

const getStatusElement = () => $(`#${FIELD_IDS.status}`);

function clearStatus() {
    const $status = getStatusElement();
    if (!$status.length) {
        return;
    }
    if (statusTimeoutId) {
        clearTimeout(statusTimeoutId);
        statusTimeoutId = null;
    }
    $status.stop(true, true).hide().text('').removeClass('success-message error-message');
}

function updateStatus(message, type) {
    const $status = getStatusElement();
    if (!$status.length) {
        return;
    }
    if (statusTimeoutId) {
        clearTimeout(statusTimeoutId);
    }
    $status
        .removeClass('success-message error-message')
        .addClass(type === 'success' ? 'success-message' : 'error-message')
        .text(message)
        .show();

    statusTimeoutId = window.setTimeout(() => {
        $status.fadeOut();
    }, 5000);
}

async function runAction($button, pendingText, action, messages) {
    if (!$button.length) {
        return;
    }

    const originalText = $button.text();
    $button.prop('disabled', true).text(pendingText);
    clearStatus();

    try {
        const result = await action();
        if (messages?.success) {
            const successMessage = typeof messages.success === 'function' ? messages.success(result) : messages.success;
            if (successMessage) {
                updateStatus(successMessage, 'success');
            }
        }
    } catch (error) {
        console.error(messages?.log || 'Ошибка при выполнении действия Settings:', error);
        if (messages?.error) {
            updateStatus(messages.error, 'error');
        }
    } finally {
        $button.prop('disabled', false).text(originalText);
    }
}

async function loadSettings() {
    try {
        const [config, repoTypes] = await Promise.all([
            JSONRPC.System.getConfig(),
            JSONRPC.System.getRepositoryTypes()
        ]);
        currentConfig = config || {};
        repositoryTypes = Array.isArray(repoTypes) ? repoTypes : [];
        return true;
    } catch (error) {
        console.error('Ошибка загрузки настроек:', error);
        currentConfig = {};
        repositoryTypes = [];
        return false;
    }
}

function getConfigValue(key, fallback) {
    return key in currentConfig ? currentConfig[key] : fallback;
}

function getTypeValue(type) {
    if (!type) {
        return '';
    }
    return typeof type === 'string' ? type : type?.name || '';
}

function getTypeLabel(value) {
    if (!value) {
        return '';
    }
    const parts = value.split('.');
    return parts.length ? parts[parts.length - 1] : value;
}

function renderRepositoryOptions(selected) {
    const options = repositoryTypes.map(type => {
        const value = getTypeValue(type);
        if (!value) {
            return '';
        }
        const isSelected = value === selected ? 'selected' : '';
        const label = getTypeLabel(value);
        return `<option value="${value}" ${isSelected}>${label}</option>`;
    }).join('');

    return `<option value="" ${selected ? '' : 'selected'} disabled hidden>Выберите тип</option>${options}`;
}

function createSubscriptionRow(subscription = {}, index = 0) {
    const name = subscription.name || '';
    const type = subscription.type || '';
    const source = subscription.source || '';
    const script = subscription.script || '';
    const uid = `${Date.now()}-${index}`;

    return `
        <div class="${CLASS_NAMES.subscriptionEntry}" style="border: 1px solid var(--color-border); padding: 20px; border-radius: 12px; margin-bottom: 20px; background: var(--color-surface, #1f2333);">
            <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px;">
                <h4 style="margin: 0;">Репозиторий</h4>
                <button type="button" class="btn-link ${CLASS_NAMES.subscriptionRemove}">Удалить</button>
            </div>
            <div class="form-group">
                <label for="subscription-name-${uid}">Название</label>
                <input type="text" id="subscription-name-${uid}" class="form-control ${CLASS_NAMES.subscriptionName}" value="${name}">
            </div>
            <div class="form-group">
                <label for="subscription-type-${uid}">Тип</label>
                <select id="subscription-type-${uid}" class="form-control ${CLASS_NAMES.subscriptionType}">
                    ${renderRepositoryOptions(type)}
                </select>
            </div>
            <div class="form-group">
                <label for="subscription-source-${uid}">Источник</label>
                <input type="text" id="subscription-source-${uid}" class="form-control ${CLASS_NAMES.subscriptionSource}" value="${source}">
            </div>
            <div class="form-group">
                <label for="subscription-script-${uid}">Скрипт</label>
                <input type="text" id="subscription-script-${uid}" class="form-control ${CLASS_NAMES.subscriptionScript}" value="${script}">
            </div>
        </div>
    `;
}

function populateSubscriptions() {
    const $list = $(`#${FIELD_IDS.subscriptionsList}`);
    $list.empty();
    const subscriptions = Array.isArray(currentConfig.subscriptions) ? currentConfig.subscriptions : [];
    subscriptions.forEach((subscription, index) => {
        $list.append(createSubscriptionRow(subscription, index));
    });
}

function textareaFromArray(array) {
    if (!Array.isArray(array) || !array.length) {
        return '';
    }
    return array.join('\n');
}

function renderSettingsForm() {
    const $container = $(`#${FIELD_IDS.container}`);
    const updateSubscriptionsInterval = getConfigValue('updateSubscriptionsInterval', 1);
    const cachingAS = !!getConfigValue('cachingAS', false);
    const updateASInterval = getConfigValue('updateASInterval', 1);
    const host = getConfigValue('host', '');
    const cacheDirectory = getConfigValue('cacheDirectory', '');
    const httpPort = getConfigValue('httpPort', 8080);
    const mergeSubnets = !!getConfigValue('mergeSubnets', false);
    const displayDebuggingInfo = !!getConfigValue('displayDebuggingInfo', false);
    const mergeSubnetsWithUsage = getConfigValue('mergeSubnetsWithUsage', 80);
    const cachingDomains = !!getConfigValue('cachingDomains', false);
    const domainResolvers = getConfigValue('domainResolvers', []);
    const domainLookupInterval = getConfigValue('domainLookupInterval', 60);
    const domainsTimeToLive = getConfigValue('domainsTimeToLive', 24);

    const customResources = getConfigValue('customResources', {});
    const filteredResources = getConfigValue('filteredResources', {});

    $container.html(`
        <div class="component-config-form">
            <div class="action-buttons" style="justify-content: flex-start; margin-bottom: 30px;">
                <button id="${FIELD_IDS.changePasswordButton}" class="btn-secondary" style="width: 220px;">Сменить пароль</button>
            </div>
            <h3 class="config-section-title">Обновление ресурсов</h3>
            <div class="form-group">
                <label for="${FIELD_IDS.updateSubscriptionsInterval}">Интервал обновления подписок (часы)</label>
                <input type="number" min="1" max="24" id="${FIELD_IDS.updateSubscriptionsInterval}" class="form-control" value="${updateSubscriptionsInterval}">
            </div>
            <div class="form-group">
                <label for="${FIELD_IDS.updateASInterval}">Интервал обновления ASN (часы)</label>
                <input type="number" min="1" max="24" id="${FIELD_IDS.updateASInterval}" class="form-control" value="${updateASInterval}">
            </div>
            <div class="form-group checkbox-group">
                <input type="checkbox" id="${FIELD_IDS.cachingAS}" ${cachingAS ? 'checked' : ''}>
                <label for="${FIELD_IDS.cachingAS}" style="margin-bottom: 0;">Кэшировать ASN</label>
            </div>

            <h3 class="config-section-title" style="margin-top: 40px;">Сервис</h3>
            <p class="hint-text" style="margin-bottom: 16px;">После изменения параметров сервиса необходимо перезапустить сервис на вкладке «Статистика», чтобы настройки вступили в силу.</p>
            <div class="form-group">
                <label for="${FIELD_IDS.host}">Хост сервиса</label>
                <input type="text" id="${FIELD_IDS.host}" class="form-control" value="${host}">
            </div>
            <div class="form-group">
                <label for="${FIELD_IDS.httpPort}">HTTP порт</label>
                <input type="number" min="1" max="65535" id="${FIELD_IDS.httpPort}" class="form-control" value="${httpPort}">
            </div>
            <div class="form-group">
                <label for="${FIELD_IDS.cacheDirectory}">Путь к кэшу</label>
                <input type="text" id="${FIELD_IDS.cacheDirectory}" class="form-control" value="${cacheDirectory}">
            </div>
            <div class="form-group checkbox-group">
                <input type="checkbox" id="${FIELD_IDS.displayDebuggingInfo}" ${displayDebuggingInfo ? 'checked' : ''}>
                <label for="${FIELD_IDS.displayDebuggingInfo}" style="margin-bottom: 0;">Отображать отладочную информацию</label>
            </div>

            <h3 class="config-section-title" style="margin-top: 40px;">Сетевые ресурсы</h3>
            <div class="form-group checkbox-group">
                <input type="checkbox" id="${FIELD_IDS.mergeSubnets}" ${mergeSubnets ? 'checked' : ''}>
                <label for="${FIELD_IDS.mergeSubnets}" style="margin-bottom: 0;">Объединять подсети</label>
            </div>
            <div class="form-group">
                <label for="${FIELD_IDS.mergeSubnetsWithUsage}">Объединять подсети с заполнением &gt;= %</label>
                <input type="number" min="51" max="99" id="${FIELD_IDS.mergeSubnetsWithUsage}" class="form-control" value="${mergeSubnetsWithUsage}">
            </div>

            <h3 class="config-section-title" style="margin-top: 40px;">DNS Resolver</h3>
            <div class="form-group checkbox-group">
                <input type="checkbox" id="${FIELD_IDS.cachingDomains}" ${cachingDomains ? 'checked' : ''}>
                <label for="${FIELD_IDS.cachingDomains}" style="margin-bottom: 0;">Кешировать домены</label>
            </div>
            <div class="form-group">
                <label for="${FIELD_IDS.domainResolvers}">DNS серверы</label>
                <textarea id="${FIELD_IDS.domainResolvers}" class="form-control" rows="3" placeholder="8.8.8.8">${textareaFromArray(domainResolvers)}</textarea>
            </div>
            <div class="form-group">
                <label for="${FIELD_IDS.domainLookupInterval}">Интервал проверки доменов (минуты): <span id="domain-lookup-value">${domainLookupInterval}</span></label>
                <input type="range" min="1" max="${60 * 24}" id="${FIELD_IDS.domainLookupInterval}" class="form-control" value="${domainLookupInterval}" style="padding: 0;">
            </div>
            <div class="form-group">
                <label for="${FIELD_IDS.domainsTimeToLive}">Время жизни кешированных доменов (часы): <span id="domains-ttl-value">${domainsTimeToLive}</span></label>
                <input type="range" min="1" max="${24 * 7}" id="${FIELD_IDS.domainsTimeToLive}" class="form-control" value="${domainsTimeToLive}" style="padding: 0;">
            </div>
            <div style="margin-top: 30px;">
                <h4 style="margin-bottom: 15px;">Дополнительные ресурсы</h4>
                <div class="form-group">
                    <label for="${FIELD_IDS.customASN}">Пользовательские ASN</label>
                    <textarea id="${FIELD_IDS.customASN}" class="form-control" rows="3" placeholder="Каждое значение с новой строки">${textareaFromArray(customResources.ASN)}</textarea>
                </div>
                <div class="form-group">
                    <label for="${FIELD_IDS.customSubnets}">Пользовательские подсети</label>
                    <textarea id="${FIELD_IDS.customSubnets}" class="form-control" rows="3" placeholder="Каждая подсеть с новой строки">${textareaFromArray(customResources.subnets)}</textarea>
                </div>
                <div class="form-group">
                    <label for="${FIELD_IDS.customDomains}">Пользовательские домены</label>
                    <textarea id="${FIELD_IDS.customDomains}" class="form-control" rows="3" placeholder="Каждый домен с новой строки">${textareaFromArray(customResources.domains)}</textarea>
                </div>
            </div>
            <div style="margin-top: 30px;">
                <h4 style="margin-bottom: 15px;">Фильтр ресурсов</h4>
                <div class="form-group">
                    <label for="${FIELD_IDS.filteredASN}">Исключаемые ASN</label>
                    <textarea id="${FIELD_IDS.filteredASN}" class="form-control" rows="3">${textareaFromArray(filteredResources.ASN)}</textarea>
                </div>
                <div class="form-group">
                    <label for="${FIELD_IDS.filteredSubnets}">Исключаемые подсети</label>
                    <textarea id="${FIELD_IDS.filteredSubnets}" class="form-control" rows="3">${textareaFromArray(filteredResources.subnets)}</textarea>
                </div>
                <div class="form-group">
                    <label for="${FIELD_IDS.filteredDomains}">Исключаемые домены</label>
                    <textarea id="${FIELD_IDS.filteredDomains}" class="form-control" rows="3">${textareaFromArray(filteredResources.domains)}</textarea>
                </div>
            </div>

            <h3 class="config-section-title" style="margin-top: 40px;">Репозитории подписок</h3>
            <div id="${FIELD_IDS.subscriptionsList}"></div>
            <button type="button" id="${FIELD_IDS.addSubscriptionButton}" class="btn-secondary" style="width: 220px;">Добавить репозиторий</button>

            <div class="action-buttons" style="margin-top: 40px;">
                <button id="${FIELD_IDS.saveButton}" class="btn-primary" style="width: 240px;">Применить Настройки</button>
            </div>
            <div id="${FIELD_IDS.status}" class="error-message" style="display: none; margin-top: 20px;"></div>
        </div>
    `);

    populateSubscriptions();
    attachEventHandlers();
}

function addSubscriptionRow(subscription = {}) {
    const $list = $(`#${FIELD_IDS.subscriptionsList}`);
    const index = $list.children(`.${CLASS_NAMES.subscriptionEntry}`).length;
    $list.append(createSubscriptionRow(subscription, index));
}

function parseNumberInRange(value, min, max, fieldName) {
    const num = parseInt(value, 10);
    if (Number.isNaN(num) || num < min || num > max) {
        throw new Error(`${fieldName} должно быть числом от ${min} до ${max}.`);
    }
    return num;
}

function parseTextAreaLines($element, transform) {
    const lines = $element.val().split('\n').map(line => line.trim()).filter(Boolean);
    if (transform) {
        return lines.map(value => transform(value));
    }
    return lines;
}

function parseASNLines($element) {
    const lines = $element.val().split('\n').map(line => line.trim()).filter(Boolean);
    return lines.map(value => {
        const num = parseInt(value, 10);
        if (Number.isNaN(num) || num < 0) {
            throw new Error(`Некорректный ASN: ${value}`);
        }
        return num;
    });
}

function collectSubscriptions() {
    const subscriptions = [];
    let hasEmptyType = false;
    $(`#${FIELD_IDS.subscriptionsList}`).find(`.${CLASS_NAMES.subscriptionEntry}`).each((_, element) => {
        const $entry = $(element);
        const name = $entry.find(`.${CLASS_NAMES.subscriptionName}`).val().trim();
        const type = $entry.find(`.${CLASS_NAMES.subscriptionType}`).val();
        const source = $entry.find(`.${CLASS_NAMES.subscriptionSource}`).val().trim();
        const script = $entry.find(`.${CLASS_NAMES.subscriptionScript}`).val().trim();

        if (!type) {
            hasEmptyType = true;
            return false;
        }

        if (name || type || source || script) {
            subscriptions.push({ name, type, source, script });
        }
        return true;
    });

    if (hasEmptyType) {
        throw new Error('Для каждого репозитория необходимо выбрать тип.');
    }

    return subscriptions;
}

function buildNetworkResourceBundle({ asnSelector, subnetsSelector, domainsSelector }) {
    const $asn = $(`#${asnSelector}`);
    const $subnets = $(`#${subnetsSelector}`);
    const $domains = $(`#${domainsSelector}`);

    return {
        ASN: parseASNLines($asn),
        subnets: parseTextAreaLines($subnets),
        domains: parseTextAreaLines($domains)
    };
}

function collectSettingsFromForm() {
    const updateSubscriptionsInterval = parseNumberInRange($(`#${FIELD_IDS.updateSubscriptionsInterval}`).val(), 1, 24, 'Интервал обновления подписок');
    const updateASInterval = parseNumberInRange($(`#${FIELD_IDS.updateASInterval}`).val(), 1, 24, 'Интервал обновления ASN');
    const mergeSubnetsWithUsage = parseNumberInRange($(`#${FIELD_IDS.mergeSubnetsWithUsage}`).val(), 51, 99, 'Процент объединения подсетей');
    const domainLookupInterval = parseNumberInRange($(`#${FIELD_IDS.domainLookupInterval}`).val(), 1, 60 * 24, 'Интервал проверки доменов');
    const domainsTimeToLive = parseNumberInRange($(`#${FIELD_IDS.domainsTimeToLive}`).val(), 1, 24 * 7, 'Время жизни кешированных доменов');

    const httpPortValue = parseInt($(`#${FIELD_IDS.httpPort}`).val(), 10);
    if (Number.isNaN(httpPortValue) || httpPortValue < 1 || httpPortValue > 65535) {
        throw new Error('HTTP порт должен быть от 1 до 65535.');
    }

    const subscriptions = collectSubscriptions();
    const customResources = buildNetworkResourceBundle({
        asnSelector: FIELD_IDS.customASN,
        subnetsSelector: FIELD_IDS.customSubnets,
        domainsSelector: FIELD_IDS.customDomains
    });
    const filteredResources = buildNetworkResourceBundle({
        asnSelector: FIELD_IDS.filteredASN,
        subnetsSelector: FIELD_IDS.filteredSubnets,
        domainsSelector: FIELD_IDS.filteredDomains
    });

    return {
        ...currentConfig,
        updateSubscriptionsInterval,
        cachingAS: $(`#${FIELD_IDS.cachingAS}`).prop('checked'),
        updateASInterval,
        host: $(`#${FIELD_IDS.host}`).val().trim(),
        cacheDirectory: $(`#${FIELD_IDS.cacheDirectory}`).val().trim(),
        httpPort: httpPortValue,
        mergeSubnets: $(`#${FIELD_IDS.mergeSubnets}`).prop('checked'),
        displayDebuggingInfo: $(`#${FIELD_IDS.displayDebuggingInfo}`).prop('checked'),
        mergeSubnetsWithUsage,
        cachingDomains: $(`#${FIELD_IDS.cachingDomains}`).prop('checked'),
        domainResolvers: parseTextAreaLines($(`#${FIELD_IDS.domainResolvers}`)),
        domainLookupInterval,
        domainsTimeToLive,
        subscriptions,
        customResources,
        filteredResources
    };
}

async function handleSave() {
    const $button = $(`#${FIELD_IDS.saveButton}`);

    let newConfig;
    try {
        newConfig = collectSettingsFromForm();
    } catch (error) {
        updateStatus(error.message || 'Ошибка подготовки настроек.', 'error');
        return;
    }

    await runAction($button, 'Применение...', async () => {
        await JSONRPC.System.setConfig(newConfig);
        currentConfig = newConfig;
    }, {
        success: 'Настройки успешно сохранены.',
        error: 'Ошибка при сохранении настроек.',
        log: 'Ошибка сохранения настроек'
    });
}

async function handleChangePassword() {
    const newPassword = prompt('Введите новый пароль администратора:');
    if (newPassword === null) {
        return;
    }
    if (!newPassword.trim()) {
        updateStatus('Пароль не может быть пустым.', 'error');
        return;
    }

    const $button = $(`#${FIELD_IDS.changePasswordButton}`);
    await runAction($button, 'Сохранение...', async () => {
        await JSONRPC.Auth.changePassword(newPassword.trim());
    }, {
        success: 'Пароль успешно изменён.',
        error: 'Ошибка при смене пароля.',
        log: 'Ошибка смены пароля'
    });
}

function attachEventHandlers() {
    $(`#${FIELD_IDS.saveButton}`).off('click').on('click', handleSave);
    $(`#${FIELD_IDS.addSubscriptionButton}`).off('click').on('click', () => addSubscriptionRow());
    $(`#${FIELD_IDS.subscriptionsList}`).off('click', `.${CLASS_NAMES.subscriptionRemove}`).on('click', `.${CLASS_NAMES.subscriptionRemove}`, function (event) {
        event.preventDefault();
        $(this).closest(`.${CLASS_NAMES.subscriptionEntry}`).remove();
    });
    $(`#${FIELD_IDS.changePasswordButton}`).off('click').on('click', handleChangePassword);
    $(`#${FIELD_IDS.domainLookupInterval}`).off('input').on('input', function () {
        $('#domain-lookup-value').text($(this).val());
    });
    $(`#${FIELD_IDS.domainsTimeToLive}`).off('input').on('input', function () {
        $('#domains-ttl-value').text($(this).val());
    });
}

function detachEventHandlers() {
    $(`#${FIELD_IDS.saveButton}`).off('click');
    $(`#${FIELD_IDS.addSubscriptionButton}`).off('click');
    $(`#${FIELD_IDS.subscriptionsList}`).off('click', `.${CLASS_NAMES.subscriptionRemove}`);
    $(`#${FIELD_IDS.changePasswordButton}`).off('click');
    $(`#${FIELD_IDS.domainLookupInterval}`).off('input');
    $(`#${FIELD_IDS.domainsTimeToLive}`).off('input');
}

export const SettingsPage = {
    render: () => `
        <h1 class="page-title">Системные Настройки</h1>
        <div id="${FIELD_IDS.container}">
            <p>Загрузка настроек...</p>
        </div>
    `,
    mount: async () => {
        const success = await loadSettings();
        if (success) {
            renderSettingsForm();
        } else {
            $(`#${FIELD_IDS.container}`).html('<p class="error-message">Не удалось загрузить настройки.</p>');
        }
    },
    unmount: () => {
        detachEventHandlers();
        clearStatus();
        currentConfig = {};
        repositoryTypes = [];
    }
};
