import path from "node:path";
import fs from "node:fs";
import { fileURLToPath } from "node:url";
import { app, BrowserWindow, dialog, ipcMain, shell } from "electron";

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

const defaultGodotRoot = "/Users/jason/Projects/anime-fighter-pro";
const homeRoot = app.getPath("home");
const notesRuntimeRoot = path.join(homeRoot, "Library", "Application Support", "anime-fighter-pro-organizer", "runtime");
const bundledSeedDbPath = path.join(app.getAppPath(), "data", "anime-fighter-pro-organizer.sqlite");
let serverHandle = null;
let mainWindow = null;
let quitting = false;
let startServerFn = null;

function configureRuntimeEnv() {
  process.env.SSB_ADMIN_DATA_ROOT = notesRuntimeRoot;
  process.env.SSB_SEED_DB_PATH = process.env.SSB_SEED_DB_PATH || bundledSeedDbPath;
  process.env.SSB_GODOT_ROOT = process.env.SSB_GODOT_ROOT || defaultGodotRoot;
}

function isLocalUrl(url) {
  return Boolean(serverHandle) && url.startsWith(`http://127.0.0.1:${serverHandle.port}`);
}

async function stopServer() {
  if (!serverHandle?.server) return;
  const activeServer = serverHandle.server;
  serverHandle = null;
  await new Promise((resolve) => activeServer.close(resolve));
}

async function ensureServer() {
  if (!startServerFn) {
    ({ startServer: startServerFn } = await import("../src/server.js"));
  }
  if (!serverHandle) {
    serverHandle = await startServerFn({ port: 0 });
  }
}

async function createMainWindow() {
  configureRuntimeEnv();

  await ensureServer();

  mainWindow = new BrowserWindow({
    width: 1560,
    height: 980,
    minWidth: 1180,
    minHeight: 760,
    title: "Anime Fighter Pro Moveset Organizer",
    backgroundColor: "#eef2f7",
    autoHideMenuBar: true,
    show: false,
    webPreferences: {
      preload: path.join(__dirname, "notes-preload.cjs"),
      contextIsolation: true,
      sandbox: true,
    },
  });

  mainWindow.on("ready-to-show", () => {
    mainWindow?.show();
  });

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

  mainWindow.webContents.setWindowOpenHandler(({ url }) => {
    if (isLocalUrl(url)) {
      return { action: "allow" };
    }
    shell.openExternal(url);
    return { action: "deny" };
  });

  mainWindow.webContents.on("will-navigate", (event, url) => {
    if (!isLocalUrl(url)) {
      event.preventDefault();
      shell.openExternal(url);
    }
  });

  await mainWindow.loadURL(`http://127.0.0.1:${serverHandle.port}/notes`);
}

async function createPdfFromHtml(html, outputPath) {
  const pdfWindow = new BrowserWindow({
    show: false,
    webPreferences: {
      sandbox: true,
      contextIsolation: true,
    },
  });
  try {
    await pdfWindow.loadURL(`data:text/html;charset=utf-8,${encodeURIComponent(html)}`);
    const pdfBuffer = await pdfWindow.webContents.printToPDF({
      printBackground: true,
      pageSize: "Letter",
      margins: {
        top: 0.5,
        bottom: 0.5,
        left: 0.5,
        right: 0.5,
      },
    });
    fs.writeFileSync(outputPath, pdfBuffer);
  } finally {
    pdfWindow.destroy();
  }
}

function exportFolderPath() {
  return path.join(app.getPath("documents"), "Anime Fighter Pro Moveset Exports");
}

async function registerNotesIpcHandlers() {
  configureRuntimeEnv();

  ipcMain.handle("notes:export", async (_event, format) => {
    const archive = await import("../src/notes-archive.js");
    const exportDir = exportFolderPath();
    fs.mkdirSync(exportDir, { recursive: true });

    const model = archive.buildDocumentExportModel();
    const baseName = archive.defaultExportBasename();

    let outputPath = "";
    if (format === "text") {
      outputPath = path.join(exportDir, `${baseName}.txt`);
      fs.writeFileSync(outputPath, archive.renderTextArchive(model), "utf8");
    } else if (format === "word") {
      outputPath = path.join(exportDir, `${baseName}.doc`);
      fs.writeFileSync(outputPath, archive.renderWordArchive(model), "utf8");
    } else if (format === "excel") {
      outputPath = path.join(exportDir, `${baseName}.xls`);
      fs.writeFileSync(outputPath, archive.renderExcelArchive(model), "utf8");
    } else if (format === "pdf") {
      outputPath = path.join(exportDir, `${baseName}.pdf`);
      await createPdfFromHtml(archive.renderPdfArchive(model), outputPath);
    } else if (format === "bundle") {
      outputPath = path.join(exportDir, `${baseName}${archive.bundleExtension()}`);
      fs.writeFileSync(outputPath, JSON.stringify(archive.buildMovesetBundle(), null, 2), "utf8");
    } else {
      throw new Error("Unsupported export format.");
    }

    shell.showItemInFolder(outputPath);
    return {
      ok: true,
      output_path: outputPath,
    };
  });

  ipcMain.handle("notes:import", async () => {
    const result = await dialog.showOpenDialog(mainWindow, {
      title: "Load Anime Fighter Pro Moveset File",
      properties: ["openFile"],
      filters: [
        {
          name: "Anime Fighter Pro Moveset File",
          extensions: ["animefightermoveset"],
        },
      ],
      defaultPath: exportFolderPath(),
    });

    if (result.canceled || !result.filePaths[0]) {
      return { ok: false, canceled: true };
    }

    const archive = await import("../src/notes-archive.js");
    const bundle = JSON.parse(fs.readFileSync(result.filePaths[0], "utf8"));
    const imported = archive.importMovesetBundle(bundle);

    return {
      ok: true,
      file_path: result.filePaths[0],
      imported,
    };
  });
}

const gotLock = app.requestSingleInstanceLock();
if (!gotLock) {
  app.quit();
} else {
  app.on("second-instance", () => {
    if (mainWindow) {
      if (mainWindow.isMinimized()) {
        mainWindow.restore();
      }
      mainWindow.focus();
    }
  });

  app.whenReady().then(async () => {
    await registerNotesIpcHandlers();
    await createMainWindow();

    app.on("activate", async () => {
      if (!BrowserWindow.getAllWindows().length) {
        await createMainWindow();
      }
    });
  });

  app.on("before-quit", async (event) => {
    if (quitting) return;
    event.preventDefault();
    quitting = true;
    await stopServer();
    app.quit();
  });

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