const fs = require('fs')
const path = require('path')
const mariadb = require('mariadb')
require('dotenv').config()

const log = require('./logger')('db')

const pool = mariadb.createPool({
  host: process.env.DB_HOST || '127.0.0.1',
  port: Number(process.env.DB_PORT) || 3306,
  user: process.env.DB_USER || 'root',
  password: process.env.DB_PASSWORD || '',
  database: process.env.DB_NAME || 'runic_gateway',
  connectionLimit: 5,
  // Return plain JS numbers, never BigInt — keeps JSON responses clean.
  insertIdAsNumber: true,
  bigIntAsNumber: true,
  decimalAsNumber: true,
  // The driver defaults to 'local' — silently serializing bound JS Date
  // params using the HOST MACHINE's local offset instead of the DB session's
  // timezone (discovered via the Discord bot's temp_roles.expires_at coming
  // back hours off in dev). 'auto' negotiates the actual session timezone so
  // Date round-trips correctly regardless of host TZ — affects any write of
  // a JS Date param, e.g. botConfig.model.js's last_connected_at.
  timezone: 'auto',
})

/**
 * Run a parameterized query and release the connection.
 * @param {string} sql
 * @param {Array} [params]
 */
async function query(sql, params) {
  const conn = await pool.getConnection()
  try {
    return await conn.query(sql, params)
  } finally {
    conn.release()
  }
}

const SCHEMA_PATH = path.join(__dirname, '..', '..', 'db', 'schema.sql')

/**
 * Create tables if they do not exist. Idempotent. Retries while the DB is still
 * coming up (important under docker-compose even with a healthcheck).
 */
async function ensureSchema({ retries = 10, delayMs = 2000 } = {}) {
  for (let attempt = 1; attempt <= retries; attempt++) {
    try {
      const conn = await pool.getConnection()
      try {
        const sql = fs.readFileSync(SCHEMA_PATH, 'utf8')
        // Strip `--` comments (full-line AND trailing) before splitting — so a
        // leading comment block doesn't get glued onto the statement that follows
        // it, and a `;` inside a trailing comment can't chop a statement in half.
        // Safe because the schema never puts `--` inside a string literal.
        const statements = sql
          .split('\n')
          .map((line) => {
            const i = line.indexOf('--')
            return i === -1 ? line : line.slice(0, i)
          })
          .join('\n')
          .split(';')
          .map((s) => s.trim())
          .filter((s) => s.length > 0)
        for (const statement of statements) {
          await conn.query(statement)
        }
        log.info('schema ensured')
        return
      } finally {
        conn.release()
      }
    } catch (err) {
      if (attempt === retries) throw err
      log.warn(`database not ready, retrying (attempt ${attempt}/${retries})`, {
        code: err.code || err.message,
      })
      await new Promise((r) => setTimeout(r, delayMs))
    }
  }
}

async function close() {
  await pool.end()
}

module.exports = { pool, query, ensureSchema, close }
