/**
 * Electron Main Process — Bradly Desktop App
 *
 * Responsibilities:
 * - Creates the BrowserWindow
 * - Starts the embedded Express server
 * - Manages IPC handlers for native features
 */
import { app, BrowserWindow, ipcMain, dialog } from 'electron';
import path from 'path';
import fs from 'fs';
import net from 'net';

// Signal to server.ts / renderQueue.ts that we're in Electron
process.env.BRADLY_ELECTRON = 'true';

const PREFERRED_PORT = 3000;
let expressPort = PREFERRED_PORT;
let mainWindow: BrowserWindow | null = null;

// ═══ Port Utilities ═══

/** Find an available port, starting from the preferred one */
function getAvailablePort(startPort: number): Promise<number> {
  return new Promise((resolve, reject) => {
    const server = net.createServer();
    server.listen(startPort, '127.0.0.1', () => {
      const port = (server.address() as net.AddressInfo).port;
      server.close(() => resolve(port));
    });
    server.on('error', () => {
      // Port in use, try the next one
      if (startPort < 65535) {
        resolve(getAvailablePort(startPort + 1));
      } else {
        reject(new Error('No available ports found'));
      }
    });
  });
}

// ═══ Path Setup for Electron ═══

function setupPaths() {
  const userDataPath = app.getPath('userData');

  // Uploads and renders persist in the user's app data directory
  const uploadsDir = path.join(userDataPath, 'uploads');
  const rendersDir = path.join(userDataPath, 'renders');

  // Create directories if they don't exist
  for (const dir of [uploadsDir, rendersDir]) {
    if (!fs.existsSync(dir)) {
      fs.mkdirSync(dir, { recursive: true });
    }
  }

  process.env.BRADLY_UPLOADS_DIR = uploadsDir;
  process.env.BRADLY_RENDERS_DIR = rendersDir;

  // In packaged app, set the serve URL to the embedded Express server
  if (app.isPackaged) {
    // BRADLY_SERVE_URL will be set after Express starts
    // (see startExpressServer)
  }

  console.log('📂 User data:', userDataPath);
  console.log('📂 Uploads:', uploadsDir);
  console.log('📂 Renders:', rendersDir);
}

// ═══ Express Server ═══

async function startExpressServer(): Promise<number> {
  // Find an available port
  expressPort = await getAvailablePort(PREFERRED_PORT);

  const { createExpressApp } = await import('../../server');
  const expressApp = await createExpressApp();

  // In production Electron, serve the built renderer files
  if (!process.env.NODE_ENV || process.env.NODE_ENV !== 'development') {
    const { default: express } = await import('express');
    // electron-vite builds renderer to out/renderer/
    const rendererPath = app.isPackaged
      ? path.join(process.resourcesPath, 'renderer')
      : path.join(__dirname, '..', '..', 'out', 'renderer');

    if (fs.existsSync(rendererPath)) {
      expressApp.use(express.static(rendererPath));
      // SPA fallback — serve index.html for all non-API routes
      expressApp.get('*', (_req: any, res: any) => {
        res.sendFile(path.join(rendererPath, 'index.html'));
      });
      console.log('📦 Serving renderer from:', rendererPath);
    } else {
      console.warn('⚠️ Renderer build not found at:', rendererPath);
    }
  }

  return new Promise<number>((resolve, reject) => {
    const server = expressApp.listen(expressPort, '127.0.0.1', () => {
      console.log(`🚀 Express server on http://127.0.0.1:${expressPort}`);
      if (expressPort !== PREFERRED_PORT) {
        console.warn(`⚠️ Port ${PREFERRED_PORT} was in use, using ${expressPort} instead`);
      }
      resolve(expressPort);
    });
    server.on('error', reject);
  });
}

// ═══ Window Management ═══

function createWindow() {
  mainWindow = new BrowserWindow({
    width: 1440,
    height: 900,
    minWidth: 1024,
    minHeight: 600,
    titleBarStyle: 'hiddenInset',
    trafficLightPosition: { x: 15, y: 15 },
    backgroundColor: '#0a0a0a',
    show: false, // Show when ready to prevent visual flash
    webPreferences: {
      preload: path.join(__dirname, '../preload/index.js'),
      contextIsolation: true,
      nodeIntegration: false,
      sandbox: false, // Required for preload to access Node APIs
    },
  });

  // Show window when content is ready
  mainWindow.once('ready-to-show', () => {
    mainWindow?.show();
  });

  // Load the app
  if (process.env.NODE_ENV === 'development') {
    // In dev, electron-vite serves the renderer on a dev server URL
    const rendererUrl = process.env.ELECTRON_RENDERER_URL || 'http://localhost:5173';
    mainWindow.loadURL(rendererUrl);
    // Open DevTools in dev mode
    mainWindow.webContents.openDevTools({ mode: 'detach' });
  } else {
    // In production, load from the embedded Express server
    // which serves the built renderer assets
    mainWindow.loadURL(`http://127.0.0.1:${expressPort}`);
  }

  mainWindow.on('closed', () => {
    mainWindow = null;
  });
}

// ═══ IPC Handlers ═══

function setupIPC() {
  // Native save dialog
  ipcMain.handle('dialog:save', async (_event, options) => {
    if (!mainWindow) return null;
    const result = await dialog.showSaveDialog(mainWindow, options);
    return result;
  });

  // Native open dialog
  ipcMain.handle('dialog:open', async (_event, options) => {
    if (!mainWindow) return null;
    const result = await dialog.showOpenDialog(mainWindow, options);
    return result;
  });

  // App info
  ipcMain.handle('app:info', () => ({
    version: app.getVersion(),
    name: app.getName(),
    userData: app.getPath('userData'),
    isPackaged: app.isPackaged,
  }));

  // Save rendered file to user-chosen location
  ipcMain.handle('file:saveRendered', async (_event, renderUrl: string, defaultName: string) => {
    if (!mainWindow) return null;

    // Extract the filename from the URL (e.g. /api/renders/abc123.mp4 → abc123.mp4)
    const filename = renderUrl.split('/').pop();
    if (!filename) return null;

    // Determine the source file path in RENDERS_DIR
    const rendersDir = process.env.BRADLY_RENDERS_DIR
      || path.join(process.cwd(), 'renders');
    const sourcePath = path.join(rendersDir, filename);

    // Verify the source file exists
    if (!fs.existsSync(sourcePath)) {
      console.error('❌ Rendered file not found:', sourcePath);
      return null;
    }

    // Determine file extension and filters
    const ext = path.extname(filename).slice(1); // 'mp4', 'png', etc.
    const filterMap: Record<string, { name: string; extensions: string[] }[]> = {
      mp4: [{ name: 'Video MP4', extensions: ['mp4'] }],
      webm: [{ name: 'Video WebM', extensions: ['webm'] }],
      gif: [{ name: 'GIF', extensions: ['gif'] }],
      png: [{ name: 'Imagen PNG', extensions: ['png'] }],
      jpeg: [{ name: 'Imagen JPEG', extensions: ['jpeg', 'jpg'] }],
    };

    // Show native save dialog
    const result = await dialog.showSaveDialog(mainWindow, {
      title: 'Guardar exportación',
      defaultPath: path.join(app.getPath('downloads'), defaultName),
      filters: filterMap[ext] || [{ name: 'Archivo', extensions: [ext] }],
    });

    if (result.canceled || !result.filePath) return null;

    // Copy the rendered file to the chosen location
    try {
      await fs.promises.copyFile(sourcePath, result.filePath);
      console.log(`✅ Saved to: ${result.filePath}`);
      return result.filePath;
    } catch (err) {
      console.error('❌ Failed to save file:', err);
      return null;
    }
  });

  // Save raw blob data to user-chosen location (for ZIP exports etc.)
  ipcMain.handle('file:saveBlob', async (_event, data: Uint8Array, defaultName: string, filters?: { name: string; extensions: string[] }[]) => {
    if (!mainWindow) return null;

    const result = await dialog.showSaveDialog(mainWindow, {
      title: 'Guardar archivo',
      defaultPath: path.join(app.getPath('downloads'), defaultName),
      filters: filters || [{ name: 'Archivo', extensions: ['*'] }],
    });

    if (result.canceled || !result.filePath) return null;

    try {
      await fs.promises.writeFile(result.filePath, Buffer.from(data));
      console.log(`✅ Blob saved to: ${result.filePath}`);
      return result.filePath;
    } catch (err) {
      console.error('❌ Failed to save blob:', err);
      return null;
    }
  });
}


// ═══ App Lifecycle ═══

app.whenReady().then(async () => {
  // 1. Configure paths
  setupPaths();

  // 2. Setup IPC handlers
  setupIPC();

  // 3. Start Express server
  try {
    await startExpressServer();
  } catch (err) {
    console.error('❌ Failed to start Express server:', err);
    app.quit();
    return;
  }

  // 4. Set BRADLY_SERVE_URL for the headless renderer (Puppeteer)
  if (process.env.NODE_ENV === 'development') {
    // In dev, the React app is served by electron-vite's Vite dev server
    const rendererUrl = process.env.ELECTRON_RENDERER_URL || 'http://localhost:5173';
    process.env.BRADLY_SERVE_URL = rendererUrl;
  } else {
    // In prod, Express serves both API and static renderer files
    process.env.BRADLY_SERVE_URL = `http://127.0.0.1:${expressPort}`;
  }

  // 5. Create the main window
  createWindow();

  // macOS: re-create window when dock icon is clicked
  app.on('activate', () => {
    if (BrowserWindow.getAllWindows().length === 0) {
      createWindow();
    }
  });
});

// Quit when all windows are closed
app.on('window-all-closed', () => {
  app.quit();
});
