Police/PoliceBackend.cs

Client-side wrapper for the HorizonRP police and justice backend. Defines DTOs for officers, penal code, records, jail, fines and a set of Justice* methods that post JSON payloads to named server endpoints through the shared Backend.Post helper.

namespace HorizonRP;

/// <summary>
/// Les appels de l'API du chantier « Justice et service » (outils/police/CONCEPTION.md, section 2) :
/// effectifs et code pénal, casier (amende, arrestation), prison, amendes payées à l'accueil.
/// Clé du serveur, appelés par l'hôte seul (PoliceService.Service.cs, PoliceActions.cs) après avoir
/// revérifié les droits. Les noms commencent par « Justice » pour ne pas croiser ceux de la tablette
/// (PoliceBackend.Tablet.cs, « Mdt »).
///
/// Les SteamID partent en texte (colonnes VARCHAR de l'API), comme pour la tablette. Les nombres
/// rendus en texte par PHP se lisent quand même (réglages « Web » de System.Text.Json).
/// </summary>
public static partial class Backend
{
	/// <summary>Un agent inscrit, tel que serverPoliceSync le rend.</summary>
	public sealed class JusticeOfficer
	{
		/// <summary>BIGINT en base : il peut arriver en nombre JSON comme en texte (lu par <see cref="SteamIdText"/>).</summary>
		public object SteamId { get; set; }

		/// <summary>Le SteamID en texte, quelle que soit sa forme dans la réponse.</summary>
		public string SteamIdText => SteamId?.ToString()?.Trim( '"' );

		public int Grade { get; set; }
		public string Badge { get; set; }
		public string Callsign { get; set; }
	}

	/// <summary>Une ligne active du code pénal.</summary>
	public sealed class JusticePenal
	{
		public string Id { get; set; }
		public string Category { get; set; }
		public string Title { get; set; }
		public string Description { get; set; }
		public string Class { get; set; }
		public int Fine { get; set; }
		public int JailMinutes { get; set; }
	}

	public sealed class JusticePlateFlag
	{
		public string Plate { get; set; }
		public string Reason { get; set; }
	}

	public sealed class JusticeSyncResponse
	{
		public bool Ok { get; set; }
		public string Error { get; set; }
		public List<JusticeOfficer> Officers { get; set; }
		public List<JusticePenal> Penal { get; set; }
		public List<JusticePlateFlag> Flags { get; set; }
	}

	public sealed class JusticeRecordResponse
	{
		public bool Ok { get; set; }
		public string Error { get; set; }
		public long RecordId { get; set; }
		public int FineTotal { get; set; }
		public int JailMinutes { get; set; }
		public long? FineId { get; set; }

		/// <summary>Arrestation : la peine en cours après celle-ci (elle s'ajoute à une peine déjà en cours, plafond 120 min).</summary>
		public JusticeJail Jail { get; set; }
	}

	public sealed class JusticeJail
	{
		public int SecondsLeft { get; set; }
		public int SecondsTotal { get; set; }
	}

	public sealed class JusticeJailResponse
	{
		public bool Ok { get; set; }
		public string Error { get; set; }
		/// <summary>Null : pas en prison.</summary>
		public JusticeJail Jail { get; set; }
	}

	/// <summary>Une amende, pour l'accueil du commissariat.</summary>
	public sealed class JusticeFine
	{
		public long Id { get; set; }
		public int Amount { get; set; }
		public string Status { get; set; }
		public string IssuedAt { get; set; }
		public string Title { get; set; }
	}

	public sealed class JusticeFinesResponse
	{
		public bool Ok { get; set; }
		public string Error { get; set; }
		public List<JusticeFine> Fines { get; set; }
	}

	public sealed class JusticeFinePayResponse
	{
		public bool Ok { get; set; }
		public string Error { get; set; }
		/// <summary>Le solde HZ BANK après paiement : l'hôte le reporte sur le joueur (sinon la sauvegarde suivante l'écraserait).</summary>
		public int Bank { get; set; }
	}

	/// <summary>Effectifs, code pénal (lignes actives) et véhicules signalés.</summary>
	public static Task<JusticeSyncResponse> JusticeSync()
		=> Post<JusticeSyncResponse>( "serverPoliceSync", new { } );

	/// <summary>
	/// Une ligne du casier écrite en jeu (menu F6) : <paramref name="kind"/> « amende » ou
	/// « arrestation ». L'API recalcule amende et peine d'après hz_penal_code.
	/// </summary>
	public static Task<JusticeRecordResponse> JusticeRecord( ulong steamId, string kind, List<string> charges, string title, string notes, string location, ulong officerSteam, string officerName )
		=> Post<JusticeRecordResponse>( "serverPoliceRecord", new { steamId = steamId.ToString(), kind, charges, title, notes, location, officerSteam = officerSteam.ToString(), officerName } );

	/// <summary>La peine en cours d'un joueur qui se connecte, ou null.</summary>
	public static Task<JusticeJailResponse> JusticeJailLoad( ulong steamId )
		=> Post<JusticeJailResponse>( "serverPoliceJail", new { steamId = steamId.ToString() } );

	/// <summary>Le temps qui reste (0 = libéré : la ligne est supprimée).</summary>
	public static Task<SimpleResponse> JusticeJailSave( ulong steamId, int secondsLeft )
		=> Post<SimpleResponse>( "serverPoliceJailSave", new { steamId = steamId.ToString(), secondsLeft } );

	public static Task<JusticeFinesResponse> JusticeFines( ulong steamId )
		=> Post<JusticeFinesResponse>( "serverPoliceFines", new { steamId = steamId.ToString() } );

	/// <summary><paramref name="balance"/> : le solde que le jeu a en mémoire (il fait foi, la base n'est écrite qu'aux sauvegardes).</summary>
	public static Task<JusticeFinePayResponse> JusticeFinePay( ulong steamId, long fineId, int balance )
		=> Post<JusticeFinePayResponse>( "serverPoliceFinePay", new { steamId = steamId.ToString(), fineId, balance } );
}