import {
  app,
  BrowserWindow,
  Tray,
  Menu,
  nativeImage,
  ipcMain,
  Notification,
  dialog,
} from 'electron';
import path from 'path';
import https from 'https';
import fs from 'fs';
import { autoUpdater } from 'electron-updater';

// ─── NOM DE L'APPLICATION ─────────────────────────────────────────────────────
app.setName('Obsidienne');
// Windows utilise l'AppUserModelId pour le nom affiché dans les notifications
if (process.platform === 'win32') {
  app.setAppUserModelId('Obsidienne');
}

// ─── MODE DEV / E2E ────────────────────────────��─────────────────────────────
// En E2E (Playwright), utiliser un dossier userData dédié
if (process.env.ELECTRON_USER_DATA_DIR) {
  app.setPath('userData', process.env.ELECTRON_USER_DATA_DIR);
} else if (!app.isPackaged) {
  // En dev (npm start), les données sont isolées de l'app installée
  app.setPath('userData', path.join(app.getPath('appData'), 'Obsidienne-DEV'));
}

// ─── MIGRATION DONNÉES (ancien nom → Obsidienne) ────────────────────────────
// Les utilisateurs de "Minuteur Dragodinde" conservent leurs données après le renommage
if (app.isPackaged) {
  const oldDataFile = path.join(app.getPath('appData'), 'Minuteur Dragodinde', 'dd-timer-data.json');
  const newDataFile = path.join(app.getPath('userData'), 'dd-timer-data.json');
  if (!fs.existsSync(newDataFile) && fs.existsSync(oldDataFile)) {
    try {
      fs.mkdirSync(path.dirname(newDataFile), { recursive: true });
      fs.copyFileSync(oldDataFile, newDataFile);
      console.log('Migration données: Minuteur Dragodinde → Obsidienne OK');
    } catch (e: unknown) {
      console.error('Migration données échouée:', (e as Error).message);
    }
  }
}

// ─── CONFIG GITEA ─────────────────────────────────────────────────────────────
const GITEA_HOST = 'gitea.mickael-pol.fr';   // ton instance Gitea
const GITEA_USER = 'mickael';                 // ton user Gitea
const GITEA_REPO = 'dd-timer';               // ton repo
const CURRENT_VERSION: string = app.getVersion();      // lu depuis package.json

interface UpdateInfo {
  version: string;
}

let mainWindow: BrowserWindow | null = null;
let tray: Tray | null = null;
let isQuitting = false;
let updateInfo: UpdateInfo | null = null;
let updateCheckInProgress = false;
let updateDownloaded = false;

// ─── ICÔNE ───────────────────────────────────────────────────────────────────
function getAppIcon(): Electron.NativeImage {
  const iconPath = app.isPackaged
    ? path.join(process.resourcesPath, 'icon.ico')
    : path.join(__dirname, '../icon.ico');
  if (fs.existsSync(iconPath)) return nativeImage.createFromPath(iconPath);
  return nativeImage.createEmpty();
}

// ─── FENÊTRE ─────────────────────────────────────────────────────────────────
function createWindow(): void {
  mainWindow = new BrowserWindow({
    width: 1280, height: 900, minWidth: 960, minHeight: 650,
    title: 'Obsidienne - Dofus 3',
    icon: getAppIcon(),
    backgroundColor: '#0b0b14',
    webPreferences: {
      nodeIntegration:      false,
      contextIsolation:     true,
      sandbox:              true,
      backgroundThrottling: false,
      preload: path.join(__dirname, 'preload.js'),
    },
  });
  // Dev: Vite dev server; Prod: built renderer in dist-vite/
  if (process.env['VITE_DEV_SERVER_URL']) {
    mainWindow.loadURL(process.env['VITE_DEV_SERVER_URL']);
  } else {
    mainWindow.loadFile(path.join(__dirname, '../dist-vite/index.html'));
  }

  mainWindow.on('close', (e) => {
    if (!isQuitting) {
      e.preventDefault();
      const choice = dialog.showMessageBoxSync(mainWindow!, {
        type: 'question',
        buttons: ['Minimiser', 'Quitter'],
        defaultId: 0,
        cancelId: 0,
        title: 'Obsidienne',
        message: 'Que souhaites-tu faire ?',
        detail: 'Minimiser garde l\'app en arriere-plan.\nLes alarmes continueront de sonner.',
      });
      if (choice === 1) {
        if (tray) { tray.destroy(); tray = null; }
        process.exit(0);
      } else {
        mainWindow!.hide();
      }
    }
  });

  // Zoom clavier : Ctrl+Plus, Ctrl+Minus, Ctrl+0
  mainWindow.webContents.on('before-input-event', (_e, input) => {
    if (!input.control || input.type !== 'keyDown') return;
    const wc = mainWindow!.webContents;
    if (input.key === '+' || input.key === '=') {
      wc.setZoomLevel(wc.getZoomLevel() + 0.5);
    } else if (input.key === '-') {
      wc.setZoomLevel(wc.getZoomLevel() - 0.5);
    } else if (input.key === '0') {
      wc.setZoomLevel(0);
    }
  });

  // Envoyer les infos de version au renderer une fois chargé
  mainWindow.webContents.on('did-finish-load', () => {
    mainWindow!.webContents.send('app-version', CURRENT_VERSION);
    if (updateInfo) {
      mainWindow!.webContents.send('update-available', updateInfo);
    }
    // Badge DEV visible dans l'interface (via IPC, pas executeJavaScript)
    if (!app.isPackaged) {
      mainWindow!.webContents.send('dev-mode');
    }
  });
}

// ─── TRAY ─────────────────────────────────────────────────────────────────────
function createTray(): void {
  tray = new Tray(getAppIcon());
  tray.setToolTip(`Obsidienne v${CURRENT_VERSION}`);
  rebuildTrayMenu();
  tray.on('double-click', () => { mainWindow!.show(); mainWindow!.focus(); });
}

function rebuildTrayMenu(): void {
  if (!tray) return;
  const items: Electron.MenuItemConstructorOptions[] = [
    { label: `Obsidienne v${CURRENT_VERSION}`, enabled: false },
    { type: 'separator' },
    { label: 'Ouvrir', click: () => { mainWindow!.show(); mainWindow!.focus(); } },
  ];
  if (updateInfo) {
    items.push({ type: 'separator' });
    if (updateDownloaded) {
      items.push({
        label: `⬆ Installer v${updateInfo.version} maintenant`,
        click: () => autoUpdater.quitAndInstall(true, true),
      });
    } else {
      items.push({
        label: `⏳ Téléchargement v${updateInfo.version}...`,
        enabled: false,
      });
    }
  }
  items.push({ type: 'separator' });
  items.push({ label: 'Quitter', click: () => { isQuitting = true; app.quit(); } });
  tray.setContextMenu(Menu.buildFromTemplate(items));
}

// ─── NOTIFICATIONS ────────────────────────────────────────────────────────────
function fireNotification(title: string, body: string): void {
  if (!Notification.isSupported()) return;
  const n = new Notification({ title, body, timeoutType: 'never' });
  n.on('click', () => { mainWindow!.show(); mainWindow!.focus(); });
  n.show();
}

// ─── IPC ──────────────────────────────────────────────────────────────────────
ipcMain.on('trigger-alarm', (_event, { enclosName }: { enclosName: string }) => {
  fireNotification('Dragodindes pretes !', enclosName + ' - Toutes les cibles ont ete atteintes !');
  if (mainWindow && !mainWindow.isDestroyed()) {
    mainWindow.webContents.send('play-alarm-sound');
  }
});

ipcMain.on('show-notification', (_event, { title, body }: { title: string; body: string }) => {
  fireNotification(title, body);
});

// Dialogue de confirmation natif (remplace confirm() du renderer qui casse les inputs)
ipcMain.handle('show-confirm', (_event, { title, message, detail }: { title: string; message: string; detail: string }) => {
  const choice = dialog.showMessageBoxSync(mainWindow!, {
    type: 'question',
    buttons: ['Annuler', 'Confirmer'],
    defaultId: 0,
    cancelId: 0,
    title: title || 'Confirmation',
    message: message || '',
    detail: detail || '',
  });
  return choice === 1;
});

// ─── SAUVEGARDE FICHIER (persistante entre mises à jour) ─────────────────
const dataFile: string = path.join(app.getPath('userData'), 'dd-timer-data.json');

ipcMain.handle('load-data', () => {
  try {
    if (fs.existsSync(dataFile)) return fs.readFileSync(dataFile, 'utf-8');
  } catch (e: unknown) { console.error('load-data error:', (e as Error).message); }
  return null;
});

ipcMain.on('save-data', (_event, json: string) => {
  try {
    fs.writeFileSync(dataFile, json, 'utf-8');
  } catch (e: unknown) { console.error('save-data error:', (e as Error).message); }
});

// ─── NTFY (notifications mobiles) ─────────────────────────────────────────
ipcMain.on('send-ntfy', (_event, { url, title, message }: { url: string; title: string; message: string }) => {
  if (!url) return;
  try {
    const parsed = new URL(url.trim());
    if (parsed.protocol !== 'https:') {
      console.warn('ntfy: HTTPS requis, requête ignorée');
      return;
    }
    // API JSON ntfy : supporte nativement l'UTF-8 (accents, emojis)
    const topic = parsed.pathname.replace(/^\//, '');
    const jsonBody = JSON.stringify({
      topic,
      title,
      message,
      priority: 4,
      tags: ['dragon'],
    });
    const options: https.RequestOptions = {
      hostname: parsed.hostname,
      port:     parsed.port || (parsed.protocol === 'https:' ? 443 : 80),
      path:     '/',
      method:   'POST',
      headers: {
        'Content-Type':   'application/json; charset=utf-8',
        'Content-Length':  Buffer.byteLength(jsonBody, 'utf-8'),
      },
    };
    const req = https.request(options, (res) => {
      res.on('data', () => {}); // drain
      res.on('end', () => {});
    });
    req.on('error', (e: Error) => console.warn('ntfy send error:', e.message));
    req.write(jsonBody, 'utf-8');
    req.end();
  } catch (e: unknown) {
    console.warn('ntfy error:', (e as Error).message);
  }
});

ipcMain.on('focus-window', () => { mainWindow!.show(); mainWindow!.focus(); });

// Renderer demande à installer la mise à jour
ipcMain.on('install-update', () => {
  if (updateDownloaded) {
    autoUpdater.quitAndInstall(true, true);
  }
});

// Renderer demande la version
ipcMain.handle('get-version', () => CURRENT_VERSION);

// ─── EXPORT / IMPORT FICHIER ────────────────────────────────────────────────
ipcMain.handle('export-file', async (_event, { data, defaultName }: { data: string; defaultName: string }) => {
  if (!mainWindow) return false;
  const result = await dialog.showSaveDialog(mainWindow, {
    title: 'Exporter les plans',
    defaultPath: path.join(app.getPath('documents'), defaultName),
    filters: [{ name: 'JSON', extensions: ['json'] }],
  });
  if (result.canceled || !result.filePath) return false;
  try {
    fs.writeFileSync(result.filePath, data, 'utf-8');
    return true;
  } catch (e: unknown) {
    console.error('export-file error:', (e as Error).message);
    return false;
  }
});

ipcMain.handle('import-file', async () => {
  if (!mainWindow) return null;
  const result = await dialog.showOpenDialog(mainWindow, {
    title: 'Importer des plans',
    defaultPath: app.getPath('documents'),
    filters: [{ name: 'JSON', extensions: ['json'] }],
    properties: ['openFile'],
  });
  if (result.canceled || result.filePaths.length === 0) return null;
  try {
    return fs.readFileSync(result.filePaths[0], 'utf-8');
  } catch (e: unknown) {
    console.error('import-file error:', (e as Error).message);
    return null;
  }
});

// ─── COMPARAISON DE VERSIONS ────────────────────────────────────────────────
function compareVersions(a: string, b: string): number {
  const pa = a.replace(/^v/, '').split('.').map(Number);
  const pb = b.replace(/^v/, '').split('.').map(Number);
  for (let i = 0; i < 3; i++) {
    if ((pb[i] || 0) > (pa[i] || 0)) return 1;
    if ((pb[i] || 0) < (pa[i] || 0)) return -1;
  }
  return 0;
}

// ─── ELECTRON-UPDATER : CONFIGURATION ───────────────────────────────────────
autoUpdater.autoDownload = true;
autoUpdater.autoInstallOnAppQuit = false;

// ─── ELECTRON-UPDATER : EVENTS ──────────────────────────────────────────────
autoUpdater.on('update-available', (info) => {
  updateInfo = { version: info.version };
  if (mainWindow && !mainWindow.isDestroyed()) {
    mainWindow.webContents.send('update-available', updateInfo);
    mainWindow.webContents.send('update-downloading', { version: info.version });
  }
  fireNotification(
    `Mise a jour v${info.version} disponible !`,
    'Téléchargement en cours...'
  );
  rebuildTrayMenu();
});

autoUpdater.on('download-progress', (progress) => {
  if (mainWindow && !mainWindow.isDestroyed()) {
    mainWindow.webContents.send('update-progress', { percent: Math.round(progress.percent) });
  }
});

autoUpdater.on('update-downloaded', () => {
  updateDownloaded = true;
  if (mainWindow && !mainWindow.isDestroyed()) {
    mainWindow.webContents.send('update-ready');
  }
  rebuildTrayMenu();
});

autoUpdater.on('error', (err) => {
  console.error('Update error:', err.message);
  updateCheckInProgress = false;
  if (mainWindow && !mainWindow.isDestroyed()) {
    mainWindow.webContents.send('update-error', { message: err.message });
  }
});

autoUpdater.on('update-not-available', () => {
  console.log('electron-updater: no update found in latest.yml');
  updateCheckInProgress = false;
});

// ─── VÉRIFICATION VIA API GITEA ─────────────────────────────────────────────
function checkForUpdates(silent = false): void {
  if (updateCheckInProgress) return;
  updateCheckInProgress = true;
  const options: https.RequestOptions = {
    hostname: GITEA_HOST,
    port: 443,
    path: `/api/v1/repos/${GITEA_USER}/${GITEA_REPO}/releases?limit=1`,
    method: 'GET',
    headers: {
      'User-Agent': `Obsidienne/${CURRENT_VERSION}`,
      'Accept': 'application/json',
    },
  };

  const req = https.request(options, (res) => {
    let data = '';
    res.on('data', (chunk: string) => { data += chunk; });
    res.on('end', () => {
      try {
        const releases = JSON.parse(data);
        if (!Array.isArray(releases) || releases.length === 0) { updateCheckInProgress = false; return; }
        const release = releases[0];
        const latestVersion = release.tag_name;
        if (!latestVersion || compareVersions(CURRENT_VERSION, latestVersion) <= 0) {
          updateCheckInProgress = false;
          if (!silent && mainWindow && !mainWindow.isDestroyed()) {
            mainWindow.webContents.send('update-not-available');
          }
          return;
        }

        // Pointer electron-updater vers le tag de la release
        const tag = latestVersion.startsWith('v') ? latestVersion : `v${latestVersion}`;
        autoUpdater.setFeedURL({
          provider: 'generic',
          url: `https://${GITEA_HOST}/${GITEA_USER}/${GITEA_REPO}/releases/download/${tag}`,
        });

        // electron-updater prend le relais : lit latest.yml, télécharge, vérifie sha512
        autoUpdater.checkForUpdates();
      } catch (e: unknown) {
        updateCheckInProgress = false;
        console.error('Update check parse error:', (e as Error).message);
      }
    });
  });

  req.on('error', (e: Error) => { updateCheckInProgress = false; console.error('Update check error:', e.message); });
  req.end();
}

// ─── CYCLE DE VIE ────────────────────────────────────────────────────────────
app.whenReady().then(() => {
  createWindow();
  createTray();

  // Vérifier les mises à jour uniquement au démarrage (silencieux)
  setTimeout(() => checkForUpdates(true), 3000);

  app.on('activate', () => {
    if (BrowserWindow.getAllWindows().length === 0) createWindow();
  });
});

app.on('window-all-closed', () => {
  if (process.platform === 'darwin') app.quit();
});

app.on('before-quit', () => { isQuitting = true; });
