using ZB.MOM.WW.ScadaBridge.Commons.Messages.Management;

namespace ZB.MOM.WW.ScadaBridge.CentralUI.Services;

/// <summary>
/// Outcome of a single secured-write command dispatch. Wraps either the resulting
/// <see cref="SecuredWriteDto"/> (on success) or a human-readable error, so the page
/// can render an inline result/toast rather than reasoning about transport exceptions
/// or the three management response shapes.
/// </summary>
/// <param name="Success">Whether the command succeeded.</param>
/// <param name="Dto">The resulting secured-write row when <paramref name="Success"/> is <c>true</c>; otherwise <c>null</c>.</param>
/// <param name="Error">A human-readable error message when <paramref name="Success"/> is <c>false</c>; otherwise <c>null</c>.</param>
public record SecuredWriteActionResult(bool Success, SecuredWriteDto? Dto, string? Error)
{
    /// <summary>Creates a successful result wrapping <paramref name="dto"/>.</summary>
    /// <param name="dto">The secured-write row the command produced.</param>
    /// <returns>A successful <see cref="SecuredWriteActionResult"/>.</returns>
    public static SecuredWriteActionResult Ok(SecuredWriteDto dto) => new(true, dto, null);

    /// <summary>Creates a failed result carrying <paramref name="error"/>.</summary>
    /// <param name="error">The human-readable failure message.</param>
    /// <returns>A failed <see cref="SecuredWriteActionResult"/>.</returns>
    public static SecuredWriteActionResult Fail(string error) => new(false, null, error);
}

/// <summary>
/// CentralUI facade over the two-person ("secured") write management commands.
/// It dispatches the strongly-typed
/// <c>SubmitSecuredWriteCommand</c> / <c>ApproveSecuredWriteCommand</c> /
/// <c>RejectSecuredWriteCommand</c> / <c>ListSecuredWritesCommand</c> to the central
/// <c>ManagementActor</c> through the in-process <c>ManagementActorHolder</c> seam —
/// the SAME path the HTTP <c>/management</c> endpoint uses — so the server remains the
/// single enforcer of role gating, separation-of-duties (no self-approval), the actual
/// MxGateway device relay on approve, and the append-only audit trail.
/// </summary>
/// <remarks>
/// The page itself performs NO device I/O and re-implements NO security logic: every
/// mutation is a command submitted to the server. The current user's claims are mapped
/// to an <see cref="AuthenticatedUser"/> so the actor's role check and no-self-approval
/// guard run against the real principal. <c>ManagementUnauthorized</c> /
/// <c>ManagementError</c> / transport failures collapse into a typed
/// <see cref="SecuredWriteActionResult"/> so the page renders an inline outcome rather
/// than throwing.
/// </remarks>
public interface ISecuredWriteService
{
    /// <summary>
    /// Submits a new pending secured write (Operator action). The target connection
    /// must exist within <paramref name="siteId"/> and use the MxGateway protocol —
    /// both validated server-side.
    /// </summary>
    /// <param name="siteId">Site identifier the write targets.</param>
    /// <param name="connectionName">MxGateway data connection name within the site.</param>
    /// <param name="tagPath">Fully-qualified tag path the value is written to.</param>
    /// <param name="valueJson">JSON-serialised value to write.</param>
    /// <param name="valueType">Target data type name (e.g. <c>Boolean</c>, <c>Double</c>).</param>
    /// <param name="comment">Optional free-text comment supplied by the operator.</param>
    /// <param name="cancellationToken">Cancellation token.</param>
    /// <returns>A task resolving to the submit outcome.</returns>
    Task<SecuredWriteActionResult> SubmitAsync(
        string siteId,
        string connectionName,
        string tagPath,
        string valueJson,
        string valueType,
        string? comment,
        CancellationToken cancellationToken = default);

    /// <summary>
    /// Approves (and triggers execution of) a pending secured write (Verifier action).
    /// The server enforces that the approver differs from the submitter and runs the
    /// device relay.
    /// </summary>
    /// <param name="id">Identity of the pending secured write.</param>
    /// <param name="comment">Optional free-text comment supplied by the verifier.</param>
    /// <param name="cancellationToken">Cancellation token.</param>
    /// <returns>A task resolving to the approve outcome.</returns>
    Task<SecuredWriteActionResult> ApproveAsync(
        long id, string? comment, CancellationToken cancellationToken = default);

    /// <summary>
    /// Rejects a pending secured write (Verifier action). The server enforces that the
    /// rejecter differs from the submitter.
    /// </summary>
    /// <param name="id">Identity of the pending secured write.</param>
    /// <param name="comment">Optional free-text comment supplied by the verifier.</param>
    /// <param name="cancellationToken">Cancellation token.</param>
    /// <returns>A task resolving to the reject outcome.</returns>
    Task<SecuredWriteActionResult> RejectAsync(
        long id, string? comment, CancellationToken cancellationToken = default);

    /// <summary>
    /// Lists secured writes, optionally filtered by <paramref name="status"/> and
    /// <paramref name="siteId"/> with offset paging (read-only — any authenticated user).
    /// On any failure an empty result (<c>TotalCount = 0</c>) is returned so the page
    /// renders gracefully. The returned <see cref="SecuredWriteListResult.TotalCount"/> is
    /// the unpaged match count, so the page can drive a pager independent of page size.
    /// </summary>
    /// <param name="status">Status filter; <c>null</c> matches every status.</param>
    /// <param name="siteId">Site id filter; <c>null</c> matches every site.</param>
    /// <param name="skip">Rows to skip (offset paging); clamped to &gt;= 0 server-side.</param>
    /// <param name="take">Maximum rows to return; clamped to 1..500 server-side.</param>
    /// <param name="cancellationToken">Cancellation token.</param>
    /// <returns>A task resolving to the matching page + total match count, newest submission first.</returns>
    Task<SecuredWriteListResult> ListAsync(
        string? status, string? siteId, int skip = 0, int take = 200,
        CancellationToken cancellationToken = default);
}
