import pg from 'pg'
import { useRuntimeConfig } from '#imports'

const { Pool } = pg

let pool: pg.Pool | null = null
let connectionStringLogged = false

function buildConnectionString(): string {
  const config = useRuntimeConfig()
  if (config.postgresUrl) {
    return config.postgresUrl
  }

  // Fallback para entornos locales si no se pasó NUXT_POSTGRES_URL
  const user = process.env.POSTGRES_USER || 'seguidor'
  const password = process.env.POSTGRES_PASSWORD || 'seguidor_password'
  const defaultHost =
    process.env.APP_NAME ? `${process.env.APP_NAME}-postgres` : 'postgres'
  const host = process.env.POSTGRES_HOST || defaultHost
  const port = process.env.POSTGRES_PORT || '5432'
  const db = process.env.POSTGRES_DB || 'seguidor_lotes'
  return `postgres://${user}:${password}@${host}:${port}/${db}`
}

/**
 * Obtiene o crea el pool de conexiones a PostgreSQL.
 * Usa cadena de conexión única para mantener consistencia.
 */
export function getPool(): pg.Pool {
  if (!pool) {
    const connectionString = buildConnectionString()

    if (!connectionStringLogged && process.env.NODE_ENV !== 'production') {
      const masked = connectionString.replace(/:\/\/([^:]+):([^@]+)@/, '://$1:*****@')
      console.log('[db] Usando connectionString:', masked)
      connectionStringLogged = true
    }

    pool = new Pool({
      connectionString,
      max: 10,
      idleTimeoutMillis: 30000,
      connectionTimeoutMillis: 10000,
    })

    pool.on('error', (err) => {
      console.error('Error inesperado en el pool de PostgreSQL:', err)
    })

    if (process.env.NODE_ENV !== 'production') {
      pool.on('connect', () => {
        console.log('Nueva conexión establecida con PostgreSQL')
      })
    }
  }

  return pool
}

/**
 * Ejecuta una query SQL con parámetros.
 */
export async function query<T = any>(
  text: string,
  params?: any[]
): Promise<pg.QueryResult<T>> {
  const start = Date.now()
  const maxRetries = 5

  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    const currentPool = getPool()

    try {
      const result = await currentPool.query<T>(text, params)
      const duration = Date.now() - start

      if (process.env.NODE_ENV !== 'production') {
        console.log('Query ejecutada:', { text, duration: `${duration}ms`, rows: result.rowCount })
      }

      return result
    } catch (error: any) {
      const isAuthError = error?.code === '28P01'
      const isConnError = ['ECONNREFUSED', 'ECONNRESET', '57P01'].includes(error?.code)
      const shouldRetry = attempt < maxRetries && (isAuthError || isConnError)

      console.error('Error ejecutando query:', { text, params, error: error?.message || error, code: error?.code, attempt })

      if (shouldRetry) {
        // Backoff progresivo y reintento
        const delay = Math.min(2000, 300 * (attempt + 1))
        await new Promise((res) => setTimeout(res, delay))
        // Resetear pool en auth/conn error por si la contraseña/estado cambia en caliente
        try {
          await currentPool.end()
        } catch (_) {}
        pool = null
        continue
      }

      throw error
    }
  }
}

/**
 * Obtiene un cliente del pool para ejecutar transacciones.
 */
export async function getClient(): Promise<pg.PoolClient> {
  const pool = getPool()
  return await pool.connect()
}

/**
 * Cierra el pool de conexiones (tests o shutdown).
 */
export async function closePool(): Promise<void> {
  if (pool) {
    await pool.end()
    pool = null
    console.log('Pool de PostgreSQL cerrado')
  }
}

/**
 * Verifica que la conexión a la base de datos esté funcionando.
 */
export async function checkConnection(): Promise<boolean> {
  try {
    const result = await query('SELECT NOW() as now')
    return result.rows.length > 0
  } catch (error) {
    console.error('Error verificando conexión a PostgreSQL:', error)
    return false
  }
}
