import { apiAction, toast } from './api.js';
const state = {
setup: null,
loading: false,
};
let form;
let tablesInput;
let tablesPreview;
let modeInputs;
let importInputs;
let directFields;
let statusLabel;
let loadBtn;
let bridgeFields;
export function initBridgeSetupPage() {
form = document.getElementById('bridgeSetupForm');
if (!form) return;
tablesInput = form.elements.tables;
tablesPreview = document.getElementById('selectedTables');
bridgeFields = document.getElementById('bridgeFields');
directFields = document.getElementById('directFields');
statusLabel = document.getElementById('setupStatus');
loadBtn = document.getElementById('btn-load-remote');
modeInputs = Array.from(form.querySelectorAll('input[name="db_mode"]'));
importInputs = Array.from(form.querySelectorAll('input[name="bridge_import"]'));
form.addEventListener('submit', submitBridgeSetup);
tablesInput?.addEventListener('input', () => updateTablesPreview(parseTablesInput()));
loadBtn?.addEventListener('click', loadTablesFromBridge);
modeInputs.forEach(input => {
input.addEventListener('change', () => applyModeVisibility(input.value));
});
loadBridgeSetup();
}
function defaultSetup() {
return {
tables: [],
mode: 'bridge',
import_type: 'schema',
direct: {
host: '',
port: 3306,
database: '',
user: '',
password: '',
charset: 'utf8mb4',
},
};
}
async function loadBridgeSetup() {
state.loading = true;
try {
const res = await apiAction('account.bridge.setup.get', { method: 'GET' });
if (!res?.ok) throw new Error(res?.error || 'Bridge-Setup konnte nicht geladen werden');
fillForm(res.setup || state.setup || defaultSetup());
updateStatus('Daten geladen.');
} catch (err) {
console.error(err);
toast(err.message || 'Bridge-Setup konnte nicht geladen werden', false);
} finally {
state.loading = false;
}
}
function fillForm(setup) {
const data = normalizeSetupInput(setup);
state.setup = data;
if (tablesInput) {
tablesInput.value = data.tables.join(', ');
updateTablesPreview(data.tables);
}
const activeMode = (data.mode || 'direct').toLowerCase();
modeInputs.forEach(input => {
input.checked = input.value === activeMode;
});
applyModeVisibility(activeMode);
if (importInputs.length) {
const importType = (data.import_type || 'schema').toLowerCase();
importInputs.forEach(input => {
input.checked = input.value === importType;
});
}
if (directFields) {
const directMap = {
direct_host: data.direct.host || '',
direct_port: String(data.direct.port || 3306),
direct_database: data.direct.database || '',
direct_charset: data.direct.charset || 'utf8mb4',
direct_user: data.direct.user || '',
direct_password: data.direct.password || '',
};
Object.entries(directMap).forEach(([name, value]) => {
const input = directFields.querySelector(`[name="${name}"]`);
if (input) input.value = value;
});
}
}
function applyModeVisibility(mode) {
const showDirect = mode === 'direct';
directFields?.classList[showDirect ? 'remove' : 'add']('hidden');
bridgeFields?.classList[showDirect ? 'add' : 'remove']('hidden');
}
function parseTablesInput() {
if (!tablesInput) return [];
return tablesInput.value
.split(/[\s,]+/)
.map(part => part.trim())
.filter(Boolean)
.filter((value, index, arr) => arr.indexOf(value) === index);
}
function updateTablesPreview(list) {
if (!tablesPreview) return;
if (!list.length) {
tablesPreview.innerHTML = 'Noch keine Tabellen angegeben.';
return;
}
tablesPreview.innerHTML = list.map(name => `${escapeHtml(name)}`).join('');
}
async function submitBridgeSetup(ev) {
ev.preventDefault();
if (!form) return;
const mode = form.querySelector('input[name="db_mode"]:checked')?.value || 'direct';
const importType = form.querySelector('input[name="bridge_import"]:checked')?.value || 'schema';
const payload = {
tables: parseTablesInput(),
mode,
import_type: importType,
direct_host: form.direct_host?.value.trim() || '',
direct_port: Number(form.direct_port?.value || 0) || 3306,
direct_database: form.direct_database?.value.trim() || '',
direct_charset: form.direct_charset?.value.trim() || 'utf8mb4',
direct_user: form.direct_user?.value.trim() || '',
direct_password: form.direct_password?.value || '',
};
try {
const res = await apiAction('account.bridge.setup.save', { method: 'POST', data: payload });
if (!res?.ok) throw new Error(res?.error || 'Bridge-Setup konnte nicht gespeichert werden');
fillForm(res.setup || payload);
updateStatus('Bridge-Setup gespeichert.');
toast('Bridge-Setup gespeichert', true);
} catch (err) {
console.error(err);
toast(err.message || 'Bridge-Setup konnte nicht gespeichert werden', false);
}
}
async function loadTablesFromBridge(ev) {
ev?.preventDefault();
if (!loadBtn) return;
loadBtn.disabled = true;
try {
const mode = form?.querySelector('input[name="db_mode"]:checked')?.value || 'bridge';
const importType = form?.querySelector('input[name="bridge_import"]:checked')?.value || 'schema';
const payload = {
mode,
import_type: importType,
direct_host: form?.direct_host?.value.trim() || '',
direct_port: Number(form?.direct_port?.value || 0) || 3306,
direct_database: form?.direct_database?.value.trim() || '',
direct_charset: form?.direct_charset?.value.trim() || 'utf8mb4',
direct_user: form?.direct_user?.value.trim() || '',
direct_password: form?.direct_password?.value || '',
};
const res = await apiAction('account.bridge.test', { method: 'POST', data: payload });
if (!res?.ok) throw new Error(res?.error || 'Bridge konnte nicht abgefragt werden');
const fetchedTables = normalizeTableNames(res.tables);
const allowedTables = normalizeTableNames(res.setup_hint?.tables ?? fetchedTables);
const merged = {
...(state.setup || {}),
tables: allowedTables,
};
fillForm(merged);
updateStatus(`Tabellen geladen (${fetchedTables.length}).`);
toast('Tabellen erfolgreich geladen', true);
} catch (err) {
console.error(err);
toast(err.message || 'Bridge konnte nicht geprüft werden', false);
} finally {
loadBtn.disabled = false;
}
}
function normalizeTableNames(list) {
if (!Array.isArray(list)) return [];
const result = [];
const seen = new Set();
for (const entry of list) {
let name = '';
if (typeof entry === 'string') {
name = entry;
} else if (entry && typeof entry === 'object') {
name = entry.name || entry.table || entry.label || '';
}
if (typeof name === 'string') {
const trimmed = name.trim();
if (trimmed && !seen.has(trimmed)) {
seen.add(trimmed);
result.push(trimmed);
}
}
}
return result;
}
function updateStatus(msg) {
if (!statusLabel) return;
const time = new Date().toLocaleTimeString('de-DE', { hour: '2-digit', minute: '2-digit', second: '2-digit' });
statusLabel.textContent = `${msg} (${time})`;
}
function escapeHtml(str) {
return String(str || '')
.replace(/&/g, '&')
.replace(//g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
function normalizeSetupInput(input) {
const base = defaultSetup();
if (!input || typeof input !== 'object') return base;
const mode = (input.mode || base.mode).toLowerCase();
const validMode = mode === 'direct' ? 'direct' : 'bridge';
const importType = (input.import_type || base.import_type).toLowerCase();
const validImport = importType === 'settings' ? 'settings' : 'schema';
const tables = normalizeTableNames(input.tables || base.tables);
const direct = { ...base.direct, ...(input.direct || {}) };
direct.port = Number(direct.port || 3306) || 3306;
direct.charset = direct.charset || 'utf8mb4';
return { tables, mode: validMode, import_type: validImport, direct };
}