using ZB.MOM.WW.OtOpcUa.Configuration.Enums;
namespace ZB.MOM.WW.OtOpcUa.AdminUI.Uns;
///
/// A UNS area projected for editing: its operator-editable fields plus the owning cluster and
/// the concurrency token the edit modal must echo back on save.
///
/// The area's stable id (read-only on edit).
/// The area name.
/// Optional notes; null when unset.
/// The owning cluster id (the served-by selection).
/// The optimistic-concurrency token last read.
public sealed record AreaEditDto(string UnsAreaId, string Name, string? Notes, string ClusterId, byte[] RowVersion);
///
/// A UNS line projected for editing: its operator-editable fields plus the parent area and the
/// concurrency token the edit modal must echo back on save.
///
/// The line's stable id (read-only on edit).
/// The owning area id (the parent-area selection).
/// The line name.
/// Optional notes; null when unset.
/// The optimistic-concurrency token last read.
public sealed record LineEditDto(string UnsLineId, string UnsAreaId, string Name, string? Notes, byte[] RowVersion);
///
/// An equipment projected for editing: its system-generated id, the operator-editable identity and
/// OPC 40010 identification fields, plus the concurrency token the edit modal must echo back on save.
///
/// The system-generated stable id (read-only — never operator-edited, decision #125).
/// UNS level-5 segment name.
/// Operator colloquial id; unique fleet-wide.
/// The owning line id (the UNS-line selection).
/// Optional driver binding; null when driver-less.
/// Optional ERP equipment id.
/// Optional SAP PM equipment id.
/// Optional OPC 40010 manufacturer name.
/// Optional OPC 40010 model designation.
/// Optional OPC 40010 serial number.
/// Optional OPC 40010 hardware revision.
/// Optional OPC 40010 software revision.
/// Optional OPC 40010 year of construction.
/// Optional OPC 40010 asset location.
/// Optional OPC 40010 manufacturer URI.
/// Optional OPC 40010 device-manual URI.
/// Whether the equipment is surfaced in deployments.
/// The optimistic-concurrency token last read.
public sealed record EquipmentEditDto(string EquipmentId, string Name, string MachineCode, string UnsLineId,
string? DriverInstanceId, string? ZTag, string? SAPID, string? Manufacturer, string? Model, string? SerialNumber,
string? HardwareRevision, string? SoftwareRevision, short? YearOfConstruction, string? AssetLocation,
string? ManufacturerUri, string? DeviceManualUri, bool Enabled, byte[] RowVersion);
///
/// An equipment-bound tag projected for editing: its operator-editable fields, the owning equipment
/// (so the host can scope the candidate-driver list and refresh the right node), plus the concurrency
/// token the edit modal must echo back on save. Tree tags are always equipment-bound (decision #110),
/// so FolderPath never surfaces here.
///
/// The tag's stable id (read-only on edit).
/// The owning equipment id.
/// The tag name.
/// The bound driver id.
/// The OPC UA built-in type name.
/// The tag-level access baseline.
/// Whether writes are safe to retry.
/// Optional poll-group key; null when unset.
/// The schemaless per-driver-type JSON config.
/// The optimistic-concurrency token last read.
public sealed record TagEditDto(string TagId, string EquipmentId, string Name, string DriverInstanceId, string DataType,
TagAccessLevel AccessLevel, bool WriteIdempotent, string? PollGroupId, string TagConfig, byte[] RowVersion);
///
/// An equipment-bound virtual tag projected for editing: its operator-editable fields, the owning
/// equipment (so the host can refresh the right node), plus the concurrency token the edit modal must
/// echo back on save. Virtual tags are always scoped to an equipment (plan decision #2), so the modal
/// never offers an equipment-change control.
///
/// The virtual tag's stable id (read-only on edit).
/// The owning equipment id.
/// The virtual-tag name.
/// The OPC UA built-in type name.
/// The bound script id.
/// Whether the tag re-evaluates on dependency change.
/// Optional periodic re-evaluation cadence in ms; null when unset.
/// Whether the tag's values are historized.
/// Whether the tag is spawned in deployments.
/// The optimistic-concurrency token last read.
public sealed record VirtualTagEditDto(string VirtualTagId, string EquipmentId, string Name, string DataType, string ScriptId,
bool ChangeTriggered, int? TimerIntervalMs, bool Historize, bool Enabled, byte[] RowVersion);
///
/// The outcome of a bulk equipment CSV import: how many rows were inserted, how many were skipped
/// (existing MachineCode — the importer is additive-only, never an update), and a per-row error list
/// for rows that could not be inserted (unknown line, unknown driver, or a decision-#122 cluster
/// mismatch). Skipped rows never appear in .
///
/// The count of new Equipment rows added.
/// The count of rows skipped because their MachineCode already exists.
/// The human-readable error strings for rows that failed validation.
public sealed record EquipmentImportResult(int Inserted, int Skipped, IReadOnlyList Errors);
///
/// Loads the structural portion of the unified-namespace (UNS) browse tree —
/// Enterprise → Cluster → Area → Line → Equipment — from the config database.
/// Equipment is a leaf in the tree; its tags and virtual tags are accessed via the
/// equipment detail page, not via lazy tree expansion.
///
public interface IUnsTreeService
{
///
/// Loads the full structural tree. Empty clusters are retained so they remain
/// visible and editable. 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 root nodes, each populated down to equipment.
Task> LoadStructureAsync(CancellationToken ct = default);
///
/// Loads the driver tags bound to a single equipment as flat row projections for the equipment
/// page's Tags tab table, ordered by Name. Each row carries the display columns plus the
/// TagId the table uses to open the edit modal. Reads untracked. Returns an empty list when
/// the equipment has no tags.
///
/// The equipment whose tags to load.
/// A token to cancel the load.
/// The equipment's tag rows ordered by Name; empty if it has none.
Task> LoadTagsForEquipmentAsync(string equipmentId, CancellationToken ct = default);
///
/// Loads the virtual tags scoped to a single equipment as flat row projections for the equipment
/// page's Virtual Tags tab table, ordered by Name. Each row carries the display columns plus the
/// VirtualTagId the table uses to open the edit modal. Reads untracked. Returns an empty list
/// when the equipment has no virtual tags.
///
/// The equipment whose virtual tags to load.
/// A token to cancel the load.
/// The equipment's virtual-tag rows ordered by Name; empty if it has none.
Task> LoadVirtualTagsForEquipmentAsync(string equipmentId, CancellationToken ct = default);
///
/// Loads a single UNS area projected for editing, or null if it no longer exists.
/// Reads untracked and captures the current concurrency token for last-write-wins saves.
///
/// The area to load.
/// A token to cancel the load.
/// The area's edit projection, or null when missing.
Task LoadAreaAsync(string unsAreaId, CancellationToken ct = default);
///
/// Loads a single UNS line projected for editing, or null if it no longer exists.
/// Reads untracked and captures the current concurrency token for last-write-wins saves.
///
/// The line to load.
/// A token to cancel the load.
/// The line's edit projection, or null when missing.
Task LoadLineAsync(string unsLineId, CancellationToken ct = default);
///
/// Loads a single equipment projected for editing, or null if it no longer exists.
/// Reads untracked and captures the current concurrency token for last-write-wins saves.
///
/// The equipment to load.
/// A token to cancel the load.
/// The equipment's edit projection, or null when missing.
Task LoadEquipmentAsync(string equipmentId, CancellationToken ct = default);
///
/// Loads a single equipment-bound tag projected for editing, or null if it no longer exists.
/// Reads untracked and captures the current concurrency token for last-write-wins saves.
///
/// The tag to load.
/// A token to cancel the load.
/// The tag's edit projection, or null when missing.
Task LoadTagAsync(string tagId, CancellationToken ct = default);
///
/// Loads a single equipment-bound virtual tag projected for editing, or null if it no longer
/// exists. Reads untracked and captures the current concurrency token for last-write-wins saves.
///
/// The virtual tag to load.
/// A token to cancel the load.
/// The virtual tag's edit projection, or null when missing.
Task LoadVirtualTagAsync(string virtualTagId, CancellationToken ct = default);
///
/// Loads every driver instance in a cluster (regardless of namespace kind) so the equipment modal
/// can offer the full cluster driver list for binding. Ordered by DriverInstanceId. Each is
/// projected to a (DriverInstanceId, Display) pair where Display is
/// "{DriverInstanceId} — {Name} ({DriverType})".
///
/// The cluster whose drivers to load.
/// A token to cancel the load.
/// The cluster's drivers projected to (DriverInstanceId, Display) pairs.
Task> LoadDriversForClusterAsync(string clusterId, CancellationToken ct = default);
///
/// Loads the UNS-line and driver (Id, Display) option lists the equipment page's Details tab
/// offers, scoped to the cluster that owns the supplied line: every line in that cluster (for the
/// line picker) and that cluster's drivers (reusing ).
/// Centralizes the resolution the page would otherwise need the loaded tree to perform. Returns
/// empty lists when is null/empty or cannot be resolved to a cluster.
///
/// The line whose owning cluster scopes the option lists; null/empty yields empties.
/// A token to cancel the load.
/// The cluster-scoped line and driver options, or empty lists when the line can't be resolved.
Task LoadEquipmentPickContextAsync(string? lineId, CancellationToken ct = default);
///
/// Creates a new UNS area under a cluster. Fails if an area with the same id already exists.
/// Whitespace-only notes are stored as null.
///
/// The owning cluster.
/// The unique area id to create.
/// The area name.
/// Optional notes; whitespace collapses to null.
/// A token to cancel the operation.
/// Success, or a duplicate-id failure.
Task CreateAreaAsync(string clusterId, string unsAreaId, string name, string? notes, CancellationToken ct = default);
///
/// Updates a UNS area's name, notes, and owning cluster. When the cluster changes, the
/// decision-#122 reassignment guard blocks the move if any driver-bound equipment under the
/// area is bound to a driver in a different cluster than the target. Uses last-write-wins
/// optimistic concurrency on .
///
/// The area to update.
/// The new name.
/// The new notes; whitespace collapses to null.
/// The target cluster (may equal the current one).
/// The concurrency token the caller last read.
/// A token to cancel the operation.
/// Success, a missing-row failure, a #122 guard failure, or a concurrency failure.
Task UpdateAreaAsync(string unsAreaId, string name, string? notes, string newClusterId, byte[] rowVersion, CancellationToken ct = default);
///
/// Deletes a UNS area. A missing row is treated as success (already gone). Uses last-write-wins
/// optimistic concurrency; a delete that fails because lines still reference the area surfaces a
/// guidance message.
///
/// The area to delete.
/// The concurrency token the caller last read.
/// A token to cancel the operation.
/// Success, a concurrency failure, or a delete-failed failure.
Task DeleteAreaAsync(string unsAreaId, byte[] rowVersion, CancellationToken ct = default);
///
/// Creates a new UNS line under an area. Fails if a line with the same id already exists.
/// Whitespace-only notes are stored as null.
///
/// The owning area.
/// The unique line id to create.
/// The line name.
/// Optional notes; whitespace collapses to null.
/// A token to cancel the operation.
/// Success, or a duplicate-id failure.
Task CreateLineAsync(string unsAreaId, string unsLineId, string name, string? notes, CancellationToken ct = default);
///
/// Updates a UNS line's owning area, name, and notes. Uses last-write-wins optimistic
/// concurrency on .
///
/// The line to update.
/// The new name.
/// The new notes; whitespace collapses to null.
/// The target parent area.
/// The concurrency token the caller last read.
/// A token to cancel the operation.
/// Success, a missing-row failure, or a concurrency failure.
Task UpdateLineAsync(string unsLineId, string name, string? notes, string newUnsAreaId, byte[] rowVersion, CancellationToken ct = default);
///
/// Deletes a UNS line. A missing row is treated as success (already gone). Uses last-write-wins
/// optimistic concurrency; a delete that fails because equipment still references the line
/// surfaces a guidance message.
///
/// The line to delete.
/// The concurrency token the caller last read.
/// A token to cancel the operation.
/// Success, a concurrency failure, or a delete-failed failure.
Task DeleteLineAsync(string unsLineId, byte[] rowVersion, CancellationToken ct = default);
///
/// Creates a new equipment under a UNS line. The EquipmentId is system-generated
/// (decision #125: EQ- + the first 12 hex chars of a fresh EquipmentUuid).
/// Fails if the line is unset, if the MachineCode is already used fleet-wide, or if the
/// decision-#122 driver-cluster guard trips. Whitespace-only DriverInstanceId/ZTag/SAPID
/// collapse to null.
///
/// The operator-editable equipment fields.
/// A token to cancel the operation.
/// Success, a missing-line failure, a duplicate-MachineCode failure, or a #122 guard failure.
Task CreateEquipmentAsync(EquipmentInput input, CancellationToken ct = default);
///
/// Bulk-imports equipment from a parsed set of rows in a single
/// context, applying the same rules as the single-add path: a row whose UnsLineId does not
/// exist is an error; a row whose DriverInstanceId is set but does not resolve is an error;
/// a driver-bound row whose driver is in a different cluster than its line fails the decision-#122
/// guard; and a row whose MachineCode already exists in the DB or earlier in the
/// same batch is silently skipped (additive-only — never an update). Inserted rows get a
/// system-generated EQ- id and a fresh EquipmentUuid. All inserts are saved once at
/// the end.
///
/// The parsed equipment rows to import.
/// A token to cancel the operation.
/// The insert/skip counts and the per-row error list.
Task ImportEquipmentAsync(IReadOnlyList rows, CancellationToken ct = default);
///
/// Updates an equipment's mutable fields (driver binding, line, name, MachineCode, external
/// ids, and the OPC 40010 identification fields). The decision-#122 driver-cluster guard blocks
/// binding to a driver in a different cluster than the equipment's line. Uses last-write-wins
/// optimistic concurrency on .
///
/// The equipment to update.
/// The new operator-editable equipment fields.
/// The concurrency token the caller last read.
/// A token to cancel the operation.
/// Success, a missing-row failure, a #122 guard failure, or a concurrency failure.
Task UpdateEquipmentAsync(string equipmentId, EquipmentInput input, byte[] rowVersion, CancellationToken ct = default);
///
/// Deletes an equipment. A missing row is treated as success (already gone). Uses last-write-wins
/// optimistic concurrency; a delete that fails because tags or virtual tags still reference the
/// equipment surfaces a guidance message.
///
/// The equipment to delete.
/// The concurrency token the caller last read.
/// A token to cancel the operation.
/// Success, a concurrency failure, or a delete-failed failure.
Task DeleteEquipmentAsync(string equipmentId, byte[] rowVersion, CancellationToken ct = default);
///
/// Loads the drivers eligible to back a tag on the given equipment: drivers in the equipment's
/// cluster (Equipment.UnsLine → UnsArea.ClusterId) whose namespace is Equipment-kind
/// (decision #110 — tree tags are equipment-bound). Ordered by DriverInstanceId. Returns
/// an empty list when the equipment cannot be resolved to a cluster.
///
/// The equipment whose candidate drivers to load.
/// A token to cancel the load.
/// The eligible drivers projected to (DriverInstanceId, Display, DriverType) triples,
/// where DriverType lets the TagModal dispatch to a per-driver-type typed config editor.
Task> LoadTagDriversForEquipmentAsync(string equipmentId, CancellationToken ct = default);
/// Galaxy gateway driver instances (DriverType "GalaxyMxGateway") in the equipment's
/// cluster, for the alias address picker. Tuple = (DriverInstanceId, Display, DriverConfig).
Task>
LoadGalaxyGatewaysForEquipmentAsync(string equipmentId, CancellationToken ct = default);
///
/// Creates a new equipment-bound tag. FolderPath is always null (decision #110 —
/// the tree only edits equipment-bound tags). Fails on a duplicate TagId, invalid
/// TagConfig JSON, an unknown driver, a driver whose namespace is not Equipment-kind, a
/// driver in a different cluster than the equipment (decision #122), or a name already used on
/// the equipment. Whitespace-only PollGroupId collapses to null.
///
/// The owning equipment.
/// The operator-editable tag fields.
/// A token to cancel the operation.
/// Success, or one of the guard failures.
Task CreateTagAsync(string equipmentId, TagInput input, CancellationToken ct = default);
///
/// Updates an equipment-bound tag's driver binding, name, data type, access level, write-retry
/// flag, poll group, and config. The owning EquipmentId and the null
/// FolderPath are preserved. Re-runs the JSON-validity, namespace-kind, and decision-#122
/// cluster guards against the tag's existing equipment, and enforces name uniqueness on that
/// equipment excluding this tag. Uses last-write-wins optimistic concurrency on
/// .
///
/// The tag to update.
/// The new operator-editable tag fields.
/// The concurrency token the caller last read.
/// A token to cancel the operation.
/// Success, a missing-row failure, a guard failure, or a concurrency failure.
Task UpdateTagAsync(string tagId, TagInput input, byte[] rowVersion, CancellationToken ct = default);
///
/// Deletes a tag. A missing row is treated as success (already gone). Uses last-write-wins
/// optimistic concurrency on .
///
/// The tag to delete.
/// The concurrency token the caller last read.
/// A token to cancel the operation.
/// Success, a concurrency failure, or a delete-failed failure.
Task DeleteTagAsync(string tagId, byte[] rowVersion, CancellationToken ct = default);
///
/// Loads the scripts eligible to back a virtual tag, ordered by name. Each is projected to a
/// (ScriptId, Display) pair where Display is "{Name} ({Language})".
///
/// A token to cancel the load.
/// The scripts projected to (ScriptId, Display) pairs.
Task> LoadScriptsAsync(CancellationToken ct = default);
///
/// Creates a new equipment-bound virtual tag (plan decision #2 — virtual tags are always scoped
/// to an equipment). Fails if the equipment does not exist, if no script is chosen, if neither a
/// change trigger nor a timer is set, if the timer is below the 50 ms minimum, on a duplicate
/// VirtualTagId, or on a name already used on the equipment.
///
/// The owning equipment.
/// The operator-editable virtual-tag fields.
/// A token to cancel the operation.
/// Success, or one of the guard failures; or if the chosen script uses the {{equip}}
/// token but the equipment has no derivable single tag base.
Task CreateVirtualTagAsync(string equipmentId, VirtualTagInput input, CancellationToken ct = default);
///
/// Updates an equipment-bound virtual tag's name, data type, script binding, triggers, historize,
/// and enabled flags. The owning EquipmentId is preserved. Re-runs the script-chosen,
/// change-or-timer, and 50 ms timer-minimum guards, and enforces name uniqueness on the tag's
/// existing equipment excluding this virtual tag. Uses last-write-wins optimistic concurrency on
/// .
///
/// The virtual tag to update.
/// The new operator-editable virtual-tag fields.
/// The concurrency token the caller last read.
/// A token to cancel the operation.
/// Success, a missing-row failure, a guard failure, or a concurrency failure; or if the
/// chosen script uses the {{equip}} token but the equipment has no derivable single tag base.
Task UpdateVirtualTagAsync(string virtualTagId, VirtualTagInput input, byte[] rowVersion, CancellationToken ct = default);
///
/// Deletes a virtual tag. A missing row is treated as success (already gone). Uses last-write-wins
/// optimistic concurrency on .
///
/// The virtual tag to delete.
/// The concurrency token the caller last read.
/// A token to cancel the operation.
/// Success, a concurrency failure, or a delete-failed failure.
Task DeleteVirtualTagAsync(string virtualTagId, byte[] rowVersion, CancellationToken ct = default);
///
/// Loads a script's editable source for the inline script-source panel in the virtual-tag modal,
/// along with the concurrency token the panel must echo back on save and the script's display name.
/// Reads untracked. Returns null when the script no longer exists.
///
/// The script whose source to load.
/// A token to cancel the load.
/// The (SourceCode, RowVersion, Name) triple, or null when missing.
Task<(string SourceCode, byte[] RowVersion, string Name)?> GetScriptSourceAsync(string scriptId, CancellationToken ct = default);
///
/// Counts how many virtual tags bind the given script, so the inline editor can warn the operator
/// that an edit to a shared script affects every virtual tag using it.
///
/// The script to count usages of.
/// A token to cancel the query.
/// The number of virtual tags whose ScriptId matches.
Task CountVirtualTagsUsingScriptAsync(string scriptId, CancellationToken ct = default);
///
/// Saves an edited script body from the inline panel: updates SourceCode and recomputes the
/// SHA-256 SourceHash (lower-case hex, matching the Script-edit page). This save is separate
/// from the virtual-tag save and is guarded by its own last-write-wins optimistic concurrency on
/// .
///
/// The script to update.
/// The new source body.
/// The concurrency token the panel last read.
/// A token to cancel the operation.
/// Success, a missing-row failure, or a concurrency failure.
Task<(bool Ok, string? Error)> UpdateScriptSourceAsync(string scriptId, string sourceCode, byte[] rowVersion, CancellationToken ct = default);
///
/// Loads the scripted alarms owned by a single equipment as flat row projections for the equipment
/// page's Alarms tab table, ordered by Name. Each row carries the display columns plus the
/// ScriptedAlarmId the table uses to open the edit modal. Reads untracked. Returns an empty
/// list when the equipment has no scripted alarms.
///
/// The equipment whose scripted alarms to load.
/// A token to cancel the load.
/// The equipment's scripted-alarm rows ordered by Name; empty if it has none.
Task> LoadAlarmsForEquipmentAsync(string equipmentId, CancellationToken ct = default);
///
/// Loads a single scripted alarm projected for editing, or null if it no longer exists.
/// Reads untracked and captures the current concurrency token for last-write-wins saves.
///
/// The scripted alarm to load.
/// A token to cancel the load.
/// The scripted alarm's edit projection, or null when missing.
Task LoadScriptedAlarmAsync(string scriptedAlarmId, CancellationToken ct = default);
///
/// Creates a new scripted alarm under an equipment. The ScriptedAlarmId is operator-typed
/// (not system-generated). Fails on a duplicate ScriptedAlarmId. Field validation (severity
/// range, required fields) is enforced client-side in the modal. On success the operator-typed id is
/// echoed back via .
///
/// The owning equipment.
/// The operator-editable scripted-alarm fields.
/// A token to cancel the operation.
/// Success carrying the created id, or a duplicate-id failure.
Task CreateScriptedAlarmAsync(string equipmentId, ScriptedAlarmInput input, CancellationToken ct = default);
///
/// Updates a scripted alarm's mutable fields (name, alarm type, severity, message template,
/// predicate script, and the historize/retain/enabled flags). The owning EquipmentId is
/// preserved (the Alarms tab fixes it). Uses last-write-wins optimistic concurrency on
/// .
///
/// The scripted alarm to update.
/// The new operator-editable scripted-alarm fields.
/// The concurrency token the caller last read.
/// A token to cancel the operation.
/// Success, a missing-row failure, or a concurrency failure.
Task UpdateScriptedAlarmAsync(string scriptedAlarmId, ScriptedAlarmInput input, byte[] rowVersion, CancellationToken ct = default);
///
/// Deletes a scripted alarm. A missing row is treated as success (already gone). Uses last-write-wins
/// optimistic concurrency on .
///
/// The scripted alarm to delete.
/// The concurrency token the caller last read.
/// A token to cancel the operation.
/// Success, a concurrency failure, or a delete-failed failure.
Task DeleteScriptedAlarmAsync(string scriptedAlarmId, byte[] rowVersion, CancellationToken ct = default);
}