using ZB.MOM.WW.OtOpcUa.Configuration.Enums;
namespace ZB.MOM.WW.OtOpcUa.AdminUI.Uns;
///
/// Detached, editable projection of a raw Tag — the read side of tag editing. WP1 exposes this
/// loader; WP4 owns the create/update authoring surface and should align its input model with these
/// fields (identity is the RawPath, formed from the tag's device + optional group + name).
///
/// The tag's stable logical id.
/// The owning device's logical id.
/// The containing tag group's logical id, or null when directly under the device.
/// The tag name (a RawPath segment).
/// The OPC UA built-in type name.
/// The tag's access-level baseline.
/// Whether writes to this tag are retry-eligible.
/// The optional poll-group id.
/// The schemaless per-driver TagConfig JSON blob.
/// The optimistic-concurrency token.
public readonly record struct RawTagEditDto(
string TagId,
string DeviceId,
string? TagGroupId,
string Name,
string DataType,
TagAccessLevel AccessLevel,
bool WriteIdempotent,
string? PollGroupId,
string TagConfig,
byte[] RowVersion);
///
/// Detached, editable projection of a DriverInstance — the read side of the Wave-B (WP3)
/// "Configure driver" modal. DriverType is included so the modal can dispatch to the correct
/// typed driver-config editor; it is immutable, so does
/// not change it.
///
/// The driver instance's stable logical id.
/// The driver instance name (a RawPath segment).
/// The immutable driver-type string (see DriverTypeNames).
/// The schemaless per-driver-type DriverConfig JSON blob.
/// Optional per-instance resilience-pipeline overrides JSON, or null.
/// The optimistic-concurrency token.
public sealed record RawDriverEditDto(
string DriverInstanceId,
string Name,
string DriverType,
string DriverConfig,
string? ResilienceConfig,
byte[] RowVersion);
///
/// Detached, editable projection of a Device — the read side of the Wave-B (WP3) "Configure
/// device" modal. DriverType is joined in from the parent DriverInstance so the modal can
/// dispatch to the correct typed device-config editor (endpoint/connection settings now live in
/// DeviceConfig).
///
/// The device's stable logical id.
/// The owning driver instance's logical id.
/// The device name (a RawPath segment).
/// The schemaless per-driver-type DeviceConfig JSON blob (host/endpoint + per-device settings).
/// Whether the device is enabled.
/// The parent driver's type string, joined in for editor dispatch.
/// The optimistic-concurrency token.
public sealed record RawDeviceEditDto(
string DeviceId,
string DriverInstanceId,
string Name,
string DeviceConfig,
bool Enabled,
string DriverType,
byte[] RowVersion);
///
/// Loads and mutates the v3 Raw project tree (/raw) — the cluster-rooted
/// Enterprise → Cluster → Folder → Driver → Device → TagGroup → Tag hierarchy — from the config
/// database. The peer of for the Raw subtree.
///
/// Contract split (Batch 2 Wave A): this file's committed surface is the read contract
/// the RawTree component consumes — (eager Enterprise→Cluster roots)
/// and (one lazy level per expand). B2-WP1 (RawTreeService)
/// extends this interface with the mutation surface — create/rename/delete per node type,
/// move-into-folder, and the per-node edit projections — enforcing the integrity rules with
/// user-readable errors (a delete blocked by a UnsTagReference names the referencing equipment).
/// Rename methods return so the UI can show non-blocking warnings.
/// Mutations reuse . WP2 must not add to this interface.
///
///
public interface IRawTreeService
{
///
/// Loads the eager top of the Raw tree: Enterprise → Cluster roots, each cluster marked
/// so its folders + drivers load on first expand. Empty
/// clusters are retained so they stay visible and authorable. The returned nodes are detached
/// view-models, safe to hold and mutate UI state on after the underlying context is disposed.
///
/// A token to cancel the load.
/// The enterprise roots, populated down to (but not through) their clusters.
Task> LoadRootsAsync(CancellationToken ct = default);
///
/// Loads the direct children of one container node — the next level down, keyed off
/// 's and :
/// a Cluster yields its root Folders + Drivers; a Folder yields sub-Folders + Drivers; a Driver
/// yields its Devices; a Device yields its root TagGroups + Tags; a TagGroup yields sub-TagGroups
/// + Tags. Tags are leaves and yield nothing. Ordering is deterministic and ordinal. Reads
/// untracked; returns detached nodes. Per-device tag counts can be large — the implementation may
/// page, but the committed shape returns the level's nodes (paging knobs, if any, are WP1's to add
/// on the concrete type without changing this signature's meaning for the tree).
///
/// The container node whose direct children to load.
/// A token to cancel the load.
/// The parent's direct child nodes; empty for a leaf or an empty container.
Task> LoadChildrenAsync(RawNode parent, CancellationToken ct = default);
// --- Folder mutations ---
///
/// Creates a new RawFolder under a cluster ( null) or under
/// another folder. The name is validated as a RawPath segment and must be unique among its siblings
/// (case-sensitive ordinal). On success the result's CreatedId carries the new folder's
/// logical id.
///
/// The owning cluster id.
/// The parent folder's logical id, or null for a cluster-root folder.
/// The folder name (a RawPath segment).
/// A token to cancel the operation.
/// The create outcome; CreatedId is the new RawFolderId on success.
Task CreateFolderAsync(string clusterId, string? parentFolderId, string name, CancellationToken ct = default);
///
/// Renames a RawFolder. Validates the new name as a RawPath segment and sibling-unique.
/// Because a folder rename changes the RawPath of every tag beneath it, the returned
/// carries advisory warnings for historized and equipment-referenced
/// tags in the folder's subtree.
///
/// The folder's logical id.
/// The new folder name.
/// The optimistic-concurrency token echoed from the loaded node.
/// A token to cancel the operation.
/// The rename outcome with any downstream-impact warnings.
Task RenameFolderAsync(string rawFolderId, string newName, byte[] rowVersion, CancellationToken ct = default);
///
/// Deletes an empty RawFolder. Blocked (with the blocker named) while it still contains child
/// folders or driver instances.
///
/// The folder's logical id.
/// The optimistic-concurrency token echoed from the loaded node.
/// A token to cancel the operation.
/// The delete outcome.
Task DeleteFolderAsync(string rawFolderId, byte[] rowVersion, CancellationToken ct = default);
///
/// Moves a driver instance into a folder () or to the cluster root
/// (null target). The target folder must be in the driver's cluster and the driver's name must be
/// unique among the target's driver siblings.
///
/// The driver instance's logical id.
/// The destination folder's logical id, or null for the cluster root.
/// The optimistic-concurrency token echoed from the loaded node.
/// A token to cancel the operation.
/// The move outcome.
Task MoveDriverToFolderAsync(string driverInstanceId, string? targetFolderId, byte[] rowVersion, CancellationToken ct = default);
// --- Driver mutations ---
///
/// Creates a minimal driver instance and its auto-created default Device so the tree has a
/// child to show. Full typed driver/device config authoring is Wave B (WP3) — this create takes the
/// driver config JSON verbatim and seeds an empty ({}) default device. The driver name is a
/// RawPath segment, unique among its cluster/folder siblings.
///
/// The owning cluster id.
/// The containing folder's logical id, or null for a cluster-root driver.
/// The driver instance name (a RawPath segment).
/// The driver-type string (see DriverTypeNames).
/// The driver config JSON blob (opaque here; validated in Wave B).
/// A token to cancel the operation.
/// The create outcome; CreatedId is the new DriverInstanceId on success.
Task CreateDriverAsync(string clusterId, string? folderId, string name, string driverType, string driverConfigJson, CancellationToken ct = default);
///
/// Renames a driver instance. Validates the new name as a sibling-unique RawPath segment and returns
/// downstream-impact warnings for historized/equipment-referenced tags beneath the driver.
///
/// The driver instance's logical id.
/// The new driver name.
/// The optimistic-concurrency token echoed from the loaded node.
/// A token to cancel the operation.
/// The rename outcome with any downstream-impact warnings.
Task RenameDriverAsync(string driverInstanceId, string newName, byte[] rowVersion, CancellationToken ct = default);
/// Enables or disables a driver instance (last-write-wins on ).
/// The driver instance's logical id.
/// The new enabled state.
/// The optimistic-concurrency token echoed from the loaded node.
/// A token to cancel the operation.
/// The update outcome.
Task SetDriverEnabledAsync(string driverInstanceId, bool enabled, byte[] rowVersion, CancellationToken ct = default);
///
/// Deletes a driver instance, cascading its auto-created empty devices. Blocked (with the blocking
/// device named) when any of its devices still contains tag groups or tags — remove those first.
///
/// The driver instance's logical id.
/// The optimistic-concurrency token echoed from the loaded node.
/// A token to cancel the operation.
/// The delete outcome.
Task DeleteDriverAsync(string driverInstanceId, byte[] rowVersion, CancellationToken ct = default);
// --- Device mutations ---
///
/// Creates a minimal Device under a driver. Full typed device-config authoring is Wave B
/// (WP3) — this create takes the device config JSON verbatim. The device name must be unique among
/// the driver's devices.
///
/// The owning driver instance's logical id.
/// The device name (a RawPath segment).
/// The device config JSON blob (opaque here; validated in Wave B).
/// A token to cancel the operation.
/// The create outcome; CreatedId is the new DeviceId on success.
Task CreateDeviceAsync(string driverInstanceId, string name, string deviceConfigJson, CancellationToken ct = default);
///
/// Renames a Device. Validates the new name as a driver-unique RawPath segment and returns
/// downstream-impact warnings for historized/equipment-referenced tags beneath the device.
///
/// The device's logical id.
/// The new device name.
/// The optimistic-concurrency token echoed from the loaded node.
/// A token to cancel the operation.
/// The rename outcome with any downstream-impact warnings.
Task RenameDeviceAsync(string deviceId, string newName, byte[] rowVersion, CancellationToken ct = default);
/// Deletes a Device. Blocked (with the blocker named) while it holds tag groups or tags.
/// The device's logical id.
/// The optimistic-concurrency token echoed from the loaded node.
/// A token to cancel the operation.
/// The delete outcome.
Task DeleteDeviceAsync(string deviceId, byte[] rowVersion, CancellationToken ct = default);
// --- TagGroup mutations ---
///
/// Creates a new TagGroup under a device ( null) or under
/// another group. The name is validated as a RawPath segment, unique among its siblings.
///
/// The owning device's logical id.
/// The parent group's logical id, or null for a device-root group.
/// The group name (a RawPath segment).
/// A token to cancel the operation.
/// The create outcome; CreatedId is the new TagGroupId on success.
Task CreateTagGroupAsync(string deviceId, string? parentGroupId, string name, CancellationToken ct = default);
///
/// Renames a TagGroup. Validates the new name as a sibling-unique RawPath segment and returns
/// downstream-impact warnings for historized/equipment-referenced tags beneath the group.
///
/// The group's logical id.
/// The new group name.
/// The optimistic-concurrency token echoed from the loaded node.
/// A token to cancel the operation.
/// The rename outcome with any downstream-impact warnings.
Task RenameTagGroupAsync(string tagGroupId, string newName, byte[] rowVersion, CancellationToken ct = default);
/// Deletes a TagGroup. Blocked (with the blocker named) while it holds child groups or tags.
/// The group's logical id.
/// The optimistic-concurrency token echoed from the loaded node.
/// A token to cancel the operation.
/// The delete outcome.
Task DeleteTagGroupAsync(string tagGroupId, byte[] rowVersion, CancellationToken ct = default);
// --- Tag mutations / projections (create + update are WP4) ---
///
/// Deletes a raw Tag. Blocked while any UnsTagReference points at it; the failure
/// message names the referencing equipment(s) so the operator can remove the reference(s) first.
///
/// The tag's logical id.
/// The optimistic-concurrency token echoed from the loaded node.
/// A token to cancel the operation.
/// The delete outcome.
Task DeleteTagAsync(string tagId, byte[] rowVersion, CancellationToken ct = default);
///
/// Loads a raw tag's editable fields as a detached projection. WP1 provides the read-only projection;
/// the create/update authoring surface is WP4 (which should align its input shape with
/// ).
///
/// The tag's logical id.
/// A token to cancel the load.
/// The tag's editable projection, or null when the tag does not exist.
Task LoadTagForEditAsync(string tagId, CancellationToken ct = default);
///
/// Creates a raw Tag under a device ( null) or a tag group. The
/// name is validated as a RawPath segment and must be unique among its siblings on the same
/// (DeviceId, TagGroupId); the is validated for JSON
/// well-formedness. On success the result's CreatedId carries the new tag's logical id.
///
/// The owning device's logical id.
/// The containing tag group's logical id, or null for a device-root tag.
/// The tag's editable fields (identity is the RawPath — no TagId here).
/// A token to cancel the operation.
/// The create outcome; CreatedId is the new TagId on success.
Task CreateTagAsync(string deviceId, string? tagGroupId, RawTagInput input, CancellationToken ct = default);
///
/// Updates a raw Tag's editable fields. The new name is re-validated as a RawPath segment and
/// sibling-unique on the tag's existing (DeviceId, TagGroupId) excluding itself; the
/// is validated for JSON well-formedness. Last-write-wins on
/// . The tag's DeviceId/TagGroupId (its identity location)
/// are preserved — moving a tag is not this method's job.
///
/// The tag's logical id.
/// The tag's edited fields.
/// The optimistic-concurrency token echoed from the loaded tag.
/// A token to cancel the operation.
/// The update outcome.
Task UpdateTagAsync(string tagId, RawTagInput input, byte[] rowVersion, CancellationToken ct = default);
///
/// Commits a batch of raw tags under a device — the WP5 CSV-import path. Each row's
/// TagGroupPath is a /-separated tag-group path under the device whose segments are
/// auto-created as nested TagGroups (reusing existing ones). Per-row validation errors (bad
/// name segment, malformed TagConfig JSON, a duplicate name within the device+group) are
/// collected, not thrown. The import is all-or-nothing: if any row errors, nothing is inserted
/// and the errors are returned; otherwise all tags (and any newly-needed groups) are committed in one
/// SaveChanges.
///
/// The target device's logical id.
/// The rows to import.
/// A token to cancel the operation.
/// The import outcome: the inserted count on success, or the per-row errors with a 0 count.
Task ImportTagsAsync(string deviceId, IReadOnlyList rows, CancellationToken ct = default);
///
/// Loads a driver instance's editable fields as a detached projection for the WP3 "Configure driver"
/// modal. DriverType is included for typed-editor dispatch (it is immutable).
///
/// The driver instance's logical id.
/// A token to cancel the load.
/// The driver's editable projection, or null when it does not exist.
Task LoadDriverForEditAsync(string driverInstanceId, CancellationToken ct = default);
///
/// Updates a driver instance's name + config from the WP3 "Configure driver" modal. The name is
/// validated as a sibling-unique RawPath segment (same scope as );
/// last-write-wins on . DriverType is immutable and is not changed.
///
/// The driver instance's logical id.
/// The (possibly changed) driver name.
/// The new DriverConfig JSON blob.
/// The new resilience-config JSON, or null/blank to clear.
/// The optimistic-concurrency token echoed from the loaded projection.
/// A token to cancel the operation.
/// The update outcome.
Task UpdateDriverAsync(string driverInstanceId, string name, string driverConfigJson, string? resilienceConfig, byte[] rowVersion, CancellationToken ct = default);
///
/// Loads a device's editable fields as a detached projection for the WP3 "Configure device" modal.
/// DriverType is joined in from the parent driver so the modal can dispatch to the correct typed
/// device-config editor.
///
/// The device's logical id.
/// A token to cancel the load.
/// The device's editable projection, or null when it does not exist.
Task LoadDeviceForEditAsync(string deviceId, CancellationToken ct = default);
///
/// Updates a device's name + config + enabled state from the WP3 "Configure device" modal. The name
/// is validated as a RawPath segment unique among the driver's devices; last-write-wins on
/// .
///
/// The device's logical id.
/// The (possibly changed) device name.
/// The new DeviceConfig JSON blob (endpoint + per-device settings).
/// The new enabled state.
/// The optimistic-concurrency token echoed from the loaded projection.
/// A token to cancel the operation.
/// The update outcome.
Task UpdateDeviceAsync(string deviceId, string name, string deviceConfigJson, bool enabled, byte[] rowVersion, CancellationToken ct = default);
///
/// Builds the single merged config blob the driver-probe (test-connect) path binds from for one device:
/// the parent driver's DriverConfig folded together with this device's DeviceConfig (via
/// DriverDeviceConfigMerger, endpoint keys merging up from DeviceConfig). Used by the
/// "Test connect" button inside the WP3 driver/device modals now that the endpoint lives in
/// DeviceConfig.
///
/// The device to probe.
/// A token to cancel the load.
/// The parent driver's type + the merged config JSON, or null when the device/driver cannot be resolved.
Task<(string DriverType, string MergedConfigJson)?> LoadMergedProbeConfigAsync(string deviceId, CancellationToken ct = default);
}