const express = require("express");
const pool = require("../db"); // Stelle sicher, dass dein DB-Pool importiert wird
const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");
const crypto = require("crypto");
const nodemailer = require("nodemailer");
const {
  requireAuth,
  requireRole,
  requireAdmin,
} = require("../middleware/auth"); // Falls Middleware in einer extra Datei liegt
const { transporter, sendActivationEmail } = require("../middleware/mail");

const router = express.Router();

// Registrierung
router.post("/register", async (req, res) => {
  const { username, email, password } = req.body;
  try {
    const hashedPassword = await bcrypt.hash(password, 10);
    await pool.query(
      "INSERT INTO users (username, email, password) VALUES ($1, $2, $3)",
      [username, email, hashedPassword]
    );
    const message =
      "Registrierung erfolgreich. Ein Admin wird dich in kürze freischalten";
    const mailOptions = {
      to: "admin@boergmann.it",
      from: "admin@boergmann.it",
      subject: "Neue Registrierung",
      text: `${username} hat sich registriert`,
    };

    transporter.sendMail(mailOptions, (error) => {
      if (error) {
        console.error("Error sending email:", error);
        res.status(500).json({ error: "Interner Serverfehler" });
      }
    });

    res.status(201).json({ message: message });
  } catch (error) {
    console.error("Error registering user:", error);
    res.status(500).json({ error: "Interner Serverfehler" });
  }
});

// Login
router.post("/login", async (req, res) => {
  const { username, password } = req.body;

  try {
    const userResult = await pool.query(
      "SELECT * FROM users WHERE username = $1",
      [username]
    );

    if (userResult.rows.length === 0) {
      return res.status(401).json({ error: "Ungültige Anmeldedaten" });
    }

    const user = userResult.rows[0];
    const match = await bcrypt.compare(password, user.password);
    if (!match) {
      return res.status(401).json({ error: "Ungültige Anmeldedaten" });
    }

    if (!user.is_active) {
      return res.status(401).json({ error: "Auf Freischaltung warten" });
    }

    const rightsResult = await pool.query(
      `SELECT fid_abteilung, fid_role FROM userrights WHERE fid_user = $1`,
      [user.id]
    );

    const abteilungsIds = rightsResult.rows.map((r) => r.fid_abteilung);

    // Abfrage aller passenden Abteilungen in einem Query
    let abteilungen = [];
    if (abteilungsIds.length > 0) {
      const abteilungenResult = await pool.query(
        `SELECT id, name, trainingstag FROM abteilungen WHERE id = ANY($1::int[])`,
        [abteilungsIds]
      );

      // Kombiniere Rechte + Abteilungsdetails
      abteilungen = abteilungenResult.rows.map((abteilung) => {
        const rechte = rightsResult.rows.find(
          (r) => r.fid_abteilung === abteilung.id
        )?.fid_role;
        return {
          id: abteilung.id,
          name: abteilung.name,
          trainingstag: abteilung.trainingstag,
          rechte: rechte,
        };
      });
    }

    const roles = {};
    rightsResult.rows.forEach((row) => {
      roles[row.fid_abteilung] = row.fid_role;
    });

    const token = jwt.sign(
      { id: user.id, username: user.username, roles },
      process.env.JWT_SECRET,
      {
        expiresIn: "24d",
      }
    );

    res.json({ token, abteilungen });
  } catch (error) {
    console.error("Error logging in:", error);
    return res.status(500).json({ error: "Fehler beim Login" });
  }
});


// Reset initiieren
router.post("/reset-password", async (req, res) => {
  const { email } = req.body;

  if (!email) {
    return res.status(400).json({ error: "E-Mail-Adresse ist erforderlich" });
  }

  try {
    // Prüfen, ob die E-Mail existiert
    const userResult = await pool.query(
      "SELECT id, username FROM users WHERE email = $1",
      [email]
    );

    if (userResult.rows.length === 0) {
      return res
        .status(404)
        .json({ error: "Benutzer mit dieser E-Mail nicht gefunden" });
    }

    const { id, username } = userResult.rows[0];

    // Token generieren (random 32 Byte)
    const token = crypto.randomBytes(32).toString("hex");
    const expires = new Date(Date.now() + 3600000); // Token 1 Stunde gültig

    // Token und Ablaufdatum in die DB speichern
    await pool.query(
      "UPDATE users SET reset_password_token = $1, reset_password_expires = $2 WHERE id = $3",
      [token, expires, id]
    );

    // Mail senden
    const resetLink = `https://${process.env.HOST}/reset/${token}`;
    const mailOptions = {
      from: process.env.MAILUSER,
      to: email,
      subject: "Passwort zurücksetzen",
      text: `Hallo ${username},\n\nKlicke auf den folgenden Link, um dein Passwort zurückzusetzen:\n\n${resetLink}\n\nDer Link ist 1 Stunde gültig.\n\nFalls du das Zurücksetzen nicht beantragt hast, ignoriere diese Nachricht.`,
    };

    await transporter.sendMail(mailOptions);

    res.json({ message: "Passwort-Reset-Link wurde per E-Mail gesendet." });
  } catch (err) {
    console.error(err);
    res.status(500).json({ error: "Interner Serverfehler" });
  }
});

// Reset Abschließen
router.post("/reset/:token", async (req, res) => {
  const { token } = req.params;
  const { password } = req.body;

  if (!password) {
    return res.status(400).json({ error: "Neues Passwort ist erforderlich" });
  }

  try {
    // Token in der Datenbank suchen und prüfen, ob es noch gültig ist
    const result = await pool.query(
      "SELECT id FROM users WHERE reset_password_token = $1 AND reset_password_expires > NOW()",
      [token]
    );

    if (result.rows.length === 0) {
      return res
        .status(400)
        .json({ error: "Ungültiges oder abgelaufenes Token" });
    }

    const userId = result.rows[0].id;

    // Passwort hashen
    const hashedPassword = await bcrypt.hash(password, 10);

    // Passwort speichern und Token-Felder leeren
    await pool.query(
      "UPDATE users SET password = $1, reset_password_token = NULL, reset_password_expires = NULL WHERE id = $2",
      [hashedPassword, userId]
    );

    res.json({ message: "Passwort erfolgreich zurückgesetzt" });
  } catch (err) {
    console.error(err);
    res.status(500).json({ error: "Interner Serverfehler" });
  }
});

// Email und/oder Passwort ändern
router.post("/update", requireAuth, async (req, res) => {
  const { email, password } = req.body;
  try {
    if (email) {
      await pool.query("UPDATE users SET email = $1 WHERE id = $2", [
        email,
        req.user.id,
      ]);
    }
    if (password) {
      const hashedPassword = await bcrypt.hash(password, 10);
      await pool.query("UPDATE users SET password = $1 WHERE id = $2", [
        hashedPassword,
        req.user.id,
      ]);
    }
    res.json({
      message: "Benutzerdaten erfolgreich aktualisiert",
    });
  } catch (error) {
    console.error("Error updating profile:", error);
    const message = "Error updating profile:" + error;
    res.status(400).json({ error: "Keine Änderungen vorgenommen" });
  }
});

// Liste der User mit Rollen und is_active
router.get("/admin", requireAuth, requireAdmin, async (req, res) => {
  try {
    // 1️⃣ Alle Benutzer abfragen:
    const usersResult = await pool.query(
      "SELECT id, username, email, is_active FROM users ORDER BY is_active ASC"
    );

    const users = usersResult.rows;

    // 2️⃣ Alle Rollen pro User abfragen:
    const rolesResult = await pool.query(
      `SELECT ur.fid_user, ur.fid_abteilung, ur.fid_role, r.role 
       FROM userrights ur
       JOIN userroles r ON ur.fid_role = r.id`
    );

    // 3️⃣ Rollen für Benutzer gruppieren:
    const userRolesMap = {};
    rolesResult.rows.forEach((row) => {
      if (!userRolesMap[row.fid_user]) {
        userRolesMap[row.fid_user] = [];
      }
      userRolesMap[row.fid_user].push({
        abteilung: row.fid_abteilung,
        role_id: row.fid_role,
        role_name: row.role,
      });
    });

    // 4️⃣ Benutzer + Rollen zusammenführen:
    const enrichedUsers = users.map((user) => ({
      ...user,
      roles: userRolesMap[user.id] || [],
    }));

    res.json(enrichedUsers);
  } catch (err) {
    console.error(err);
    res.status(500).json({ error: "Interner Serverfehler" });
  }
});

router.put("/activate/:id", requireAuth, requireAdmin, async (req, res) => {
  const { id } = req.params;

  try {
    // Benutzer-Daten abrufen (inklusive E-Mail und Benutzername)
    const userResult = await pool.query(
      "SELECT username, email FROM users WHERE id = $1",
      [id]
    );

    if (userResult.rows.length === 0) {
      return res.status(404).json({ error: "Benutzer nicht gefunden" });
    }

    const { username, email } = userResult.rows[0];

    // Benutzer aktivieren
    const result = await pool.query(
      "UPDATE users SET is_active = true WHERE id = $1 RETURNING id, username, is_active",
      [id]
    );

    if (result.rows.length === 0) {
      return res.status(404).json({ error: "Benutzer nicht gefunden" });
    }

    // E-Mail senden (wenn vorhanden)
    await sendActivationEmail(email, username);

    res.json({
      message: "Benutzer erfolgreich aktiviert",
      user: result.rows[0],
    });
  } catch (err) {
    console.error(err);
    res.status(500).json({ error: "Interner Serverfehler" });
  }
});

router.put(
  "/rights/:userId/:role",
  requireAuth,
  requireRole(2),
  async (req, res) => {
    const { userId, role } = req.params;
    const abteilung = req.abteilung; // Abteilung aus Middleware

    if (!abteilung || !role) {
      return res
        .status(400)
        .json({ error: "Abteilung und Rolle müssen angegeben werden" });
    }

    try {
      // Prüfen, ob bereits ein Recht für User & Abteilung existiert
      const existing = await pool.query(
        `SELECT id FROM userrights WHERE fid_user = $1 AND fid_abteilung = $2`,
        [userId, abteilung]
      );

      if (existing.rows.length > 0) {
        // Eintrag existiert → UPDATE
        await pool.query(`UPDATE userrights SET fid_role = $1 WHERE id = $2`, [
          role,
          existing.rows[0].id,
        ]);
      } else {
        // Kein Eintrag → INSERT
        await pool.query(
          `INSERT INTO userrights (fid_user, fid_abteilung, fid_role) VALUES ($1, $2, $3)`,
          [userId, abteilung, role]
        );
      }

      res.json({ message: "Rolle erfolgreich vergeben/geändert" });
    } catch (err) {
      console.error(err);
      res.status(500).json({ error: "Interner Serverfehler" });
    }
  }
);

router.delete("/:id", requireAuth, requireAdmin, async (req, res) => {
  const { id } = req.params;

  try {
    // Prüfen, ob der Benutzer existiert
    const userResult = await pool.query(
      "SELECT id, username FROM users WHERE id = $1",
      [id]
    );

    if (userResult.rows.length === 0) {
      return res.status(404).json({ error: "Benutzer nicht gefunden" });
    }

    // Verhindern, dass sich Admins selbst löschen
    if (req.user.id == id) {
      return res
        .status(400)
        .json({ error: "Ein Admin kann sich nicht selbst löschen" });
    }

    // Benutzer löschen
    await pool.query("DELETE FROM users WHERE id = $1", [id]);

    res.json({
      message: "Benutzer erfolgreich gelöscht",
      user: userResult.rows[0],
    });
  } catch (err) {
    console.error(err);
    res.status(500).json({ error: "Interner Serverfehler" });
  }
});

// User zu Admins machen
router.put("/admin/:id", requireAuth, requireAdmin, async (req, res) => {
  const { id } = req.params;
  const { temporary } = req.body; // erwartet { "temporary": true } oder { "temporary": false }

  if (temporary === undefined) {
    return res.status(400).json({
      error: "Es muss angegeben werden, ob der Admin-Zugang temporär sein soll",
    });
  }

  try {
    let query, values;

    if (temporary) {
      query = `
                UPDATE users 
                SET role = 'admin', admin_temp = NOW() + INTERVAL '48 hours' 
                WHERE id = $1 RETURNING id, username, role, admin_temp
            `;
      values = [id];
    } else {
      query = `
                UPDATE users 
                SET role = 'admin', admin_temp = NULL 
                WHERE id = $1 RETURNING id, username, role, admin_temp
            `;
      values = [id];
    }

    const result = await pool.query(query, values);

    if (result.rows.length === 0) {
      return res.status(404).json({ error: "Benutzer nicht gefunden" });
    }

    res.json({
      message: "Benutzer wurde zum Admin gemacht",
      user: result.rows[0],
    });
  } catch (err) {
    console.error(err);
    res.status(500).json({ error: "Interner Serverfehler" });
  }
});

module.exports = router;
