import type { RowDataPacket } from 'mysql2'
import { db, DB } from './db'
import { executeSoapCommand } from './soap'

export interface AccountRow {
  id: number
  username: string
  email: string | null
  last_ip: string | null
  last_login: string | null
  online: boolean
  gmlevel: number
  banned: boolean
  ban_reason: string | null
  ban_until: string | null // ISO, o null si permanente/no baneado
}

/** Busca cuentas por nombre de usuario o email (acore_auth.account). */
export async function searchAccounts(query: string, limit = 30): Promise<AccountRow[]> {
  const like = `%${query}%`
  const [rows] = await db(DB.auth).query<RowDataPacket[]>(
    `SELECT a.id, a.username, a.email, a.last_ip, a.last_login, a.online,
            (SELECT MAX(x.SecurityLevel) FROM account_access x WHERE x.AccountID = a.id) AS gmlevel,
            b.banreason AS ban_reason, b.bandate, b.unbandate
     FROM account a
     LEFT JOIN account_banned b ON b.id = a.id AND b.active = 1
     WHERE a.username LIKE ? OR a.email LIKE ?
     ORDER BY a.username
     LIMIT ?`,
    [like, like, limit],
  )
  return rows.map((r) => {
    const permanent = r.bandate != null && Number(r.unbandate) === Number(r.bandate)
    return {
      id: r.id,
      username: r.username,
      email: r.email || null,
      last_ip: r.last_ip || null,
      last_login: r.last_login ? new Date(r.last_login).toISOString() : null,
      online: r.online === 1,
      gmlevel: r.gmlevel != null ? Number(r.gmlevel) : 0,
      banned: r.bandate != null,
      ban_reason: r.ban_reason ?? null,
      ban_until: r.bandate != null && !permanent ? new Date(Number(r.unbandate) * 1000).toISOString() : null,
    }
  })
}

async function getUsername(accountId: number): Promise<string | null> {
  const [rows] = await db(DB.auth).query<RowDataPacket[]>('SELECT username FROM account WHERE id = ?', [accountId])
  return rows[0]?.username ?? null
}

/**
 * Banea una cuenta. `days` <= 0 => permanente (unbandate = bandate, convención AzerothCore).
 * Escribe en account_banned (autoritativo) e intenta kickear por SOAP si está conectado.
 */
export async function banAccount(
  accountId: number,
  reason: string,
  bannedBy: string,
  days: number,
): Promise<boolean> {
  const username = await getUsername(accountId)
  if (!username) return false

  // Desactiva un baneo activo previo para no acumular activos.
  await db(DB.auth).query('UPDATE account_banned SET active = 0 WHERE id = ? AND active = 1', [accountId])

  const duration = days > 0 ? Math.floor(days) * 86400 : 0
  await db(DB.auth).query(
    `INSERT INTO account_banned (id, bandate, unbandate, bannedby, banreason, active)
     VALUES (?, UNIX_TIMESTAMP(), UNIX_TIMESTAMP() + ?, ?, ?, 1)`,
    [accountId, duration, bannedBy, reason],
  )
  // Best-effort: kickear al jugador si está en línea (no bloquea el baneo si SOAP falla).
  await executeSoapCommand(`.kick ${username}`).catch(() => null)
  return true
}

/** Levanta el baneo activo de una cuenta. */
export async function unbanAccount(accountId: number): Promise<boolean> {
  const [res] = await db(DB.auth).query<RowDataPacket[] & { affectedRows?: number }>(
    'UPDATE account_banned SET active = 0 WHERE id = ? AND active = 1',
    [accountId],
  )
  return Boolean((res as unknown as { affectedRows: number }).affectedRows)
}
