import mysql from "mysql2/promise"
import config from "../config.json"

// Connection pool configuration
const poolConfig = {
  host: config.database.host,
  user: config.database.user,
  password: config.database.password,
  database: config.database.database,
  charset: "utf8mb4",
  connectionLimit: 10, // Maximum number of connections in pool
  acquireTimeout: 60000, // Maximum time to wait for a connection (60 seconds)
  timeout: 60000, // Maximum time for a query (60 seconds)
  reconnect: true,
  idleTimeout: 300000, // Close idle connections after 5 minutes
  maxIdle: 5, // Maximum idle connections
  enableKeepAlive: true,
  keepAliveInitialDelay: 0,
}

let pool: mysql.Pool | null = null

// Create connection pool
export function createPool() {
  if (!pool) {
    try {
      pool = mysql.createPool(poolConfig)
      console.log("Database connection pool created successfully")

      // Handle pool events
      pool.on("connection", (connection) => {
        console.log(`New database connection established as id ${connection.threadId}`)
      })

      pool.on("error", (err) => {
        console.error("Database pool error:", err)
        if (err.code === "PROTOCOL_CONNECTION_LOST") {
          console.log("Recreating database pool...")
          pool = null
          createPool()
        }
      })
    } catch (error) {
      console.error("Failed to create database pool:", error)
      throw error
    }
  }
  return pool
}

// Get connection from pool
export async function getConnection(): Promise<mysql.PoolConnection> {
  try {
    const connectionPool = createPool()
    const connection = await connectionPool.getConnection()

    // Set connection timeout
    await connection.query("SET SESSION wait_timeout = 300") // 5 minutes
    await connection.query("SET SESSION interactive_timeout = 300")

    return connection
  } catch (error) {
    console.error("Failed to get database connection:", error)
    throw new Error("Database connection failed")
  }
}

// Execute query with automatic connection management
export async function executeQuery(query: string, params: any[] = []) {
  let connection: mysql.PoolConnection | null = null

  try {
    connection = await getConnection()
    const [results] = await connection.execute(query, params)
    return results
  } catch (error) {
    console.error("Query execution failed:", error)
    console.error("Query:", query)
    console.error("Params:", params)
    throw error
  } finally {
    // Always release connection back to pool
    if (connection) {
      connection.release()
    }
  }
}

// Safe query execution with automatic parameter binding and connection management
export async function safeQuery(query: string, params: any[] = []) {
  try {
    return await executeQuery(query, params)
  } catch (error) {
    console.error("Database query error:", error)
    throw new Error("Database operation failed")
  }
}

// Execute transaction with automatic connection management
export async function executeTransaction(queries: Array<{ query: string; params?: any[] }>) {
  let connection: mysql.PoolConnection | null = null

  try {
    connection = await getConnection()

    // Start transaction
    await connection.beginTransaction()

    const results = []

    // Execute all queries in transaction
    for (const { query, params = [] } of queries) {
      const [result] = await connection.execute(query, params)
      results.push(result)
    }

    // Commit transaction
    await connection.commit()

    return results
  } catch (error) {
    // Rollback transaction on error
    if (connection) {
      try {
        await connection.rollback()
      } catch (rollbackError) {
        console.error("Transaction rollback failed:", rollbackError)
      }
    }

    console.error("Transaction failed:", error)
    throw error
  } finally {
    // Always release connection back to pool
    if (connection) {
      connection.release()
    }
  }
}

// Test database connection and pool health
export async function testConnection() {
  let connection: mysql.PoolConnection | null = null

  try {
    connection = await getConnection()
    await connection.ping()
    console.log("Database connection test successful")
    return true
  } catch (error) {
    console.error("Database connection test failed:", error)
    return false
  } finally {
    if (connection) {
      connection.release()
    }
  }
}

// Get pool statistics
export function getPoolStats() {
  if (!pool) {
    return null
  }

  return {
    totalConnections: pool.pool._allConnections.length,
    freeConnections: pool.pool._freeConnections.length,
    acquiringConnections: pool.pool._acquiringConnections.length,
    connectionLimit: poolConfig.connectionLimit,
  }
}

// Close all connections in pool (for graceful shutdown)
export async function closePool() {
  if (pool) {
    try {
      await pool.end()
      pool = null
      console.log("Database pool closed successfully")
    } catch (error) {
      console.error("Error closing database pool:", error)
    }
  }
}

// Health check for monitoring
export async function healthCheck() {
  let connection: mysql.PoolConnection | null = null

  try {
    const startTime = Date.now()
    connection = await getConnection()

    // Test basic query
    const [result] = await connection.execute("SELECT 1 as health_check")
    const responseTime = Date.now() - startTime

    const stats = getPoolStats()

    return {
      status: "healthy",
      responseTime,
      poolStats: stats,
      timestamp: new Date().toISOString(),
    }
  } catch (error) {
    return {
      status: "unhealthy",
      error: error instanceof Error ? error.message : "Unknown error",
      timestamp: new Date().toISOString(),
    }
  } finally {
    if (connection) {
      connection.release()
    }
  }
}

// Initialize pool on module load
createPool()

// Graceful shutdown handler
process.on("SIGINT", async () => {
  console.log("Received SIGINT, closing database pool...")
  await closePool()
  process.exit(0)
})

process.on("SIGTERM", async () => {
  console.log("Received SIGTERM, closing database pool...")
  await closePool()
  process.exit(0)
})
