
const express = require("express");
const mysql = require("mysql2/promise");
const bcrypt = require("bcryptjs");
const cors = require("cors");
const config = require("./change.js");

const app = express();
app.use(express.json());
app.use(cors());

let pool;

async function initDB() {
  let connection;
  try {
    connection = await mysql.createConnection({ ...config.dbConfig });
  } catch (err) {
    console.error("❌ CRITICAL: Could not reach local database service matrix!", err.message);
    process.exit(1);
  }

  await connection.query(`CREATE DATABASE IF NOT EXISTS \`${config.dbName}\``);
  await connection.end();

  pool = mysql.createPool({ ...config.dbConfig, database: config.dbName });

  if (config.resetDatabaseOnStart) {
    try {
      await pool.query("SET FOREIGN_KEY_CHECKS = 0;");
      for (const name of Object.keys(config.tables)) {
        await pool.query(`DROP TABLE IF EXISTS \`${name}\``);
      }
    } finally {
      await pool.query("SET FOREIGN_KEY_CHECKS = 1;");
    }
  }

  for (const [tableName, tableSchema] of Object.entries(config.tables)) {
    let queryStr = `CREATE TABLE IF NOT EXISTS \`${tableName}\` (\`${tableSchema.id_field}\` VARCHAR(50) PRIMARY KEY`;
    
    for (const [fieldName, fieldType] of Object.entries(tableSchema.fields)) {
      queryStr += `, \`${fieldName}\` ${fieldType}`;
    }

    if (tableSchema.foreignKeys) {
      tableSchema.foreignKeys.forEach(fk => {
        queryStr += `, FOREIGN KEY (\`${fk.field}\`) REFERENCES \`${fk.referenceTable}\`(\`${fk.referenceField}\`) ON DELETE CASCADE ON UPDATE CASCADE`;
      });
    }
    queryStr += `) ENGINE=InnoDB;`;
    await pool.query(queryStr);
  }

  await pool.query(`
    CREATE TABLE IF NOT EXISTS \`User\` (
      \`id\` INT AUTO_INCREMENT PRIMARY KEY,
      \`username\` VARCHAR(50) UNIQUE NOT NULL,
      \`password\` VARCHAR(255) NOT NULL
    ) ENGINE=InnoDB;
  `);
}

app.post("/api/auth/register", async (req, res) => {
  const { username, password } = req.body;
  try {
    const hashed = await bcrypt.hash(password, 10);
    await pool.query("INSERT INTO User (username, password) VALUES (?, ?)", [username, hashed]);
    res.json({ success: true });
  } catch (err) { res.status(500).json({ error: err.message }); }
});

app.post("/api/auth/login", async (req, res) => {
  const { username, password } = req.body;
  try {
    const [rows] = await pool.query("SELECT * FROM User WHERE username = ?", [username]);
    if (rows.length && await bcrypt.compare(password, rows[0].password)) {
      return res.json({ success: true, username: rows[0].username });
    }
    res.status(401).json({ error: "Invalid operational access credentials." });
  } catch (err) { res.status(500).json({ error: err.message }); }
});

app.get("/api/data/all", async (req, res) => {
  try {
    const pack = {};
    for (const name of Object.keys(config.tables)) {
      const [rows] = await pool.query(`SELECT * FROM \`${name}\``);
      pack[name] = rows;
    }
    res.json(pack);
  } catch (err) { res.status(500).json({ error: err.message }); }
});

app.get("/api/data/:table", async (req, res) => {
  try {
    const [rows] = await pool.query(`SELECT * FROM \`${req.params.table}\``);
    res.json(rows);
  } catch (err) { res.status(500).json({ error: err.message }); }
});

app.post("/api/data/:table", async (req, res) => {
  const { table } = req.params;
  const fields = Object.keys(req.body);
  const values = Object.values(req.body);
  try {
    const cols = fields.map(f => `\`${f}\``).join(", ");
    const placeholders = fields.map(() => "?").join(", ");
    await pool.query(`INSERT INTO \`${table}\` (${cols}) VALUES (${placeholders})`, values);
    res.json({ success: true });
  } catch (err) { res.status(500).json({ error: err.message }); }
});

app.put("/api/data/:table/:idField/:id", async (req, res) => {
  const { table, idField, id } = req.params;
  if (table === "Supplier") return res.status(403).json({ error: "Modifications on Supplier rows are forbidden by exam criteria." });
  
  const fields = Object.keys(req.body);
  const values = Object.values(req.body);
  try {
    const clauses = fields.map(f => `\`${f}\` = ?`).join(", ");
    await pool.query(`UPDATE \`${table}\` SET ${clauses} WHERE \`${idField}\` = ?`, [...values, id]);
    res.json({ success: true });
  } catch (err) { res.status(500).json({ error: err.message }); }
});

app.delete("/api/data/:table/:idField/:id", async (req, res) => {
  const { table, idField, id } = req.params;
  if (table === "Supplier") return res.status(403).json({ error: "Deletions on Supplier rows are forbidden by exam criteria." });
  
  try {
    await pool.query(`DELETE FROM \`${table}\` WHERE \`${idField}\` = ?`, [id]);
    res.json({ success: true });
  } catch (err) { res.status(500).json({ error: err.message }); }
});
app.put("/api/data/:table/:idField/:id", async (req, res) => {
  const { table, idField, id } = req.params;
  
  if (table === "Supplier") {
    return res.status(403).json({ error: "Modifications on Supplier rows are forbidden by exam criteria." });
  }
  
  const fields = Object.keys(req.body);
  const values = Object.values(req.body);
  try {
    const clauses = fields.map(f => `\`${f}\` = ?`).join(", ");
    await pool.query(`UPDATE \`${table}\` SET ${clauses} WHERE \`${idField}\` = ?`, [...values, id]);
    res.json({ success: true });
  } catch (err) { res.status(500).json({ error: err.message }); }
});

app.delete("/api/data/:table/:idField/:id", async (req, res) => {
  const { table, idField, id } = req.params;
  
  if (table === "Supplier") {
    return res.status(403).json({ error: "Deletions on Supplier rows are forbidden by exam criteria." });
  }
  
  try {
    await pool.query(`DELETE FROM \`${table}\` WHERE \`${idField}\` = ?`, [id]);
    res.json({ success: true });
  } catch (err) { res.status(500).json({ error: err.message }); }
});

app.get("/api/meta/count/:table", async (req, res) => {
  const { table } = req.params;
  
  if (!config.tables[table] && table !== 'User') {
    return res.status(404).json({ error: "Table not found in matrix config." });
  }
  
  try {
    const [rows] = await pool.query(`SELECT COUNT(*) as total FROM \`${table}\``);
    
    const resultCount = rows[0].total || 0;
    
    res.json({ 
      table, 
      count: resultCount 
    });
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

app.get("/api/data-view/:table", async (req, res) => {
  const { table } = req.params;
  const tableSchema = config.tables[table];
  
  if (!tableSchema) return res.status(404).json({ error: "Table not defined." });

  try {
    let selectClause = `t1.*`;
    let joinClause = "";

    if (tableSchema.foreignKeys) {
      tableSchema.foreignKeys.forEach((fk, index) => {
        const alias = `ref${index}`;
        selectClause += `, ${alias}.*`; 
        joinClause += ` LEFT JOIN \`${fk.referenceTable}\` ${alias} ON t1.\`${fk.field}\` = ${alias}.\`${fk.referenceField}\``;
      });
    }

    const queryStr = `SELECT ${selectClause} FROM \`${table}\` t1 ${joinClause}`;
    const [rows] = await pool.query(queryStr);
    res.json(rows);
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

app.get("/api/search/:table", async (req, res) => {
  const { table } = req.params;
  const { q } = req.query; 
  const tableSchema = config.tables[table];

  if (!tableSchema || !q) return res.status(400).json({ error: "Invalid search request." });

  try {
    const fieldNames = Object.keys(tableSchema.fields);
    fieldNames.push(tableSchema.id_field);

    const whereClauses = fieldNames.map(f => `\`${f}\` LIKE ?`).join(" OR ");
    const values = fieldNames.map(() => `%${q}%`);

    const [rows] = await pool.query(`SELECT * FROM \`${table}\` WHERE ${whereClauses}`, values);
    res.json(rows);
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});
app.post("/api/data/:table", async (req, res) => {
  const { table } = req.params;
  const fields = Object.keys(req.body);
  const values = Object.values(req.body);
  try {
    const cols = fields.map(f => `\`${f}\``).join(", ");
    const placeholders = fields.map(() => "?").join(", ");
    await pool.query(`INSERT INTO \`${table}\` (${cols}) VALUES (${placeholders})`, values);
    res.json({ success: true });
  } catch (err) { res.status(500).json({ error: err.message }); }
});

app.put("/api/data/:table/:idField/:id", async (req, res) => {
  const { table, idField, id } = req.params;
  
  if (table === "Supplier") {
    return res.status(403).json({ error: "Modifications on Supplier rows are forbidden by exam criteria." });
  }
  
  const fields = Object.keys(req.body);
  const values = Object.values(req.body);
  try {
    const clauses = fields.map(f => `\`${f}\` = ?`).join(", ");
    await pool.query(`UPDATE \`${table}\` SET ${clauses} WHERE \`${idField}\` = ?`, [...values, id]);
    res.json({ success: true });
  } catch (err) { res.status(500).json({ error: err.message }); }
});

app.delete("/api/data/:table/:idField/:id", async (req, res) => {
  const { table, idField, id } = req.params;
  
  if (table === "Supplier") {
    return res.status(403).json({ error: "Deletions on Supplier rows are forbidden by exam criteria." });
  }
  
  try {
    await pool.query(`DELETE FROM \`${table}\` WHERE \`${idField}\` = ?`, [id]);
    res.json({ success: true });
  } catch (err) { res.status(500).json({ error: err.message }); }
});

app.get("/api/data-view/:table", async (req, res) => {
  const { table } = req.params;
  const tableSchema = config.tables[table];
  
  if (!tableSchema) return res.status(404).json({ error: "Table not defined in config." });

  try {
    let selectClause = `t1.*`;
    let joinClause = "";

    if (tableSchema.foreignKeys) {
      tableSchema.foreignKeys.forEach((fk, index) => {
        const alias = `ref${index}`;
        selectClause += `, ${alias}.*`; 
        joinClause += ` LEFT JOIN \`${fk.referenceTable}\` ${alias} ON t1.\`${fk.field}\` = ${alias}.\`${fk.referenceField}\``;
      });
    }

    const queryStr = `SELECT ${selectClause} FROM \`${table}\` t1 ${joinClause}`;
    const [rows] = await pool.query(queryStr);
    
    res.json(rows);
  } catch (err) {
    console.error("Database Join Error:", err.message);
    res.status(500).json({ error: "Relational data fetch failed." });
  }
});
 
app.get("/api/meta/count/:table", async (req, res) => {
  const { table } = req.params;
  try {
    const [rows] = await pool.query(`SELECT COUNT(*) as total FROM \`${table}\``);
    res.json({ table, count: rows[0].total || 0 });
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

initDB().then(() => app.listen(5000, () => console.log("📡 SCMS CORE ACTIVE ON PORT 5000")));

