// S.O.L.O. WorkManager v1.0.68 — local automatic backups from program-folder database and restore UI
(function() {
  'use strict';

  var APP_VERSION = '1.0.68';
  var DB_STORES = ['projects','tasks','taskLogs','pspElements','timeEntries','reminders','tags','milestones','todos','deletedArchive','settings'];
  var SETTINGS_KEYS = ['wm_language','wm_theme','wm_fontscale','wm_work_start','wm_work_end'];
  var AUTO_CHECK_KEY = 'wm_backup_last_auto_date';
  var PANEL_ID = 'solo-workmanager-backup-panel';

  function t(de, en) {
    return (localStorage.getItem('wm_language') || 'de') === 'en' ? en : de;
  }

  function log(level, message, data) {
    try {
      if (window._pwLog) window._pwLog(level, message, data || {});
      else console.log('[S.O.L.O. WorkManager Backup]', level, message, data || {});
    } catch(e) {}
  }

  function todayIso() {
    return new Date().toISOString().slice(0, 10);
  }

  function parseJson(value, fallback) {
    try { return JSON.parse(value || ''); } catch(e) { return fallback; }
  }

  function getWorkspaces() {
    return parseJson(localStorage.getItem('wm_workspaces'), []);
  }

  function dbName(workspaceId) {
    return 'workmanager_' + workspaceId;
  }

  function createStores(db) {
    if (!db.objectStoreNames.contains('projects')) {
      var projects = db.createObjectStore('projects', { keyPath: 'id' });
      projects.createIndex('parentId', 'parentId', { unique: false });
      projects.createIndex('status', 'status', { unique: false });
    }
    if (!db.objectStoreNames.contains('tasks')) {
      var tasks = db.createObjectStore('tasks', { keyPath: 'id' });
      tasks.createIndex('projectId', 'projectId', { unique: false });
      tasks.createIndex('dueDate', 'dueDate', { unique: false });
      tasks.createIndex('status', 'status', { unique: false });
      tasks.createIndex('priority', 'priority', { unique: false });
    }
    if (!db.objectStoreNames.contains('taskLogs')) {
      var logs = db.createObjectStore('taskLogs', { keyPath: 'id' });
      logs.createIndex('taskId', 'taskId', { unique: false });
      logs.createIndex('createdAt', 'createdAt', { unique: false });
    }
    if (!db.objectStoreNames.contains('pspElements')) {
      var psp = db.createObjectStore('pspElements', { keyPath: 'id' });
      psp.createIndex('projectId', 'projectId', { unique: false });
      psp.createIndex('code', 'code', { unique: false });
    }
    if (!db.objectStoreNames.contains('timeEntries')) {
      var time = db.createObjectStore('timeEntries', { keyPath: 'id' });
      time.createIndex('pspId', 'pspId', { unique: false });
      time.createIndex('taskId', 'taskId', { unique: false });
      time.createIndex('date', 'date', { unique: false });
    }
    if (!db.objectStoreNames.contains('reminders')) {
      var reminders = db.createObjectStore('reminders', { keyPath: 'id' });
      reminders.createIndex('taskId', 'taskId', { unique: false });
      reminders.createIndex('reminderAt', 'reminderAt', { unique: false });
      reminders.createIndex('fired', 'fired', { unique: false });
    }
    if (!db.objectStoreNames.contains('tags')) db.createObjectStore('tags', { keyPath: 'id' });
    if (!db.objectStoreNames.contains('milestones')) {
      var milestones = db.createObjectStore('milestones', { keyPath: 'id' });
      milestones.createIndex('projectId', 'projectId', { unique: false });
    }
    if (!db.objectStoreNames.contains('todos')) db.createObjectStore('todos', { keyPath: 'id' });
    if (!db.objectStoreNames.contains('deletedArchive')) {
      var archive = db.createObjectStore('deletedArchive', { keyPath: 'id' });
      archive.createIndex('deletedAt', 'deletedAt', { unique: false });
    }
    if (!db.objectStoreNames.contains('settings')) db.createObjectStore('settings', { keyPath: 'key' });
  }

  function openWorkspaceDb(workspaceId) {
    return new Promise(function(resolve, reject) {
      var req = indexedDB.open(dbName(workspaceId), 4);
      req.onerror = function() { reject(req.error || new Error('IndexedDB open failed')); };
      req.onsuccess = function() { resolve(req.result); };
      req.onupgradeneeded = function(event) { createStores(event.target.result); };
    });
  }

  function getAll(db, storeName) {
    return new Promise(function(resolve) {
      if (!db.objectStoreNames.contains(storeName)) { resolve([]); return; }
      var tx = db.transaction(storeName, 'readonly');
      var req = tx.objectStore(storeName).getAll();
      req.onsuccess = function() { resolve(req.result || []); };
      req.onerror = function() { resolve([]); };
    });
  }

  async function exportWorkspaceData(workspaceId) {
    var db = await openWorkspaceDb(workspaceId);
    var data = {};
    try {
      for (var i = 0; i < DB_STORES.length; i++) {
        data[DB_STORES[i]] = await getAll(db, DB_STORES[i]);
      }
    } finally {
      db.close();
    }
    return data;
  }

  async function createSnapshot() {
    var workspaces = getWorkspaces();
    var localSettings = {};
    SETTINGS_KEYS.forEach(function(key) {
      var value = localStorage.getItem(key);
      if (value !== null) localSettings[key] = value;
    });
    var workspaceData = {};
    for (var i = 0; i < workspaces.length; i++) {
      workspaceData[workspaces[i].id] = await exportWorkspaceData(workspaces[i].id);
    }
    return {
      schema: 'SoloWorkManagerFullSnapshot',
      snapshotVersion: 1,
      appVersion: APP_VERSION,
      createdAt: new Date().toISOString(),
      origin: window.location.origin,
      workspaces: workspaces,
      activeWorkspaceId: localStorage.getItem('wm_active_workspace') || (workspaces[0] && workspaces[0].id) || null,
      localSettings: localSettings,
      workspaceData: workspaceData
    };
  }

  async function createBackup(kind) {
    // v1.0.68: Backups are created server-side from the authoritative
    // program-folder database file. The browser no longer exports legacy IndexedDB.
    var response = await fetch('/backup/create', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      cache: 'no-store',
      body: JSON.stringify({ kind: kind || 'manual' })
    });
    var result = await response.json().catch(function(){ return { ok:false, error:'Invalid JSON response' }; });
    if (!response.ok || !result.ok) throw new Error(result.error || 'Backup failed');
    if ((kind || 'manual') === 'auto') localStorage.setItem(AUTO_CHECK_KEY, todayIso());
    return result;
  }

  async function listBackups() {
    var response = await fetch('/backup/list', { cache: 'no-store' });
    var result = await response.json();
    if (!response.ok || !result.ok) throw new Error(result.error || 'Backup list failed');
    return result;
  }

  async function readBackup(fileName) {
    var response = await fetch('/backup/read?file=' + encodeURIComponent(fileName), { cache: 'no-store' });
    var result = await response.json();
    if (!response.ok || result.ok === false) throw new Error(result.error || 'Backup read failed');
    return result.payload || result;
  }

  function clearStore(db, storeName) {
    return new Promise(function(resolve, reject) {
      if (!db.objectStoreNames.contains(storeName)) { resolve(); return; }
      var tx = db.transaction(storeName, 'readwrite');
      var req = tx.objectStore(storeName).clear();
      req.onsuccess = function() { resolve(); };
      req.onerror = function() { reject(req.error || new Error('Clear failed: ' + storeName)); };
    });
  }

  function putItems(db, storeName, items) {
    return new Promise(function(resolve, reject) {
      if (!db.objectStoreNames.contains(storeName) || !items || !items.length) { resolve(); return; }
      var tx = db.transaction(storeName, 'readwrite');
      var store = tx.objectStore(storeName);
      items.forEach(function(item) { store.put(item); });
      tx.oncomplete = function() { resolve(); };
      tx.onerror = function() { reject(tx.error || new Error('Restore failed: ' + storeName)); };
    });
  }

  async function restoreSnapshot(snapshot) {
    if (!snapshot) throw new Error('Leere Sicherung');
    var payload = snapshot.payload || snapshot.snapshot || snapshot;
    if (payload && payload.workspaceData && !payload.workspacesData) payload.workspacesData = payload.workspaceData;
    var res = await fetch('/api/localdb/import-snapshot', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ snapshot: payload }) });
    var json = await res.json().catch(function(){ return { ok:false, error:'Invalid JSON response' }; });
    if (!res.ok || json.ok === false) throw new Error(json.error || 'Restore failed');
    if (payload.localSettings) Object.keys(payload.localSettings).forEach(function(key) { localStorage.setItem(key, payload.localSettings[key]); });
    if (Array.isArray(payload.workspaces)) localStorage.setItem('wm_workspaces', JSON.stringify(payload.workspaces));
    if (payload.activeWorkspaceId) localStorage.setItem('wm_active_workspace', payload.activeWorkspaceId);
  }

  function formatSize(bytes) {
    if (!bytes) return '0 KB';
    if (bytes < 1024 * 1024) return Math.round(bytes / 1024) + ' KB';
    return (bytes / 1024 / 1024).toFixed(1) + ' MB';
  }

  function formatFileDate(name, modifiedAt) {
    var m = name.match(/_(\d{4}-\d{2}-\d{2})T(\d{2})-(\d{2})-(\d{2})Z\.json$/);
    if (m) return m[1] + ' ' + m[2] + ':' + m[3] + ':' + m[4] + ' UTC';
    return modifiedAt || name;
  }

  function backupKindLabel(name) {
    if (name.indexOf('solo_workmanager_auto_backup_') === 0) return t('Automatisch', 'Automatic');
    if (name.indexOf('solo_workmanager_pre_restore_backup_') === 0) return t('Vor Wiederherstellung', 'Pre-restore');
    return t('Manuell', 'Manual');
  }

  function isSettingsVisible() {
    var active = document.querySelector('.nav-item.active');
    return !!(active && /Einstellungen|Settings/.test(active.textContent || ''));
  }

  async function refreshPanel(panel) {
    var status = panel.querySelector('[data-backup-status]');
    var list = panel.querySelector('[data-backup-list]');
    try {
      var result = await listBackups();
      var files = result.files || [];
      var latest = files[0];
      status.textContent = latest
        ? t('Letztes Backup: ', 'Latest backup: ') + formatFileDate(latest.name, latest.modifiedAt) + ' · ' + t('Anzahl: ', 'Count: ') + files.length
        : t('Noch kein Backup vorhanden.', 'No backup available yet.');
      list.innerHTML = '';
      if (!files.length) {
        var empty = document.createElement('div');
        empty.className = 'text-muted text-sm';
        empty.textContent = t('Keine Sicherungen im lokalen backups-Ordner gefunden.', 'No backups found in the local backups folder.');
        list.appendChild(empty);
        return;
      }
      files.slice(0, 30).forEach(function(file) {
        var row = document.createElement('div');
        row.style.cssText = 'display:flex;align-items:center;justify-content:space-between;gap:10px;padding:8px 0;border-top:1px solid var(--border);';
        var meta = document.createElement('div');
        meta.style.cssText = 'min-width:0;';
        meta.innerHTML = '<div style="font-weight:700;color:var(--text-primary);font-size:13px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;">' + backupKindLabel(file.name) + ' · ' + formatFileDate(file.name, file.modifiedAt) + '</div>' +
          '<div class="text-muted" style="font-size:11px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;">' + file.name + ' · ' + formatSize(file.size) + '</div>';
        var btn = document.createElement('button');
        btn.className = 'btn btn-ghost btn-sm';
        btn.textContent = t('Wiederherstellen', 'Restore');
        btn.onclick = async function() {
          var msg = t('Aktuelle S.O.L.O. WorkManager-Daten werden durch dieses Backup ersetzt. Vorher wird automatisch eine Sicherheitskopie erstellt. Fortfahren?', 'Current S.O.L.O. WorkManager data will be replaced by this backup. A safety backup will be created first. Continue?');
          if (!confirm(msg)) return;
          btn.disabled = true;
          btn.textContent = t('Lade...', 'Loading...');
          try {
            await createBackup('pre_restore');
            var snapshot = await readBackup(file.name);
            await restoreSnapshot(snapshot);
            alert(t('Backup wurde wiederhergestellt. S.O.L.O. WorkManager wird neu geladen.', 'Backup restored. S.O.L.O. WorkManager will reload.'));
            window.location.reload();
          } catch (e) {
            btn.disabled = false;
            btn.textContent = t('Wiederherstellen', 'Restore');
            alert(t('Wiederherstellung fehlgeschlagen: ', 'Restore failed: ') + e.message);
            log('ERROR', 'Restore failed', { error: e.message, file: file.name });
          }
        };
        row.appendChild(meta);
        row.appendChild(btn);
        list.appendChild(row);
      });
    } catch(e) {
      status.textContent = t('Backup-Status konnte nicht geladen werden: ', 'Backup status could not be loaded: ') + e.message;
      log('WARN', 'Backup status failed', { error: e.message });
    }
  }

  function createPanel() {
    var panel = document.createElement('section');
    panel.id = PANEL_ID;
    panel.className = 'card solo-workmanager-backup-side-panel';
    panel.style.cssText = '';
    panel.innerHTML = '' +
      '<div style="display:flex;justify-content:space-between;align-items:flex-start;gap:14px;flex-wrap:wrap;">' +
        '<div>' +
          '<h2 style="margin:0 0 6px;font-size:18px;color:var(--text-primary);">' + t('Datensicherung', 'Data backup') + '</h2>' +
          '<p class="text-muted" style="margin:0;font-size:13px;line-height:1.45;">' + t('S.O.L.O. WorkManager erstellt einmal täglich automatisch eine lokale JSON-Sicherung im Ordner backups der App. Die Sicherung liegt außerhalb des Browserprofils.', 'S.O.L.O. WorkManager automatically creates one local JSON backup per day in the app backups folder. The backup is stored outside the browser profile.') + '</p>' +
        '</div>' +
        '<button class="btn btn-primary btn-sm" data-backup-create>' + t('Jetzt Backup erstellen', 'Create backup now') + '</button>' +
      '</div>' +
      '<div data-backup-status class="text-muted" style="margin-top:12px;font-size:13px;">' + t('Backup-Status wird geladen...', 'Loading backup status...') + '</div>' +
      '<div style="margin-top:14px;font-weight:700;color:var(--text-primary);font-size:13px;">' + t('Vorhandene Backups', 'Available backups') + '</div>' +
      '<div data-backup-list class="solo-workmanager-backup-list"></div>' +
      '<div class="text-muted" style="margin-top:10px;font-size:11px;line-height:1.4;">' + t('Automatisch werden die letzten 30 Tages-Backups behalten. Vor jeder Wiederherstellung wird zusätzlich ein Pre-Restore-Backup erstellt.', 'The latest 30 automatic daily backups are kept. A pre-restore backup is also created before each restore.') + '</div>';

    panel.querySelector('[data-backup-create]').onclick = async function() {
      var btn = this;
      btn.disabled = true;
      btn.textContent = t('Erstelle...', 'Creating...');
      try {
        var result = await createBackup('manual');
        alert(t('Backup erstellt: ', 'Backup created: ') + result.file.name);
        await refreshPanel(panel);
      } catch(e) {
        alert(t('Backup fehlgeschlagen: ', 'Backup failed: ') + e.message);
        log('ERROR', 'Manual backup failed', { error: e.message });
      } finally {
        btn.disabled = false;
        btn.textContent = t('Jetzt Backup erstellen', 'Create backup now');
      }
    };
    refreshPanel(panel);
    return panel;
  }

  function mountPanelIfNeeded() {
    // v1.0.68: Datensicherung wird in einem eigenen System-Tab angezeigt, nicht mehr in den Einstellungen.
    var existing = document.getElementById(PANEL_ID);
    if (existing) existing.remove();
    return;
    if (!isSettingsVisible()) { if (existing) existing.remove(); return; }
    if (existing) return;
    var main = document.querySelector('.main-content');
    if (!main) return;
    var container = main.firstElementChild || main;
    container.appendChild(createPanel());
  }

  async function runDailyBackupCheck() {
    try {
      var result = await listBackups().catch(function() { return { files: [] }; });
      var hasTodayAuto = (result.files || []).some(function(file) {
        return file.name.indexOf('solo_workmanager_auto_backup_' + todayIso()) === 0;
      });

      // Important for ZIP-based updates:
      // wm_backup_last_auto_date is stored in the browser profile, while the
      // physical backups folder belongs to the currently extracted app folder.
      // Therefore the browser flag alone must not suppress today's backup when
      // a newly extracted version has an empty backups folder.
      if (hasTodayAuto) {
        localStorage.setItem(AUTO_CHECK_KEY, todayIso());
        return;
      }

      await createBackup('auto');
      localStorage.setItem(AUTO_CHECK_KEY, todayIso());
      log('INFO', 'Automatic daily backup created', { date: todayIso(), reason: 'no auto backup found in current backups folder' });
      mountPanelIfNeeded();
      var panel = document.getElementById(PANEL_ID);
      if (panel) refreshPanel(panel);
    } catch(e) {
      log('WARN', 'Automatic backup failed', { error: e.message });
    }
  }

  window.SoloWorkManagerBackup = { createBackup: createBackup, listBackups: listBackups, readBackup: readBackup, restoreSnapshot: restoreSnapshot, formatSize: formatSize, formatFileDate: formatFileDate, backupKindLabel: backupKindLabel };

  function init() {
    setTimeout(runDailyBackupCheck, 2500);
    setInterval(runDailyBackupCheck, 60 * 60 * 1000);
    var obs = new MutationObserver(function() { mountPanelIfNeeded(); });
    obs.observe(document.body, { childList: true, subtree: true });
    setInterval(mountPanelIfNeeded, 1000);
    mountPanelIfNeeded();
  }

  if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init);
  else init();
})();
