/// Cálculo de prazo a partir do horário do **servidor**.
///
/// Regra inviolável do domínio: o relógio do device não decide nada sobre
/// prazo, porque o participante pode alterá-lo. O app recebe `serverTime` na
/// resposta, guarda o desvio em relação ao próprio relógio, e usa esse desvio
/// para a contagem.
///
/// `relogioLocal` é injetável de propósito: sem isso o desvio seria calculado
/// contra um relógio e aplicado a outro, e a regra ficaria sem teste.
class RelogioDoServidor {
  RelogioDoServidor({
    required DateTime serverTime,
    DateTime Function()? relogioLocal,
  }) : _relogioLocal = relogioLocal ?? DateTime.now,
       _desvio = serverTime.difference((relogioLocal ?? DateTime.now)());

  final DateTime Function() _relogioLocal;
  final Duration _desvio;

  /// Agora, na régua do servidor.
  DateTime get agora => _relogioLocal().add(_desvio);

  /// Quanto falta para um prazo. Negativo quando já passou.
  Duration restanteAte(DateTime prazo) => prazo.difference(agora);

  bool aberto(DateTime prazo) => restanteAte(prazo) > Duration.zero;
}

/// Formata a contagem para o participante ler sem calcular de cabeça.
String formatarRestante(Duration d) {
  if (d <= Duration.zero) return 'fechado';

  final dias = d.inDays;
  if (dias >= 1) {
    final horas = d.inHours % 24;
    return horas > 0 ? 'fecha em ${dias}d ${horas}h' : 'fecha em ${dias}d';
  }

  final horas = d.inHours;
  final minutos = d.inMinutes % 60;
  if (horas >= 1) return 'fecha em ${horas}h ${minutos}min';
  if (minutos >= 1) return 'fecha em ${minutos}min';
  return 'fecha em menos de 1min';
}

/// Horário do jogo no **fuso do aparelho**, com o fuso escrito.
///
/// O prazo é o do servidor, mas quem lê é uma pessoa num fuso: mostrar UTC faz
/// o participante achar que tem três horas a mais e perder o prazo. O nome do
/// fuso aparece porque, em jogo que fecha de madrugada, a diferença é decisiva.
String formatarHorarioLocal(DateTime utc) {
  final l = utc.toLocal();
  final dia =
      '${l.day.toString().padLeft(2, '0')}/'
      '${l.month.toString().padLeft(2, '0')}';
  final hora =
      '${l.hour.toString().padLeft(2, '0')}:'
      '${l.minute.toString().padLeft(2, '0')}';
  return '$dia às $hora ${nomeDoFuso(l)}';
}

/// Rótulo curto do fuso local, derivado do offset. Sem base de fusos no app,
/// o offset é a informação honesta — e é o que resolve a dúvida do prazo.
String nomeDoFuso(DateTime local) {
  final offset = local.timeZoneOffset;
  if (offset == Duration.zero) return 'UTC';
  final sinal = offset.isNegative ? '-' : '+';
  final horas = offset.abs().inHours;
  final minutos = offset.abs().inMinutes % 60;
  final h = horas.toString().padLeft(2, '0');
  return minutos == 0
      ? 'UTC$sinal$h'
      : 'UTC$sinal$h:${minutos.toString().padLeft(2, '0')}';
}
