using System.Security.Claims;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;
using SameBeat.Api.Hubs;
using SameBeat.Application.Interfejsy;
using SameBeat.Application.Komendy;
namespace SameBeat.Api.Controllers;
///
/// Sterowanie mikrofonem przez hosta (ETAP 5) -- NAJWAZNIEJSZA funkcja produktu. Trasa zaczyna sie od
/// "api/host", wiec jest automatycznie chroniona [Authorize] przez KonwencjaAutoryzacjiHosta.
///
/// BEZPIECZENSTWO: kazda zmiana rozglaszana jest przez SignalR do WSZYSTKICH polaczonych klientow --
/// payload to zawsze StanMikrofonuDto (numerSlotu + nick + koniecUtc), NIGDY uczestnikId, dokladnie ten
/// sam kontrakt co przy scenie (patrz HostStageController).
///
/// Autorytatywne wygasniecie czasu NIE przechodzi przez ten kontroler -- tym zajmuje sie
/// SerwisTimeraMikrofonu (Infrastructure/Audio), ktory dziala w tle i sam rozglasza "MikrofonOdebrany"
/// przez IRozgloszenieZdarzenImprezy. Ten kontroler obsluguje wylacznie akcje hosta: przyznaj/przerwij.
///
[ApiController]
[Route("api/host/mikrofon")]
public class HostMicrophoneController : ControllerBase
{
private readonly ISerwisMikrofonu _serwisMikrofonu;
private readonly IHubContext _hubKontekst;
public HostMicrophoneController(ISerwisMikrofonu serwisMikrofonu, IHubContext hubKontekst)
{
_serwisMikrofonu = serwisMikrofonu;
_hubKontekst = hubKontekst;
}
/// Biezacy stan mikrofonu -- do wyswietlenia w panelu hosta po odswiezeniu strony.
[HttpGet]
public async Task PobierzStanAsync(CancellationToken token)
{
var wynik = await _serwisMikrofonu.PobierzStanAsync(token);
if (!wynik.Sukces || wynik.Dane is null)
{
return BadRequest(new { blad = wynik.Blad });
}
return Ok(wynik.Dane);
}
[HttpPost("{uczestnikId:guid}/przyznaj")]
public async Task PrzyznajAsync(Guid uczestnikId, [FromBody] PrzyznajMikrofonKomenda komenda, CancellationToken token)
{
var hostNick = User.FindFirstValue(ClaimTypes.Name);
if (string.IsNullOrWhiteSpace(hostNick))
{
// Nie powinno wystapic przy poprawnym tokenie JWT (GeneratorTokenowJwt zawsze dodaje ten
// claim) -- ale gdyby jednak, host dostaje czytelny blad zamiast NullReferenceException.
return BadRequest(new { blad = "Nie udalo sie odczytac tozsamosci z sesji -- zaloguj sie ponownie." });
}
var wynik = await _serwisMikrofonu.PrzyznajAsync(uczestnikId, komenda.CzasSekundy, hostNick, token);
if (!wynik.Sukces || wynik.Dane is null)
{
return BadRequest(new { blad = wynik.Blad });
}
await _hubKontekst.Clients.All.SendAsync("MikrofonPrzyznany", wynik.Dane, cancellationToken: token);
return Ok(wynik.Dane);
}
[HttpPost("{uczestnikId:guid}/przerwij")]
public async Task PrzerwijAsync(Guid uczestnikId, CancellationToken token)
{
var wynik = await _serwisMikrofonu.PrzerwijAsync(uczestnikId, token);
if (!wynik.Sukces || wynik.Dane is null)
{
return BadRequest(new { blad = wynik.Blad });
}
await _hubKontekst.Clients.All.SendAsync("MikrofonOdebrany", wynik.Dane, cancellationToken: token);
return Ok(wynik.Dane);
}
}