const express = require("express");
const { exec } = require("child_process");
const app = express();
const PORT = 3000;
const path = require("path");
const usersFile = path.join(__dirname, "users.json");

app.use(express.json());
app.use(express.urlencoded({ extended: true }));

// Session Setup (oben in server.js)
const session = require("express-session");

app.use(express.json());
app.use(express.urlencoded({ extended: true }));

app.use(session({
    secret: "ein_geheimes_passwort",
    resave: false,
    saveUninitialized: false
}));

// ------------------------
// Middleware: Schutz für alles außer /login, /public etc.
app.use((req, res, next) => {
    const publicPaths = ["/login", "/index.html", "/style.css", "/onlinesymbol.js"]; // erlaubte öffentliche Pfade
    const isPublic = publicPaths.some(path => req.path.startsWith(path));

    if (isPublic) return next();

    if (!req.session.user) {
        return res.redirect("/index.html"); // nicht eingeloggt → Login-Seite
    }

    next(); // eingeloggt → Request weiterleiten
});




app.use(express.json());       // für JSON-Body
app.use(express.urlencoded({ extended: true })); // optional für FormData / URL-encoded

// Statische Dateien (deine Webseite)
app.use(express.static("public"));

// START
app.get("/start", (req, res) => {
    exec("screen -list", (err, stdout) => {
        if (stdout && stdout.includes("mc-server")) {
            return res.send("Server läuft bereits");
        }

        exec("bash start.sh");
        res.send("Server wird gestartet");
    });
});

// STOP
app.get("/stop", (req, res) => {
    exec("bash stop.sh");
    res.send("Server wird gestoppt");
});

// STATUS
app.get("/status", (req, res) => {
    exec("screen -list", (err, stdout) => {
        const online = stdout && stdout.includes("mc-server");
        res.json({ online });
    });
});

app.listen(PORT, () => {
    console.log("Panel läuft auf http://localhost:" + PORT);
});







const fs = require("fs");

// Logs holen
app.get("/logs", (req, res) => {
    fs.readFile("/home/ubuntu/minecraft-server/logs/latest.log", "utf8", (err, data) => {
        if (err) return res.send("");
        res.send(data);
    });
});


// Befehl senden
app.get("/command", (req, res) => {
    const cmd = req.query.cmd;

    if (!cmd) return res.send("Kein Befehl");

    // Sende den Befehl an die screen-Session
    exec(`screen -S mc-server -X stuff "${cmd}\n"`);

    res.send("Befehl gesendet: " + cmd);
});







//----------------------Optionen----------------------------




// Server.properties Pfad
const propertiesPath = "/home/ubuntu/minecraft-server/server.properties";

// Optionen auslesen
app.get("/getOptions", (req, res) => {
    fs.readFile(propertiesPath, "utf8", (err, data) => {
        if (err) return res.status(500).send("Fehler beim Lesen der Datei");

        const lines = data.split("\n");
        const options = {};
        lines.forEach(line => {
            if (!line || line.startsWith("#")) return;
            const [key, value] = line.split("=");
            options[key] = value;
        });

        res.json(options);
    });
});

// Optionen speichern
app.post("/setOptions", express.json(), (req, res) => {
    const newOptions = req.body; // {motd: "xyz", max-players: "20", ...}

    fs.readFile(propertiesPath, "utf8", (err, data) => {
        if (err) return res.status(500).send("Fehler beim Lesen der Datei");

        let lines = data.split("\n");
        lines = lines.map(line => {
            if (!line || line.startsWith("#")) return line;

            const [key, value] = line.split("=");

            if (newOptions[key] !== undefined) {
                return `${key}=${newOptions[key]}`;
            }

            return line;
        });

        fs.writeFile(propertiesPath, lines.join("\n"), err => {
            if (err) return res.status(500).send("Fehler beim Schreiben der Datei");

            res.send("Optionen gespeichert!");
        });
    });
});



/*---------------------Welten-------------------------*/

const worldsDir = "/home/ubuntu/minecraft-server"; // Server-Ordner

// bekannte Vanilla-Welten
const standardWorlds = ["world", "world_nether", "world_the_end"];

app.get("/getWorlds", (req, res) => {
    const allFolders = fs.readdirSync(worldsDir)
        .filter(f => fs.statSync(path.join(worldsDir, f)).isDirectory());

    // Nur bekannte Standard-Welten oder zusätzliche bekannte Weltordner
    const welten = allFolders
        .filter(f => standardWorlds.includes(f))  // Filter anwenden
        .map(name => {
            const stats = fs.statSync(path.join(worldsDir, name));
            return {
                name,
                size: getFolderSize(path.join(worldsDir, name)), // jetzt korrekt MB/GB
                modified: stats.mtime.toLocaleDateString()
            };
        });

    res.json(welten);
});



function getFolderSize(folderPath) {
    let totalBytes = 0;

    function calcSize(dir) {
        const files = fs.readdirSync(dir, { withFileTypes: true });
        for (const f of files) {
            const fullPath = path.join(dir, f.name);
            if (f.isDirectory()) calcSize(fullPath);
            else totalBytes += fs.statSync(fullPath).size;
        }
    }

    calcSize(folderPath);

    // Größe umrechnen
    if (totalBytes >= 1024 * 1024 * 1024) {
        return (totalBytes / (1024 * 1024 * 1024)).toFixed(2) + " GB";
    } else {
        return (totalBytes / (1024 * 1024)).toFixed(2) + " MB";
    }
}


// Herunterladen
app.get("/downloadWorld/:name", (req, res) => {
    const worldPath = path.join(worldsDir, req.params.name);
    if (!fs.existsSync(worldPath)) return res.status(404).send("Welt existiert nicht");

    const archive = path.join("/tmp", `${req.params.name}.zip`);
    // Zippen
    const zip = require("adm-zip");
    const zipObj = new zip();
    zipObj.addLocalFolder(worldPath);
    zipObj.writeZip(archive);

    res.download(archive, `${req.params.name}.zip`, err => {
        fs.unlinkSync(archive); // temporäre Datei löschen
    });
});

// Backup (lokal auf Server)
app.post("/backupWorld", (req, res) => {
    const { name } = req.body;
    const worldPath = path.join(worldsDir, name);
    const backupDir = path.join("/home/ubuntu/minecraft-backups");
    if (!fs.existsSync(backupDir)) fs.mkdirSync(backupDir);

    const zip = require("adm-zip");
    const zipObj = new zip();
    zipObj.addLocalFolder(worldPath);
    const backupPath = path.join(backupDir, `${name}-${Date.now()}.zip`);
    zipObj.writeZip(backupPath);

    res.send(`Backup erstellt: ${backupPath}`);
});

// Löschen
app.post("/deleteWorld", (req, res) => {
    const { name } = req.body; // req.body muss hier ein Objekt sein
    if (!name) return res.status(400).send("Keine Welt angegeben");

    const weltOrdner = path.join(worldsDir, name);
    if (!fs.existsSync(weltOrdner)) return res.status(404).send("Welt existiert nicht");

    try {
        fs.rmSync(weltOrdner, { recursive: true, force: true });
        res.send(`Welt '${name}' erfolgreich gelöscht!`);
    } catch (err) {
        console.error(err);
        res.status(500).send("Fehler beim Löschen der Welt");
    }
});

const multer = require("multer");
const upload = multer({ dest: "/tmp/" });
const AdmZip = require("adm-zip");

app.post("/uploadWorld", upload.single("weltZip"), (req, res) => {
    const file = req.file;
    const targetFolderName = req.body.targetFolder; // Button sendet mit: "world" / "world_nether" / etc.

    if (!file) return res.status(400).send("Keine Datei hochgeladen");
    if (!targetFolderName) return res.status(400).send("Zielwelt nicht angegeben");

    const tempDir = path.join("/tmp", `upload_${Date.now()}`);
    fs.mkdirSync(tempDir);

    try {
        const zip = new AdmZip(file.path);
        zip.extractAllTo(tempDir, true); // erst alles in Temp entpacken

        const entries = fs.readdirSync(tempDir, { withFileTypes: true });
        const folders = entries.filter(e => e.isDirectory());

        const zielOrdner = path.join(worldsDir, targetFolderName);

        if (fs.existsSync(zielOrdner)) {
            fs.rmSync(tempDir, { recursive: true, force: true });
            fs.unlinkSync(file.path);
            return res.status(400).send(`Die Welt '${targetFolderName}' existiert bereits!`);
        }

        fs.mkdirSync(zielOrdner);

        if (folders.length === 1) {
            // ZIP enthält einen Ordner → dessen Inhalt in den Zielordner kopieren
            const folderPath = path.join(tempDir, folders[0].name);
            fs.cpSync(folderPath, zielOrdner, { recursive: true });
        } else {
            // ZIP enthält nur Dateien → direkt in Zielordner kopieren
            entries.forEach(e => {
                const src = path.join(tempDir, e.name);
                const dest = path.join(zielOrdner, e.name);
                if (e.isDirectory()) fs.cpSync(src, dest, { recursive: true });
                else fs.copyFileSync(src, dest);
            });
        }

        fs.rmSync(tempDir, { recursive: true, force: true });
        fs.unlinkSync(file.path);

        res.send(`Welt '${targetFolderName}' erfolgreich hochgeladen!`);

    } catch (err) {
        console.error(err);
        fs.rmSync(tempDir, { recursive: true, force: true });
        fs.unlinkSync(file.path);
        res.status(500).send("Fehler beim Entpacken der Welt");
    }
});


/*--------------------Neuinstallieren----------------------*/




const serverPath = "/home/ubuntu/minecraft-server";
const portFile = "/home/ubuntu/minecraft-panel/port";

app.post("/reinstallServer", (req, res) => {
    const { type, version } = req.body;

    console.log("Neuinstallation:", type, version);

    // 1. Server stoppen
    exec("pkill -f java", () => {

        try {
            // 2. Ordner löschen
            fs.rmSync(serverPath, { recursive: true, force: true });

            // 3. Ordner neu erstellen
            fs.mkdirSync(serverPath, { recursive: true });

        } catch (err) {
            console.error(err);
            return res.send("Fehler beim Löschen des Serverordners");
        }

        // 4. Server neu installieren
        const cmd = `
            cd ${serverPath} &&
            wget https://hummelsvrs.ddns.net/mcsvr/automation/NoUserInput/NoAutomatedStart/NoSudo/mcsvr-install-nui-nas-nosudo.sh &&
            bash mcsvr-install-nui-nas-nosudo.sh ${version} ${type} ubuntu
            wget -O server-icon.png https://hummelsvrs.ddns.net/files/minecraft/minecraft-panel/standart-server-icon.png
        `;

        exec(cmd, (err, stdout, stderr) => {
            if (err) {
                console.error(err);
                return res.send("Fehler bei der Installation");
            }

            // --- Port anpassen ---
            try {
                let port = fs.readFileSync(portFile, "utf-8").trim();
                const serverProperties = path.join(serverPath, "server.properties");
                let data = fs.readFileSync(serverProperties, "utf-8");
                let lines = data.split("\n");
                let found = false;

                lines = lines.map(line => {
                    if (line.startsWith("server-port=")) {
                        found = true;
                        return `server-port=${port}`;
                    }
                    return line;
                });

                if (!found) lines.push(`server-port=${port}`);

                fs.writeFileSync(serverProperties, lines.join("\n"), "utf-8");
                console.log(`Port auf ${port} gesetzt`);
            } catch (e) {
                console.error("Port konnte nicht gesetzt werden:", e);
            }

            // 5. Server starten
            exec(`cd /home/ubuntu/minecraft-panel && bash start.sh`);

            res.send("Server wurde komplett neu installiert!");
        });

    });
});




/*----------------------------------Login-----------------------------------*/





app.use(session({
    secret: "ein_geheimes_passwort",
    resave: false,
    saveUninitialized: false,
    cookie: {
        maxAge: 1000 * 60 * 10 // 24 Stunden in ms
    }
}));



// Beim Start die JSON laden oder anlegen
let users = [];
if (fs.existsSync(usersFile)) {
    users = JSON.parse(fs.readFileSync(usersFile, "utf-8"));
} else {
    users = [{ username: "admin", password: "geheim", redirect: "/server.html" }];
    fs.writeFileSync(usersFile, JSON.stringify(users, null, 2), "utf-8");
}

// Login-Route
app.post("/login", (req, res) => {
    const { username, password } = req.body;
    const user = users.find(u => u.username === username && u.password === password);

    if (user) {
        req.session.user = user.username;
        res.json({ success: true, redirect: user.redirect });
    } else {
        res.json({ success: false });
    }
});



function auth(req, res, next) {
    if (req.session.user) next();
    else res.redirect("/index.html"); // geschützte Seiten weiterleiten, wenn nicht eingeloggt
}



// Beispiel: Hauptseite schützen
app.get("/server.html", auth, (req, res) => {
    res.sendFile(path.join(__dirname, "public/server.html"));
});

/*--------------------------Passwort ändern--------------------------------*/

app.post("/changeCredentials", (req, res) => {
    const { oldPassword, newPassword, newUsername } = req.body;
    const username = req.session.user;

    const user = users.find(u => u.username === username && u.password === oldPassword);
    if (!user) {
        return res.json({ success: false, message: "Altes Passwort falsch" });
    }

    // Username ändern (falls angegeben)
    if (newUsername && newUsername.trim() !== "") {
        user.username = newUsername;
        req.session.user = newUsername; // Session updaten!
    }

    // Passwort ändern
    if (newPassword && newPassword.trim() !== "") {
        user.password = newPassword;
    }

    fs.writeFileSync(usersFile, JSON.stringify(users, null, 2), "utf-8");

    res.json({ success: true, message: "Daten erfolgreich geändert!" });
});


/*---------------------------------Port---------------------------------- */
const PORT_FILE = path.join(__dirname, "port");

app.get("/getPort", (req, res) => {
    let port = "25565"; // Fallback
    try {
        if (fs.existsSync(PORT_FILE)) {
            port = fs.readFileSync(PORT_FILE, "utf-8").trim();
        }
    } catch (err) {
        console.error("Port-Datei konnte nicht gelesen werden:", err);
    }
    res.json({ port });
});


/**---------------------------------------Mods------------------------------------- */
const modsDir = "/home/ubuntu/minecraft-server/mods";

// Mods Liste
app.get("/getMods", (req, res) => {
    if (!fs.existsSync(modsDir)) return res.json([]); // leer zurückgeben, kein Ordner wird erstellt

    const mods = fs.readdirSync(modsDir)
        .filter(f => f.endsWith(".jar"))
        .map(f => {
            const stats = fs.statSync(path.join(modsDir, f));
            return {
                name: f,
                size: (stats.size / (1024 * 1024)).toFixed(2),
                modified: stats.mtime.toLocaleString()
            };
        });

    res.json(mods);
});

// Mod Upload (mehrere Dateien)
app.post("/uploadMods", upload.array("mods"), (req, res) => {
    if (!fs.existsSync(modsDir)) return res.status(400).send("Mods-Ordner existiert nicht!");

    req.files.forEach(file => {
        const target = path.join(modsDir, file.originalname);
        fs.renameSync(file.path, target);
    });

    res.send("Mods hochgeladen!");
});

// Mod löschen
app.post("/deleteMod", express.json(), (req, res) => {
    const { name } = req.body;
    const filePath = path.join(modsDir, name);
    if (fs.existsSync(filePath)) {
        fs.unlinkSync(filePath);
        res.send("Mod gelöscht!");
    } else {
        res.send("Mod nicht gefunden!");
    }
});

// Prüfen ob Mods Ordner existiert
app.get("/checkModsFolder", (req, res) => {
    res.json({ exists: fs.existsSync(modsDir) });
});


/*--------------------------------Backups---------------------------*/

const backupsDir = "/home/ubuntu/minecraft-backups";


// Backup-Liste
app.get("/getBackups", (req, res) => {
    if (!fs.existsSync(backupsDir)) fs.mkdirSync(backupsDir, { recursive: true });

    const files = fs.readdirSync(backupsDir)
        .filter(f => f.endsWith(".zip"))
        .map(f => {
            const stats = fs.statSync(path.join(backupsDir, f));
            return {
                name: f,
                size: (stats.size / (1024 * 1024)).toFixed(2),
                date: stats.mtime.toLocaleString()
            };
        });

    res.json(files);
});

// Backup löschen
app.post("/deleteBackup", express.json(), (req, res) => {
    const { name } = req.body;
    const filePath = path.join(backupsDir, name);
    if (fs.existsSync(filePath)) {
        fs.unlinkSync(filePath);
        res.send("Backup gelöscht!");
    } else {
        res.send("Backup nicht gefunden!");
    }
});

// Backup wiederherstellen
app.post("/restoreBackup", express.json(), (req, res) => {
    const { name } = req.body;
    const backupPath = path.join(backupsDir, name);

    if (!fs.existsSync(backupPath)) return res.send("Backup nicht gefunden");

    // Prüfen, ob der Server läuft (über screen)
    exec("screen -list | grep mc-server", (err, stdout) => {
        if (stdout && stdout.trim() !== "") return res.send("Der Server muss offline sein!");

        // Zielordner bestimmen anhand des Backup-Namens
        let zielOrdner;
        if (name.startsWith("world_nether")) zielOrdner = path.join(serverPath, "world_nether");
        else if (name.startsWith("world_the_end")) zielOrdner = path.join(serverPath, "world_the_end");
        else zielOrdner = path.join(serverPath, "world");

        try {
            // Alten Weltordner löschen und neu erstellen
            if (fs.existsSync(zielOrdner)) fs.rmSync(zielOrdner, { recursive: true, force: true });
            fs.mkdirSync(zielOrdner, { recursive: true });

            // Backup in den richtigen Ordner entpacken
            exec(`unzip -o ${backupPath} -d ${zielOrdner}`, (err2) => {
                if (err2) {
                    console.error(err2);
                    return res.send("Fehler beim Wiederherstellen des Backups");
                }
                res.send("Backup erfolgreich wiederhergestellt!");
            });
        } catch (e) {
            console.error(e);
            return res.send("Fehler beim Wiederherstellen der Welt");
        }
    });
});


/*---------------------------------Server Icon-----------------------------*/
const iconStorage = multer.diskStorage({
    destination: (req, file, cb) => cb(null, "/home/ubuntu/minecraft-server/"),
    filename: (req, file, cb) => cb(null, "server-icon.png")
});
const iconUpload = multer({ storage: iconStorage });

app.post("/uploadServerIcon", iconUpload.single("serverIcon"), (req, res) => {
    if (!req.file) return res.send("Keine Datei ausgewählt!");
    res.send("Server Icon erfolgreich hochgeladen!");
});

// Statischer Zugriff auf den Minecraft Server Ordner (für icon.png etc.)
app.use("/minecraft-server", express.static("/home/ubuntu/minecraft-server"));



/**-----------------------------------------Plugins----------------------------------- */
const pluginsDir = "/home/ubuntu/minecraft-server/plugins";

app.get("/getPlugins", (req, res) => {
    if (!fs.existsSync(pluginsDir)) {
        return res.json([]); // nichts anzeigen wenn Ordner fehlt
    }

    const plugins = fs.readdirSync(pluginsDir)
        .filter(f => f.endsWith(".jar"))
        .map(f => {
            const stats = fs.statSync(path.join(pluginsDir, f));
            return {
                name: f,
                size: (stats.size / (1024 * 1024)).toFixed(2),
                modified: stats.mtime.toLocaleString()
            };
        });

    res.json(plugins);
});

app.post("/uploadPlugins", upload.array("plugins"), (req, res) => {
    if (!fs.existsSync(pluginsDir)) {
        return res.send("Plugins-Ordner existiert nicht!");
    }

    req.files.forEach(file => {
        const target = path.join(pluginsDir, file.originalname);
        fs.renameSync(file.path, target);
    });

    res.send("Plugins hochgeladen!");
});

app.post("/deletePlugin", express.json(), (req, res) => {
    const { name } = req.body;
    const filePath = path.join(pluginsDir, name);

    if (fs.existsSync(filePath)) {
        fs.unlinkSync(filePath);
        res.send("Plugin gelöscht!");
    } else {
        res.send("Plugin nicht gefunden!");
    }
});

app.get("/checkPluginsFolder", (req, res) => {
    res.json({ exists: fs.existsSync(pluginsDir) });
});





/*-------------------------IP----------------------------- */
const os = require("os");

app.get("/getIP", (req, res) => {
    const interfaces = os.networkInterfaces();

    for (let name in interfaces) {
        for (let net of interfaces[name]) {
            if (net.family === "IPv4" && !net.internal) {
                return res.json({ ip: net.address });
            }
        }
    }

    res.json({ ip: "127.0.0.1" });
});



/**------------------------------------Update-------------------------------- */

app.post("/api/run-update", (req, res) => {
    exec("screen -ls", (err, stdout) => {
        // Prüfen, ob tatsächlich ein Update läuft
        if (err && err.code !== 1) { // Exit-Code 1 = keine Screens, also okay
            console.error("Fehler bei screen check:", err);
            return res.status(500).send("Fehler beim Prüfen des Update-Status");
        }

        if (stdout && stdout.includes("panel-update")) {
            return res.send("Update läuft bereits!");
        }

        const command = `
screen -dmS panel-update bash -lc '
cd /home/ubuntu &&
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin &&
bash update.sh
'
`;

        exec(command, (error) => {
            if (error) {
                console.error("Fehler beim Starten:", error);
                return res.status(500).send("Update konnte nicht gestartet werden");
            }

            res.send("Update läuft. Das Panel ist für ein paar Minuten nicht erreichbar. Bitte warten.");
        });
    });
});


const axios = require("axios");

const LOCAL_VERSION_FILE = "/home/ubuntu/minecraft-panel/version.json";
const REMOTE_VERSION_URL = "https://hummelsvrs.ddns.net/files/minecraft/minecraft-panel/version.json";

app.get("/api/version", async (req, res) => {
    try {
        const localData = JSON.parse(fs.readFileSync(LOCAL_VERSION_FILE));
        const remoteRes = await axios.get(REMOTE_VERSION_URL);

        const remoteData = remoteRes.data;

        res.json({
            currentVersion: localData.version,
            latestVersion: remoteData.version,
            updateAvailable: localData.version !== remoteData.version
        });

    } catch (err) {
        console.error(err);
        res.status(500).json({ error: "Version check failed" });
    }
});

app.get('/username', (req, res) => {
    const username = fs.readFileSync('user', 'utf8').trim();
    res.send(username);
});

