// ==== INSTALLASI MENGGUNAKAN SEQUELIZE / SEQUELIZE-CLI ==== //
    
    1. npm init -y ( ini untuk mulai menggunakan node.js atau membuat project node.js = auto generate package.json )
    2. npm install -D nodemon sequelize-cli ( ini instalasi untuk menjalankan nodemon agar apliaksi bisa menjalankan server tanpa harus hidup dan di matikan maka dia otomatis )
    3. npm install Dependencies : 

        == PRODUCTION DEPS ==
        * express ( ini untuk framework backend untuk buat API & Routing )
        * sequelize ( ini ORM untuk query Database tanpa SQL manual )
        * mysql2 ( ini driver untuk koneksi ke Database MySQL )
        * dotenv ( ini untuk menyimpan config rahasia ( .env ) seperti DB & JWT )
        * cors ( ini untuk mengizinkan akses API dari frontend yang beda domain )
        * jsonwebtoken ( ini untuk membuat & verifikasi token login ( auth ) )
        * bcryptjs ( ini untuk enkripsi / hash password )
        * morgan ( ini untuk logger request API ( monitoring di terminal ) )
        * uuid ( ini untuk generate ID unik ( opsional selain auto increment ) )
        * express-validator ( ini untuk validasi input user ( email, password, dll ) )
        * helmet ( ini untuk menambahkan keamanan HTTP headers )
        * body-parser ( ini untuk parsing request body ( JSON, from ) yang sudah built-in adalah: express.json()  )
        * compression ( ini untuk compress response biar lebih cepat )
        * multer ( ini untuk upload file ( gambar, dokumen, dll ) )
        * express-async-errors ( ini untuk tidak try cath lagi di semua controller ( auto handle async error ) )
        * winston ( ini untuk logger lebih powerfull dari morgan ( bisa simpan ke file ) )
        * dayjs ( ini untuk format tanggal / waktu ( misalnya di transksi ) )
        * joi ( ini untuk validasi schema ( env atau request body lebih rapih ) )
        * sequelize-paginate ( ini untuk biar gampang atau memudahkan bikin pagination API )
        * cookie-parser ( ini untuk ambil cookie dari request ( kalu pakai auth berbasis cookie) )
        * express-rate-limit ( ini untuk membatasi request ( anti spam / brute force ) )
        * xss-clean ( ini untuk menghindari XSS attack ( input berbahaya ) )
        * hpp ( ini untuk melindungi dari HTTP parameter pollution  )
        * dotenv-expand ( ini untuk .env biar bisa pakai variable lain )
        * dotenv-flow ( ini untuk multi environment ( .env.development, .env.production ) )
        * cls-hooked ( ini untuk auto handle transaction context ( advanced ) )
        * swagger-ui-express ( ini untuk dokumentasi API ( nilai plus kalo misal di tanyain dokumentasi ) )
        * axios ( ini untuk di pakai call API lain )
        * nodemailer ( ini untuk reset password / kirim email )
        * dotenv-safe ( ini untuk memastikan .env ada )
        * chalk ( ini untuk warna console.log ( biar keliatan clean ) )

        == DEV DEPS ( -D ) ==
        * nodemon ( ini instalasi untuk menjalankan nodemon agar apliaksi bisa menjalankan server tanpa harus hidup dan di matikan maka dia otomatis )
        * sequelize-cli ( ini untuk tool CLI untuk migration, seeder, dan model )
        * -D cross-env ( ini untuk set environment variable di script ( Windows / Linux yang berbeda) )
        * -D eslint prettier ( ini untuk membuat atau biar code makin rapih ( kalo kelihatan niat ini adalah nilai plus ) )
        * -D dotenv-cli ( ini untuk run envdi script )
        * -D debug ( ini untuk logging ringan buat development )

        == BUILT-IN ==
        * crypto / built-in node.js ( ini untuk generate token / random string ( kadang di pakai reset password ) )
        * fs / File System ( ini untuk handle file upload / delete file ( dipakai bareng multer ) )
        * path ( ini untuk handle path biar aman ( upload, dll ) )


        NOTES : == CORE ==
                 * express
                 * sequelize
                 * mysql2

                == AUTH ==
                 * JWT ( jsonwebtoken)
                 * bcrypt / bcryptjs

                == CONFIG ==
                 * dotenv

                == SUPPORT ==
                 * cors
                 * morgan

                == VALIDASI ==
                 * express-validator
                 * joi

                == SECURITY ==
                 * helmet
                 * express-rate-limit
                 * xss-clean
                 * hpp
                
                == FILE & UTIL ==
                 * multer 
                 * uuid
                 * fs ( built-in )
                 * path ( built-in )

                == PERFORMANCE ==
                 * compression

                == LOGGER PRO ==
                 * winston

                == ERROR HANDLING ==
                 * express-async-errors

                == OPTIONAL ( ADVANCED )
                 * dayjs
                 * cookie-parser



// ==== SORTCUT UNTUK SEQUELIZE ( MIGRATION, SEEDER, MODEL DLL ) ==== //    
    
    1. npx sequelize-cli init ( ini untuk memulai menggunakan sequelize-cli / atau membuat struktur folder( pattern ) menggunakan sequelizerc  )
    2. npx sequelize-cli model:generate --name User --attributes name:string,email:string ( ini untuk membuat migration dan model secara generate langsung )
    3. npx sequelize-cli migration:generate --name create-orders ( ini untuk membuat migration nya saja )
    4. npx sequelize-cli seed:generate --name seed-users( ini untuk membuat seeder nya saja )
    5. npx sequelize-cli db:migrate ( ini untuk menjalankan migration yang sudah jadi )
    6. npx sequelize-cli db:migrate:undo ( ini untuk menjalankan undo atau mengambil data migration satu-satu atau mundur satu langkah kebelakang )
    7. npx sequelize-cli db:migrate:undo:all ( ini untuk menjalankan migration yang di undo atau di ambil kembali )
    8. npx sequelize-cli db:seed ( ini untuk menjalankan seeder satu-satu )
    9. npx sequelize-cli db:seed:all ( ini untuk menjalankan seeder secara keseluruhan atau semua seedernya )
    10. npx sequelize-cli db:seed:undo ( ini untuk menjalankan undo atau mengambil seeder kembali secara satu-satu )
    11. npx sequelize-cli db:seed:undo:all ( ini untuk menjalankan undo atau mengambil seeder kembali secara keseluruhan atau semuanya )
    12. npx sequelize-cli db:drop ( ini untuk menghapus Database = "reset total, semua data hilang" )
    13. npx sequelize-cli db:create ( ini untuk membuat ulang Database yang kosong )
    14. npx sequelize-cli model:generate --name User ( ini untuk menjalankan atau membuat model secara manual atau tidak generate )
    15. npx sequelize-cli db:seed --seed nama-file-seeder.js ( ini untuk menjalankan seeder secara spesifik = penting kalo cuma mau inject 1 data seeder saja )
    16. npx sequelize-cli db:migrate:status ( ini untuk menjalankan atau mengecek migration mana yang sudah berjalan / belum dijalankan )
    17. npx sequelize-cli db:drop && \ ( ini untuk hapus total Database atau reset total )
    18. npx sequelize-cli db:create && \ ( ini untuk hapus total Database atau reset total yang sudah di buat )
    19. npx sequelize-cli db:migrate && \ ( ini untuk hapus total Database atau reset total yang sudah dijalankan migration )
    20. npx sequelize-cli migration:generate --name add-role-to-users ( ini untuk menjalankan atau menambahkan kolom di migration )
    
    NOTES: == INIT ==
            * init

           == GENERATE ==
            * model + migration
            * migration saja
            * model saja
            * seeder saja

           == MIGRATION ==
            * migrate
            * undo
            * undo:all
            * status

           == SEEDER ==
            * seed
            * seed:all
            * seed:undo
            * seed:undo:all

           == DATABASE ==
            * drop
            * create

           == ADVANCED ==
            * addColumn
            * removeColumn
            * renameColumn

           == COMBO ==
            * reset total ( drop -> create -> migrate -> seed ) 

// =========================================================================================

// =========================================================================================

// ======================================== ENV ============================================

DB_NAME=api_sekolah
DB_USERNAME=mildan
DB_PASSWORD=123456
DB_DIALECT=mysql
DB_HOST=localhost
JWT_SECRET=petikschool
JWT_EXPIRES_IN=1d

// ======================================== SEQUELIZE RC ===================================

const path = require("path");

module.exports = {
  config: path.resolve("src", "config", "database.js"),
  "models-path": path.resolve("src", "db", "models"),
  "seeders-path": path.resolve("src", "db", "seeders"),
  "migrations-path": path.resolve("src", "db", "migrations"),
};

// ======================================== DATABASE.JS ( CONFIG ) =========================

require('dotenv').config();

module.exports = {
  "development": {
    "username": process.env.DB_USERNAME,
    "password": process.env.DB_PASSWORD,
    "database": process.env.DB_NAME,
    "host": process.env.DB_HOST,
    "dialect": process.env.DB_DIALECT
  },
  "test": {
    "username": "root",
    "password": null,
    "database": "database_test",
    "host": "127.0.0.1",
    "dialect": "mysql"
  },
  "production": {
    "username": "root",
    "password": null,
    "database": "database_production",
    "host": "127.0.0.1",
    "dialect": "mysql"
  }
}


// ======================================== KONEKSI.JS ====================================

const { Sequelize } = require("sequelize");
const config = require("./database.js").development;

const sequelize = new Sequelize(
  config.database,
  config.username,
  config.password,
  {
    host: config.host,
    dialect: config.dialect,
    logging: false,
  },
);

module.exports = sequelize;

// ======================================== APP.JS ===========================================

require("dotenv").config()

const express = require("express")
const app = express()

const sequelize = require("./config/koneksi.js")
const cors = require("cors")

app.use(cors({
  origin: [
    "http://localhost:5173",
    "http://localhost:5174",
    "http://localhost:5175"
  ],
  methods: ['GET', 'POST', 'PUT', 'DELETE'],
  allowedHeaders: ['Content-Type', 'Authorization']
}));

/*
MIDDLEWARE
*/
app.use(express.json())

/*
IMPORT ROUTES
*/
const adminRoutes = require("./modules/admin/routes.js")
const guruRoutes = require("./modules/guru/routes.js");
const siswaRoutes = require("./modules/siswa/routes.js");
const dashboardAdminRoutes = require("./modules/dashboards/dashboardAdmin/routes.js");
const dashboardGuruRoutes = require("./modules/dashboards/dashboardGuru/routes.js");
const dashboardSiswaRoutes = require("./modules/dashboards/dashboardSiswa/routes.js");
const mapelRoutes = require("./modules/mapel/routes.js");
const absensiRoutes = require("./modules/absensi/routes.js");
const jadwalRoutes = require("./modules/jadwal/routes.js");
const nilaiRoutes = require("./modules/nilai/routes.js");
const pengumumanRoutes = require("./modules/pengumuman/routes.js");
const kelasRoutes = require("./modules/kelas/routes.js");
const tugasRoutes = require("./modules/tugas/routes.js")
const authRoutes = require("./modules/auth/routes.js")


/*
ROUTES
*/
app.use("/api/admin", adminRoutes)
app.use("/api/guru", guruRoutes)
app.use("/api/siswa", siswaRoutes)
app.use("/api/dashboard/admin", dashboardAdminRoutes)
app.use("/api/dashboard/guru", dashboardGuruRoutes)
app.use("/api/dashboard/siswa", dashboardSiswaRoutes)
app.use("/api/mapel", mapelRoutes);
app.use("/api/absensi", absensiRoutes);
app.use("/api/jadwal", jadwalRoutes);
app.use("/api/nilai", nilaiRoutes);
app.use("/api/pengumuman", pengumumanRoutes);
app.use("/api/kelas", kelasRoutes);
app.use("/api/tugas", tugasRoutes)
app.use("/login", authRoutes)
/*
TEST ROUTE
*/
app.get("/", (req,res)=>{
  res.send("API SEKOLAH RUNNING")
})

async function startServer(){

  try{

    await sequelize.authenticate()

    console.log("Database connected")

    const PORT = process.env.PORT || 3000

    app.listen(PORT,()=>{
      console.log(`Server running on port ${PORT}`)
    })

  }catch(err){

    console.log("Database connection failed:", err)

  }

}

startServer()
// ======================================== DEPENDENSI  =======================================

"dependencies": {
    "bcrypt": "^6.0.0",
    "cors": "^2.8.6",
    "dotenv": "^17.3.1",
    "express": "^5.2.1",
    "express-validator": "^7.3.2",
    "jsonwebtoken": "^9.0.3",
    "multer": "^2.1.1",
    "mysql2": "^3.19.1",
    "nodemon": "^3.1.14",
    "sequelize": "^6.37.8",
    "sequelize-cli": "^6.6.5",
    "uuid": "^13.0.0"
  }

// ======================================== VALIDATOR.JS ============================================

const { validationResult } = require("express-validator")

const validate = (validations) => {
  return async (req, res, next) => {
    await Promise.all(validations.map(v => v.run(req)))

    const errors = validationResult(req)

    if (!errors.isEmpty()) {
      return res.status(400).json({
        message: "Validation error",
        errors: errors.array().map(err => ({
          field: err.path,
          message: err.msg
        }))
      })
    }

    next()
  }
}

module.exports = validate

// ======================================== UPLOADMIDDLEWARE.JS ============================================

const multer = require("multer")
const path = require("path")
const fs = require("fs")

const uploadPath = "uploads/"

// bikin folder kalau belum ada
if (!fs.existsSync(uploadPath)) {
  fs.mkdirSync(uploadPath, { recursive: true })
}

// storage config
const storage = multer.diskStorage({
  destination: (req, file, cb) => {
    cb(null, uploadPath)
  },
  filename: (req, file, cb) => {
    const safeName = file.originalname
      .replace(/\s+/g, "-")
      .replace(/[^a-zA-Z0-9.-]/g, "")

    cb(null, `${Date.now()}-${safeName}`)
  }
})

// filter file
const fileFilter = (req, file, cb) => {
  const allowedMime = [
    "image/jpeg",
    "image/png",
    "application/pdf"
  ]

  const ext = path.extname(file.originalname).toLowerCase()
  const allowedExt = [".jpg", ".jpeg", ".png", ".pdf"]

  if (!allowedMime.includes(file.mimetype) || !allowedExt.includes(ext)) {
    return cb(new Error("File harus JPG, PNG, atau PDF"), false)
  }

  cb(null, true)
}

// multer instance
const upload = multer({
  storage,
  fileFilter,
  limits: {
    fileSize: 2 * 1024 * 1024 // 2MB
  }
})

module.exports = upload