// server.js
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() {
  console.log("🔄 Step 1: Attempting initial connection to MySQL server...");
  let connection;
  try {
    connection = await mysql.createConnection({
      ...config.dbConfig,
      connectTimeout: 5000
    });
    console.log("✅ Verified: Stock Management MySQL Server database module is online.");
  } catch (err) {
    console.error("\n❌ CRITICAL ERROR: Could not establish communication with server engine!");
    console.error("👉 Please verify that your local MySQL service controller is actively running.");
    process.exit(1);
  }

  try {
    await connection.query(`CREATE DATABASE IF NOT EXISTS \`${config.dbName}\``);
    await connection.end();
    console.log(`✅ Database target checked/created: "${config.dbName}"`);

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

    if (config.resetDatabaseOnStart) {
      console.log("⚠️ Reset flag is ON. Wiping existing tables for schema refresh...");
      try {
        await pool.query("SET FOREIGN_KEY_CHECKS = 0;");
        const tNames = Object.keys(config.tables);
        for (const name of tNames) {
          await pool.query(`DROP TABLE IF EXISTS \`${name}\``);
          console.log(`  🗑️ Dropped table: ${name}`);
        }
        console.log("✅ Teardown phase successful.");
      } catch (dropErr) {
        console.error("❌ Teardown processing failure:", dropErr.message);
      } finally {
        await pool.query("SET FOREIGN_KEY_CHECKS = 1;");
      }
    }

    console.log("🔄 Step 2: Syncing database tables and structures...");
    for (const [tableName, tableSchema] of Object.entries(config.tables)) {
      let queryStr = `CREATE TABLE IF NOT EXISTS \`${tableName}\` (`;
      
      if (
        tableName.toLowerCase().includes("record") || 
        tableName.toLowerCase().includes("payment") || 
        tableName.toLowerCase().includes("inbound") || 
        tableName.toLowerCase().includes("order") || 
        tableSchema.id_field === "id"
      ) {
        queryStr += `\`${tableSchema.id_field}\` INT AUTO_INCREMENT PRIMARY KEY`;
      } else {
        queryStr += `\`${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);
    }
    console.log("✅ Tables verified and built successfully.");

    // --- AUTOMATED DATA SEEDER ENGINE ---
    const availableTables = Object.keys(config.tables);
    const seedTargetTable = availableTables.find(t => t === "Products" || t === "Services") || availableTables[1];

    if (seedTargetTable) {
      const [rows] = await pool.query(`SELECT COUNT(*) as count FROM \`${seedTargetTable}\``);
      if (rows[0].count === 0 && config.defaultServices) {
        console.log(`🌱 Seeding initial core datasets into catalog table [${seedTargetTable}]...`);
        
        for (const item of config.defaultServices) {
          let insertQuery = "";
          let payloadData = [];

          if (seedTargetTable === "Products") {
            insertQuery = `INSERT INTO \`Products\` (\`ProductCode\`, \`ProductName\`, \`Category\`, \`UnitPrice\`) VALUES (?, ?, ?, ?)`;
            payloadData = item.length === 4 ? item : [item[0], item[1], "General Stock", item[2]];
          } else {
            insertQuery = `INSERT INTO \`Services\` (\`ServiceCode\`, \`ServiceName\`, \`ServicePrice\`) VALUES (?, ?, ?)`;
            payloadData = item;
          }

          await pool.query(insertQuery, payloadData);
        }
        console.log(`✅ Default values successfully established inside system database.`);
      }
    }

  } catch (err) {
    console.error("❌ SQL Schema Build Error encountered:", err.message);
    process.exit(1);
  }
}

// --- API MATRIX ENDPOINTS ---
app.post("/api/auth/register", async (req, res) => {
  const { username, password } = req.body;
  if (!username || !password) return res.status(400).json({ error: "All input metrics required." });
  try {
    const hashedPassword = await bcrypt.hash(password, 10);
    await pool.query("INSERT INTO User (username, password) VALUES (?, ?)", [username, hashedPassword]);
    res.json({ success: true, message: "User profile successfully generated." });
  } catch (err) {
    res.status(500).json({ error: "Internal encryption registration process failure." });
  }
});

app.post("/api/auth/login", async (req, res) => {
  const { username, password } = req.body;
  try {
    const [users] = await pool.query("SELECT * FROM User WHERE username = ?", [username]);
    if (users.length === 0) return res.status(401).json({ error: "Invalid account values matched." });
    
    const isMatch = await bcrypt.compare(password, users[0].password);
    if (!isMatch) return res.status(401).json({ error: "Invalid account values matched." });

    res.json({ success: true, username: users[0].username });
  } catch (err) {
    res.status(500).json({ error: "Server authentication validation process error." });
  }
});

app.get("/api/data/all", async (req, res) => {
  try {
    const dataPackage = {};
    for (const tableName of Object.keys(config.tables)) {
      const [rows] = await pool.query(`SELECT * FROM \`${tableName}\``);
      dataPackage[tableName] = rows;
    }
    res.json(dataPackage);
  } 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 });
  }
});

// --- AUTOMATED STOCK UPDATE INBOUND POST METHOD INTERCEPTOR ---
app.post("/api/data/:table", async (req, res) => {
  const { table } = req.params;
  const fields = Object.keys(req.body);
  const values = Object.values(req.body);
  if (fields.length === 0) return res.status(400).json({ error: "No payload dataset parsed." });

  // Get a standalone database connection for atomicity protection
  const connection = await pool.getConnection();
  try {
    await connection.beginTransaction();

    const cols = fields.map(f => `\`${f}\``).join(", ");
    const placeholders = fields.map(() => "?").join(", ");
    const query = `INSERT INTO \`${table}\` (${cols}) VALUES (${placeholders})`;
    
    await connection.query(query, values);

    // ✅ AUTOMATION: If someone posts to StockInbound, automatically increment the Product stock
    if (table === "StockInbound") {
      const targetProductCode = req.body.ProductCode;
      const inboundQuantity = Number(req.body.QuantityReceived || req.body.Quantity || 0);

      if (targetProductCode && inboundQuantity > 0) {
        const updateStockQuery = `
          UPDATE \`Products\` 
          SET \`CurrentStock\` = COALESCE(\`CurrentStock\`, 0) + ? 
          WHERE \`ProductCode\` = ?
        `;
        await connection.query(updateStockQuery, [inboundQuantity, targetProductCode]);
      }
    }

    // ✅ AUTOMATION: If someone posts a SalesOrder, automatically decrement the Product stock
    if (table === "SalesOrder") {
      const targetBatchNumber = req.body.BatchNumber;
      const soldQuantity = Number(req.body.QuantitySold || 0);

      if (targetBatchNumber && soldQuantity > 0) {
        // Find which product this batch belongs to
        const [batches] = await connection.query(
          "SELECT `ProductCode` FROM `StockInbound` WHERE `BatchNumber` = ?", 
          [targetBatchNumber]
        );
        
        if (batches.length > 0) {
          const productCode = batches[0].ProductCode;
          const reduceStockQuery = `
            UPDATE \`Products\` 
            SET \`CurrentStock\` = GREATEST(0, COALESCE(\`CurrentStock\`, 0) - ?) 
            WHERE \`ProductCode\` = ?
          `;
          await connection.query(reduceStockQuery, [soldQuantity, productCode]);
        }
      }
    }

    await connection.commit();
    res.json({ success: true });
  } catch (err) {
    await connection.rollback();
    res.status(500).json({ error: err.message });
  } finally {
    connection.release();
  }
});

app.put("/api/data/:table/:idField/:id", async (req, res) => {
  const { table, idField, id } = req.params;
  
  if (table !== "ServiceRecord" && table !== "StockInbound" && table !== "SalesOrder") {
    return res.status(403).json({ error: `Operation Forbidden. Updates are not permitted on ${table}.` });
  }

  const fields = Object.keys(req.body);
  const values = Object.values(req.body);

  try {
    const setClause = fields.map(f => `\`${f}\` = ?`).join(", ");
    const query = `UPDATE \`${table}\` SET ${setClause} WHERE \`${idField}\` = ?`;
    await pool.query(query, [...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 !== "ServiceRecord" && table !== "StockInbound" && table !== "SalesOrder") {
    return res.status(403).json({ error: `Operation Forbidden. Deletions are not permitted on ${table}.` });
  }

  try {
    await pool.query(`DELETE FROM \`${table}\` WHERE \`${idField}\` = ?`, [id]);
    res.json({ success: true });
  } catch (err) {
    res.status(500).json({ error: err.message });
  }
});

const PORT = 5000;
initDB().then(() => {
  app.listen(PORT, () => {
    console.log(`\n================================================================`);
    console.log(`📡 CORE SYSTEM ENGINE: ACTIVE! server.js listening on port ${PORT}`);
    console.log(`================================================================\n`);
  });
});