using ZB.MOM.WW.ScadaBridge.Commons.Types.Transport;

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

/// <summary>
/// Exports a bundle. Names rather than IDs in the selection so test scripts can
/// be written without an ID lookup step. <c>All=true</c> overrides the per-type
/// name lists and exports every entity of every supported type.
/// <para>
/// Inbound API keys are intentionally not selectable: per the inbound-API-key
/// re-architecture keys are not transported between environments; only API
/// methods travel. Re-create keys and re-grant their method scopes on the
/// destination via the admin UI/CLI.
/// </para>
/// </summary>
public sealed record ExportBundleCommand(
    bool All,
    IReadOnlyList<string>? TemplateNames,
    IReadOnlyList<string>? SharedScriptNames,
    IReadOnlyList<string>? ExternalSystemNames,
    IReadOnlyList<string>? DatabaseConnectionNames,
    IReadOnlyList<string>? NotificationListNames,
    IReadOnlyList<string>? SmtpConfigurationNames,
    IReadOnlyList<string>? ApiMethodNames,
    bool IncludeDependencies,
    string? Passphrase,
    string SourceEnvironment,
    // Additive: site/instance-scoped selection. Sites resolve by
    // SiteIdentifier (preferred) or Name; instances resolve by UniqueName.
    // Defaulted null so every existing positional caller keeps compiling; the
    // handler normalizes null to "select nothing" (or everything under All=true).
    IReadOnlyList<string>? SiteNames = null,
    IReadOnlyList<string>? InstanceNames = null,
    // Additive: SMS provider config selection, mirroring
    // SmtpConfigurationNames. SmsConfiguration is keyed by AccountSid (no Name
    // column), so tokens are AccountSid values. Defaulted null so every existing
    // positional caller keeps compiling.
    IReadOnlyList<string>? SmsConfigurationNames = null);

/// <summary>
/// Bundle body returned as base64-encoded ZIP. <see cref="ByteCount"/> is the
/// pre-encoded size for sanity checks against the configured bundle cap.
/// </summary>
public sealed record ExportBundleResult(
    string Base64Bundle,
    int ByteCount);

/// <summary>
/// Loads a bundle and returns its preview without applying anything. Useful
/// for tests that want to assert on the diff shape before committing.
/// </summary>
public sealed record PreviewBundleCommand(
    string Base64Bundle,
    string? Passphrase);

public sealed record PreviewBundleResult(
    IReadOnlyList<ImportPreviewItem> Items,
    int AddCount,
    int ModifiedCount,
    int IdenticalCount,
    int BlockerCount,
    // Additive: site/connection references the operator must resolve
    // before import, carried verbatim from ImportPreview. Defaulted to empty so
    // every existing positional caller keeps compiling.
    IReadOnlyList<RequiredSiteMapping>? RequiredSiteMappings = null,
    IReadOnlyList<RequiredConnectionMapping>? RequiredConnectionMappings = null)
{
    /// <summary>Site references the operator must resolve before import. Never null.</summary>
    public IReadOnlyList<RequiredSiteMapping> RequiredSiteMappings { get; init; } =
        RequiredSiteMappings ?? Array.Empty<RequiredSiteMapping>();

    /// <summary>Connection references the operator must resolve before import. Never null.</summary>
    public IReadOnlyList<RequiredConnectionMapping> RequiredConnectionMappings { get; init; } =
        RequiredConnectionMappings ?? Array.Empty<RequiredConnectionMapping>();
}

/// <summary>
/// One source-environment site → destination resolution carried on
/// <see cref="ImportBundleCommand"/> across the CLI ⇆ ManagementActor boundary.
/// A null/blank <paramref name="TargetSiteIdentifier"/> means CreateNew; a
/// present value means MapToExisting that target. Serializable via
/// System.Text.Json.
/// </summary>
public sealed record SiteMappingSpec(
    string SourceSiteIdentifier,
    string? TargetSiteIdentifier);

/// <summary>
/// One source-environment data-connection (scoped to a source site) →
/// destination resolution carried on <see cref="ImportBundleCommand"/>. A
/// null/blank <paramref name="TargetConnectionName"/> means CreateNew; a present
/// value means MapToExisting that target. Serializable via System.Text.Json.
/// </summary>
public sealed record ConnectionMappingSpec(
    string SourceSiteIdentifier,
    string SourceConnectionName,
    string? TargetConnectionName);

/// <summary>
/// Loads, previews, and applies a bundle in a single call. The diff is built
/// internally; every <see cref="ConflictKind.Modified"/> row is resolved with
/// <see cref="DefaultConflictPolicy"/>, every <see cref="ConflictKind.New"/>
/// row gets <see cref="ResolutionAction.Add"/>, every
/// <see cref="ConflictKind.Identical"/> row gets <see cref="ResolutionAction.Skip"/>,
/// and any <see cref="ConflictKind.Blocker"/> row fails the call.
/// <para>
/// Valid <see cref="DefaultConflictPolicy"/> values: <c>"skip"</c>,
/// <c>"overwrite"</c>, <c>"rename"</c>. Rename mints a unique suffix per row.
/// </para>
/// <para>
/// <paramref name="SiteMappings"/> / <paramref name="ConnectionMappings"/>
/// supply explicit operator resolutions for the source-environment site/connection
/// references the bundle carries; the handler merges them with the preview's
/// auto-matches and the <paramref name="CreateMissingSites"/> /
/// <paramref name="CreateMissingConnections"/> flags into a
/// <see cref="BundleNameMap"/> passed to Apply. All four are defaulted so every
/// existing positional caller keeps compiling and central-config-only bundles
/// (no site/instance payload) carry an empty map.
/// </para>
/// </summary>
public sealed record ImportBundleCommand(
    string Base64Bundle,
    string? Passphrase,
    string DefaultConflictPolicy,
    IReadOnlyList<SiteMappingSpec>? SiteMappings = null,
    IReadOnlyList<ConnectionMappingSpec>? ConnectionMappings = null,
    bool CreateMissingSites = false,
    bool CreateMissingConnections = false);
