const express = require("express");
const router = express.Router();
const mysql = require("mysql2/promise");
const fs = require("fs");
const path = require("path");
const { exec } = require("child_process");
const multer = require("multer");
const { NodeSSH } = require("node-ssh");
const uploadLogo = require("../middleware/uploadLogo");


// ✅ Upload Ordner für Restore Dumps
const upload = multer({ dest: path.join(__dirname, "..", "uploads_tmp") });

const {
  listUsers,
  showCreateUser,
  postCreateUser,
  changeUserRole,
  resetUserPassword,
  activateUser,
  deactivateUser,
  showInvoiceOverview,
  updateUser,
} = require("../controllers/admin.controller");

const { requireArztOrMitarbeiter, requireAdmin } = require("../middleware/auth.middleware");

// ✅ config.enc Manager
const { loadConfig, saveConfig } = require("../config-manager");

// ✅ DB (für resetPool)
const db = require("../db");

// ✅ Firmendaten
const {
  getCompanySettings,
  saveCompanySettings
} = require("../controllers/companySettings.controller");


/* ==========================
   ✅ VERWALTUNG (NUR ADMIN)
========================== */
router.get("/users", requireAdmin, listUsers);
router.get("/create-user", requireAdmin, showCreateUser);
router.post("/create-user", requireAdmin, postCreateUser);

router.post("/users/change-role/:id", requireAdmin, changeUserRole);
router.post("/users/reset-password/:id", requireAdmin, resetUserPassword);
router.post("/users/activate/:id", requireAdmin, activateUser);
router.post("/users/deactivate/:id", requireAdmin, deactivateUser);
router.post("/users/update/:id", requireAdmin, updateUser);

/* ==========================
   ✅ DATENBANKVERWALTUNG (NUR ADMIN)
========================== */

// ✅ Seite anzeigen + aktuelle DB Config aus config.enc anzeigen
router.get("/database", requireAdmin, async (req, res) => {
  const cfg = loadConfig();

  const backupDir = path.join(__dirname, "..", "backups");

  let backupFiles = [];
  try {
    if (fs.existsSync(backupDir)) {
      backupFiles = fs
        .readdirSync(backupDir)
        .filter((f) => f.toLowerCase().endsWith(".sql"))
        .sort()
        .reverse(); // ✅ neueste zuerst
    }
  } catch (err) {
    console.error("❌ Backup Ordner Fehler:", err);
  }

  let systemInfo = null;

  try {
    if (cfg?.db) {
      const conn = await mysql.createConnection({
        host: cfg.db.host,
        port: Number(cfg.db.port || 3306), // ✅ WICHTIG: Port nutzen
        user: cfg.db.user,
        password: cfg.db.password,
        database: cfg.db.name,
      });

      // ✅ Version
      const [v] = await conn.query("SELECT VERSION() AS version");

      // ✅ Anzahl Tabellen
      const [tablesCount] = await conn.query(
        "SELECT COUNT(*) AS count FROM information_schema.tables WHERE table_schema = ?",
        [cfg.db.name],
      );

      // ✅ DB Größe (Bytes)
      const [dbSize] = await conn.query(
        `
        SELECT IFNULL(SUM(data_length + index_length),0) AS bytes
        FROM information_schema.tables
        WHERE table_schema = ?
        `,
        [cfg.db.name],
      );

      // ✅ Tabellen Details
      const [tables] = await conn.query(
        `
        SELECT 
          table_name AS name,
          table_rows AS row_count,
          ROUND((data_length + index_length) / 1024 / 1024, 2) AS size_mb
        FROM information_schema.tables
        WHERE table_schema = ?
        ORDER BY (data_length + index_length) DESC
        `,
        [cfg.db.name],
      );

      await conn.end();

      systemInfo = {
        version: v?.[0]?.version || "unbekannt",
        tableCount: tablesCount?.[0]?.count || 0,
        dbSizeMB:
          Math.round(((dbSize?.[0]?.bytes || 0) / 1024 / 1024) * 100) / 100,
        tables,
      };
    }
  } catch (err) {
    console.error("❌ SYSTEMINFO ERROR:", err);
    systemInfo = {
      error: err.message,
    };
  }

  res.render("admin/database", {
    user: req.session.user,
    dbConfig: cfg?.db || null,
    testResult: null,
    backupFiles,
    systemInfo,
  });
});

// ✅ Nur testen (ohne speichern)
router.post("/database/test", requireAdmin, async (req, res) => {
  const backupDir = path.join(__dirname, "..", "backups");

  function getBackupFiles() {
    try {
      if (fs.existsSync(backupDir)) {
        return fs
          .readdirSync(backupDir)
          .filter((f) => f.toLowerCase().endsWith(".sql"))
          .sort()
          .reverse();
      }
    } catch (err) {
      console.error("❌ Backup Ordner Fehler:", err);
    }
    return [];
  }

  try {
    const { host, port, user, password, name } = req.body;

    if (!host || !port || !user || !password || !name) {
      const cfg = loadConfig();
      return res.render("admin/database", {
        user: req.session.user,
        dbConfig: cfg?.db || null,
        testResult: { ok: false, message: "❌ Bitte alle Felder ausfüllen." },
        backupFiles: getBackupFiles(),
        systemInfo: null,
      });
    }

    const conn = await mysql.createConnection({
      host,
      port: Number(port),
      user,
      password,
      database: name,
    });

    await conn.query("SELECT 1");
    await conn.end();

    return res.render("admin/database", {
      user: req.session.user,
      dbConfig: { host, port: Number(port), user, password, name }, // ✅ PORT bleibt drin!
      testResult: { ok: true, message: "✅ Verbindung erfolgreich!" },
      backupFiles: getBackupFiles(),
      systemInfo: null,
    });
  } catch (err) {
    console.error("❌ DB TEST ERROR:", err);

    return res.render("admin/database", {
      user: req.session.user,
      dbConfig: req.body,
      testResult: {
        ok: false,
        message: "❌ Verbindung fehlgeschlagen: " + err.message,
      },
      backupFiles: getBackupFiles(),
      systemInfo: null,
    });
  }
});

// ✅ DB Settings speichern + Verbindung testen
router.post("/database", requireAdmin, async (req, res) => {
  function flashSafe(type, msg) {
    if (typeof req.flash === "function") {
      req.flash(type, msg);
      return;
    }
    req.session.flash = req.session.flash || [];
    req.session.flash.push({ type, message: msg });
  }

  const backupDir = path.join(__dirname, "..", "backups");

  // ✅ backupFiles immer bereitstellen
  function getBackupFiles() {
    try {
      if (fs.existsSync(backupDir)) {
        return fs
          .readdirSync(backupDir)
          .filter((f) => f.toLowerCase().endsWith(".sql"))
          .sort()
          .reverse();
      }
    } catch (err) {
      console.error("❌ Backup Ordner Fehler:", err);
    }
    return [];
  }

  try {
    const { host, port, user, password, name } = req.body;

    if (!host || !port || !user || !password || !name) {
      flashSafe("danger", "❌ Bitte alle Felder ausfüllen.");
      return res.render("admin/database", {
        user: req.session.user,
        dbConfig: req.body,
        testResult: { ok: false, message: "❌ Bitte alle Felder ausfüllen." },
        backupFiles: getBackupFiles(),
        systemInfo: null,
      });
    }

    // ✅ Verbindung testen
    const conn = await mysql.createConnection({
      host,
      port: Number(port),
      user,
      password,
      database: name,
    });

    await conn.query("SELECT 1");
    await conn.end();

    // ✅ Speichern inkl. Port
    const current = loadConfig() || {};
    current.db = {
      host,
      port: Number(port),
      user,
      password,
      name,
    };
    saveConfig(current);

    // ✅ Pool reset
    if (typeof db.resetPool === "function") {
      db.resetPool();
    }

    flashSafe("success", "✅ DB Einstellungen gespeichert!");

    // ✅ DIREKT NEU LADEN aus config.enc (damit wirklich die gespeicherten Werte drin stehen)
    const freshCfg = loadConfig();

    return res.render("admin/database", {
      user: req.session.user,
      dbConfig: freshCfg?.db || null,
      testResult: {
        ok: true,
        message: "✅ Gespeichert und Verbindung getestet.",
      },
      backupFiles: getBackupFiles(),
      systemInfo: null,
    });
  } catch (err) {
    console.error("❌ DB UPDATE ERROR:", err);
    flashSafe("danger", "❌ Verbindung fehlgeschlagen: " + err.message);

    return res.render("admin/database", {
      user: req.session.user,
      dbConfig: req.body,
      testResult: {
        ok: false,
        message: "❌ Verbindung fehlgeschlagen: " + err.message,
      },
      backupFiles: getBackupFiles(),
      systemInfo: null,
    });
  }
});

/* ==========================
   ✅ BACKUP (NUR ADMIN)
========================== */
router.post("/database/backup", requireAdmin, async (req, res) => {
  function flashSafe(type, msg) {
    if (typeof req.flash === "function") return req.flash(type, msg);
    req.session.flash = req.session.flash || [];
    req.session.flash.push({ type, message: msg });
    console.log(`[FLASH-${type}]`, msg);
  }

  try {
    const cfg = loadConfig();
    if (!cfg?.db) {
      flashSafe("danger", "❌ Keine DB Config gefunden (config.enc fehlt).");
      return res.redirect("/admin/database");
    }

    const { host, port, user, password, name } = cfg.db;

    // ✅ Programmserver Backup Dir
    const backupDir = path.join(__dirname, "..", "backups");
    if (!fs.existsSync(backupDir)) fs.mkdirSync(backupDir);

    // ✅ SSH Ziel (DB-Server)
    const sshHost = process.env.DBSERVER_HOST;
    const sshUser = process.env.DBSERVER_USER;
    const sshPort = Number(process.env.DBSERVER_PORT || 22);

    if (!sshHost || !sshUser) {
      flashSafe("danger", "❌ SSH Config fehlt (DBSERVER_HOST / DBSERVER_USER).");
      return res.redirect("/admin/database");
    }

    const stamp = new Date()
      .toISOString()
      .replace(/T/, "_")
      .replace(/:/g, "-")
      .split(".")[0];

    const fileName = `${name}_${stamp}.sql`;

    // ✅ Datei wird zuerst auf DB-Server erstellt (tmp)
    const remoteTmpPath = `/tmp/${fileName}`;

    // ✅ Datei wird dann lokal (Programmserver) gespeichert
    const localPath = path.join(backupDir, fileName);

    const ssh = new NodeSSH();
    await ssh.connect({
      host: sshHost,
      username: sshUser,
      port: sshPort,
      privateKeyPath: "/home/cay/.ssh/id_ed25519",
    });

    // ✅ 1) Dump auf DB-Server erstellen
    const dumpCmd =
      `mysqldump -h "${host}" -P "${port || 3306}" -u "${user}" -p'${password}' "${name}" > "${remoteTmpPath}"`;

    const dumpRes = await ssh.execCommand(dumpCmd);

    if (dumpRes.code !== 0) {
      ssh.dispose();
      flashSafe("danger", "❌ Backup fehlgeschlagen: " + (dumpRes.stderr || "mysqldump Fehler"));
      return res.redirect("/admin/database");
    }

    // ✅ 2) Dump Datei vom DB-Server auf Programmserver kopieren
    await ssh.getFile(localPath, remoteTmpPath);

    // ✅ 3) Temp Datei auf DB-Server löschen
    await ssh.execCommand(`rm -f "${remoteTmpPath}"`);

    ssh.dispose();

    flashSafe("success", `✅ Backup gespeichert (Programmserver): ${fileName}`);
    return res.redirect("/admin/database");
  } catch (err) {
    console.error("❌ BACKUP SSH ERROR:", err);
    flashSafe("danger", "❌ Backup fehlgeschlagen: " + err.message);
    return res.redirect("/admin/database");
  }
});


/* ==========================
   ✅ RESTORE (NUR ADMIN)
========================== */
router.post("/database/restore", requireAdmin, async (req, res) => {
  function flashSafe(type, msg) {
    if (typeof req.flash === "function") return req.flash(type, msg);
    req.session.flash = req.session.flash || [];
    req.session.flash.push({ type, message: msg });
    console.log(`[FLASH-${type}]`, msg);
  }

  const ssh = new NodeSSH();

  try {
    const cfg = loadConfig();
    if (!cfg?.db) {
      flashSafe("danger", "❌ Keine DB Config gefunden (config.enc fehlt).");
      return res.redirect("/admin/database");
    }

    const { host, port, user, password, name } = cfg.db;

    const backupFile = req.body.backupFile;
    if (!backupFile) {
      flashSafe("danger", "❌ Kein Backup ausgewählt.");
      return res.redirect("/admin/database");
    }

    if (backupFile.includes("..") || backupFile.includes("/") || backupFile.includes("\\")) {
      flashSafe("danger", "❌ Ungültiger Dateiname.");
      return res.redirect("/admin/database");
    }

    const backupDir = path.join(__dirname, "..", "backups");
    const localPath = path.join(backupDir, backupFile);

    if (!fs.existsSync(localPath)) {
      flashSafe("danger", "❌ Datei nicht gefunden (Programmserver): " + backupFile);
      return res.redirect("/admin/database");
    }

    const sshHost = process.env.DBSERVER_HOST;
    const sshUser = process.env.DBSERVER_USER;
    const sshPort = Number(process.env.DBSERVER_PORT || 22);

    if (!sshHost || !sshUser) {
      flashSafe("danger", "❌ SSH Config fehlt (DBSERVER_HOST / DBSERVER_USER).");
      return res.redirect("/admin/database");
    }

    const remoteTmpPath = `/tmp/${backupFile}`;

    await ssh.connect({
      host: sshHost,
      username: sshUser,
      port: sshPort,
      privateKeyPath: "/home/cay/.ssh/id_ed25519",
    });

    await ssh.putFile(localPath, remoteTmpPath);

    const restoreCmd =
      `mysql -h "${host}" -P "${port || 3306}" -u "${user}" -p'${password}' "${name}" < "${remoteTmpPath}"`;

    const restoreRes = await ssh.execCommand(restoreCmd);

    await ssh.execCommand(`rm -f "${remoteTmpPath}"`);

    if (restoreRes.code !== 0) {
      flashSafe("danger", "❌ Restore fehlgeschlagen: " + (restoreRes.stderr || "mysql Fehler"));
      return res.redirect("/admin/database");
    }

    flashSafe("success", `✅ Restore erfolgreich: ${backupFile}`);
    return res.redirect("/admin/database");
  } catch (err) {
    console.error("❌ RESTORE SSH ERROR:", err);
    flashSafe("danger", "❌ Restore fehlgeschlagen: " + err.message);
    return res.redirect("/admin/database");
  } finally {
    try {
      ssh.dispose();
    } catch (e) {}
  }
});

/* ==========================
   ✅ ABRECHNUNG (NUR ARZT)
========================== */
router.get("/invoices", requireAdmin, showInvoiceOverview);

/* ==========================
   ✅ Firmendaten
========================== */
router.get(
  "/company-settings",
  requireAdmin,
  getCompanySettings
);

router.post(
  "/company-settings",
  requireAdmin,
  uploadLogo.single("logo"),
  saveCompanySettings
);

module.exports = router;
