@page "/uns/equipment/new"
@page "/uns/equipment/{EquipmentId}"
@* Dedicated tabbed editor for a single equipment, replacing the /uns EquipmentModal. This task builds
   the shell + the Details tab (lifted from EquipmentModal's EditForm) + the create→edit redirect; the
   Tags / Virtual Tags / Alarms tabs render placeholders wired in later tasks. On a successful create the
   page redirects to /uns/equipment/{newId} so the other tabs (disabled while new) become available. *@
@attribute [Authorize(Policy = AdminUiPolicies.ConfigEditor)]
@rendermode RenderMode.InteractiveServer
@using System.ComponentModel.DataAnnotations
@using Microsoft.AspNetCore.Components.Forms
@using ZB.MOM.WW.OtOpcUa.AdminUI.Uns
@using ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Uns
@inject IUnsTreeService Svc
@inject NavigationManager Nav

<PageTitle>Equipment</PageTitle>

<div class="d-flex justify-content-between align-items-center mb-3">
    <h4 class="mb-0">@(IsNew ? "New equipment" : (_equipment?.Name ?? EquipmentId))</h4>
    <a href="/uns" class="btn btn-outline-secondary btn-sm">Back to UNS</a>
</div>

@if (_loading)
{
    <p class="text-muted"><span class="spinner-border spinner-border-sm me-1"></span>Loading…</p>
}
else if (!IsNew && _equipment is null)
{
    <section class="panel notice rise"><span class="mono">@EquipmentId</span> not found.</section>
}
else
{
    <ul class="nav nav-tabs mb-3">
        <li class="nav-item"><button type="button" class="nav-link @TabClass("details")" @onclick='() => _activeTab = "details"'>Details</button></li>
        <li class="nav-item"><button type="button" class="nav-link @TabClass("tags")" @onclick='() => ShowTabAsync("tags")' disabled="@IsNew">Tags</button></li>
        <li class="nav-item"><button type="button" class="nav-link @TabClass("vtags")" @onclick='() => ShowTabAsync("vtags")' disabled="@IsNew">Virtual Tags</button></li>
        <li class="nav-item"><button type="button" class="nav-link @TabClass("alarms")" @onclick='() => ShowTabAsync("alarms")' disabled="@IsNew">Alarms</button></li>
    </ul>

    @if (_activeTab == "details")
    {
        <EditForm Model="_form" OnValidSubmit="SaveAsync" FormName="equipmentDetails">
            <DataAnnotationsValidator />

            <h6 class="text-muted">Identity</h6>
            @if (!IsNew)
            {
                <div class="mb-3">
                    <label class="form-label">EquipmentId</label>
                    <input class="form-control form-control-sm mono" value="@_equipment?.EquipmentId" disabled />
                    <div class="form-text">System-generated; never operator-edited.</div>
                </div>
            }
            <div class="row">
                <div class="col-md-6 mb-3">
                    <label class="form-label" for="eq-name">Name</label>
                    <InputText id="eq-name" @bind-Value="_form.Name" class="form-control form-control-sm mono"
                               placeholder="machine-01" />
                    <div class="form-text">UNS level 5 segment; lowercase letters, digits, dashes, up to 32 chars.</div>
                    <ValidationMessage For="@(() => _form.Name)" />
                </div>
                <div class="col-md-6 mb-3">
                    <label class="form-label" for="eq-machinecode">MachineCode</label>
                    <InputText id="eq-machinecode" @bind-Value="_form.MachineCode" class="form-control form-control-sm mono"
                               placeholder="machine_001" />
                    <ValidationMessage For="@(() => _form.MachineCode)" />
                </div>
            </div>
            <div class="row">
                <div class="col-md-6 mb-3">
                    <label class="form-label" for="eq-line">UNS line</label>
                    <InputSelect id="eq-line" @bind-Value="_form.UnsLineId" class="form-select form-select-sm">
                        <option value="">— pick a line —</option>
                        @foreach (var (id, display) in _lineOptions)
                        {
                            <option value="@id">@display</option>
                        }
                    </InputSelect>
                    <ValidationMessage For="@(() => _form.UnsLineId)" />
                </div>
            </div>
            @* v3: equipment no longer binds a driver — device I/O is authored in the /raw tree and surfaced
               here by reference on the Tags tab. The old "Driver instance" select was removed. *@
            <div class="row">
                <div class="col-md-6 mb-3">
                    <label class="form-label" for="eq-ztag">ZTag (ERP)</label>
                    <InputText id="eq-ztag" @bind-Value="_form.ZTag" class="form-control form-control-sm" />
                    <div class="form-text">Unique fleet-wide via ExternalIdReservation.</div>
                </div>
                <div class="col-md-6 mb-3">
                    <label class="form-label" for="eq-sap">SAPID</label>
                    <InputText id="eq-sap" @bind-Value="_form.SAPID" class="form-control form-control-sm" />
                </div>
            </div>
            <div class="mb-3">
                <label class="form-label">Enabled</label>
                <div class="form-check form-switch">
                    <InputCheckbox @bind-Value="_form.Enabled" class="form-check-input" />
                    <label class="form-check-label">Surface in deployments</label>
                </div>
            </div>

            <hr />
            <h6 class="text-muted">OPC 40010 identification (optional)</h6>
            <div class="row">
                <div class="col-md-4 mb-3"><label class="form-label">Manufacturer</label><InputText @bind-Value="_form.Manufacturer" class="form-control form-control-sm" /></div>
                <div class="col-md-4 mb-3"><label class="form-label">Model</label><InputText @bind-Value="_form.Model" class="form-control form-control-sm" /></div>
                <div class="col-md-4 mb-3"><label class="form-label">SerialNumber</label><InputText @bind-Value="_form.SerialNumber" class="form-control form-control-sm" /></div>
            </div>
            <div class="row">
                <div class="col-md-3 mb-3"><label class="form-label">HardwareRevision</label><InputText @bind-Value="_form.HardwareRevision" class="form-control form-control-sm" /></div>
                <div class="col-md-3 mb-3"><label class="form-label">SoftwareRevision</label><InputText @bind-Value="_form.SoftwareRevision" class="form-control form-control-sm" /></div>
                <div class="col-md-3 mb-3"><label class="form-label">Year of construction</label><InputNumber @bind-Value="_form.YearOfConstruction" class="form-control form-control-sm" /></div>
                <div class="col-md-3 mb-3"><label class="form-label">AssetLocation</label><InputText @bind-Value="_form.AssetLocation" class="form-control form-control-sm" /></div>
            </div>
            <div class="row">
                <div class="col-md-6 mb-3"><label class="form-label">ManufacturerUri</label><InputText @bind-Value="_form.ManufacturerUri" class="form-control form-control-sm mono" /></div>
                <div class="col-md-6 mb-3"><label class="form-label">DeviceManualUri</label><InputText @bind-Value="_form.DeviceManualUri" class="form-control form-control-sm mono" /></div>
            </div>

            @if (!string.IsNullOrWhiteSpace(_error)) { <div class="text-danger small mt-2">@_error</div> }

            <div class="mt-3">
                <button type="submit" class="btn btn-primary" disabled="@_busy">
                    @if (_busy) { <span class="spinner-border spinner-border-sm me-1"></span> }
                    @(IsNew ? "Create" : "Save changes")
                </button>
            </div>
        </EditForm>
    }
    else if (_activeTab == "tags")
    {
        @* v3 Batch 3: equipment is reference-only — the Tags tab lists UnsTagReference rows pointing at
           raw tags. Datatype/access are inherited (read-only) from the backing raw tag; the display-name
           override is the only per-reference editable field. *@
        <div class="d-flex justify-content-end align-items-center gap-2 mb-2">
            <button type="button" class="btn btn-outline-primary btn-sm" @onclick="OpenAddReference">+ Add reference</button>
        </div>
        @if (!string.IsNullOrWhiteSpace(_refError))
        {
            <div class="text-danger small mb-2">@_refError</div>
        }
        @if (_refs is null)
        {
            <p class="text-muted"><span class="spinner-border spinner-border-sm me-1"></span>Loading…</p>
        }
        else if (_refs.Count == 0)
        {
            <p class="text-muted">No tag references yet.</p>
        }
        else
        {
            <table class="table table-sm align-middle">
                <thead>
                    <tr>
                        <th>Effective name</th><th>Raw path</th><th>Data type</th><th>Access</th>
                        <th>Display-name override</th><th class="text-end">Actions</th>
                    </tr>
                </thead>
                <tbody>
                    @foreach (var r in _refs)
                    {
                        <tr @key="r.UnsTagReferenceId">
                            <td>@r.EffectiveName</td>
                            <td class="mono small">@r.RawPath</td>
                            <td>@r.DataType</td>
                            <td>@r.AccessLevel</td>
                            <td>
                                <input class="form-control form-control-sm" @bind="_overrideEdits[r.UnsTagReferenceId]"
                                       placeholder="(uses raw name)" />
                            </td>
                            <td class="text-end text-nowrap">
                                <button type="button" class="btn btn-outline-secondary btn-sm me-1" @onclick="() => SaveOverride(r)">Save name</button>
                                <button type="button" class="btn btn-outline-danger btn-sm" @onclick="() => RemoveReference(r)">Remove</button>
                            </td>
                        </tr>
                    }
                </tbody>
            </table>
        }

        <AddReferenceModal Visible="_refModalVisible" EquipmentId="@EquipmentId"
                           OnCommitted="OnReferencesCommittedAsync" OnCancel="@(() => { _refModalVisible = false; })" />
    }
    else if (_activeTab == "vtags")
    {
        <div class="d-flex justify-content-end mb-2">
            <button type="button" class="btn btn-outline-primary btn-sm" @onclick="OpenAddVirtualTag">Add virtual tag</button>
        </div>
        @if (!string.IsNullOrWhiteSpace(_vtagError))
        {
            <div class="text-danger small mb-2">@_vtagError</div>
        }
        @if (_vtags is null)
        {
            <p class="text-muted"><span class="spinner-border spinner-border-sm me-1"></span>Loading…</p>
        }
        else if (_vtags.Count == 0)
        {
            <p class="text-muted">No virtual tags yet.</p>
        }
        else
        {
            <table class="table table-sm">
                <thead>
                    <tr><th>Name</th><th>Data type</th><th>Script</th><th>Enabled</th><th class="text-end">Actions</th></tr>
                </thead>
                <tbody>
                    @foreach (var v in _vtags)
                    {
                        <tr @key="v.VirtualTagId">
                            <td>@v.Name</td>
                            <td>@v.DataType</td>
                            <td class="mono">@v.ScriptId</td>
                            <td>@(v.Enabled ? "Yes" : "No")</td>
                            <td class="text-end">
                                <button type="button" class="btn btn-outline-secondary btn-sm me-1" @onclick="() => OpenEditVirtualTag(v.VirtualTagId)">Edit</button>
                                <button type="button" class="btn btn-outline-danger btn-sm" @onclick="() => DeleteVirtualTag(v.VirtualTagId)">Delete</button>
                            </td>
                        </tr>
                    }
                </tbody>
            </table>
        }

        <VirtualTagModal Visible="_vtagModalVisible" IsNew="_vtagModalIsNew" EquipmentId="@EquipmentId"
                         Existing="_vtagModalExisting" Scripts="_vtagScriptOptions"
                         OnSaved="OnVirtualTagSavedAsync" OnCancel="@(() => { _vtagModalVisible = false; })" />
    }
    else if (_activeTab == "alarms")
    {
        <div class="d-flex justify-content-end mb-2">
            <button type="button" class="btn btn-outline-primary btn-sm" @onclick="OpenAddAlarm">Add alarm</button>
        </div>
        @if (!string.IsNullOrWhiteSpace(_alarmError))
        {
            <div class="text-danger small mb-2">@_alarmError</div>
        }
        @if (_alarms is null)
        {
            <p class="text-muted"><span class="spinner-border spinner-border-sm me-1"></span>Loading…</p>
        }
        else if (_alarms.Count == 0)
        {
            <p class="text-muted">No alarms yet.</p>
        }
        else
        {
            <table class="table table-sm">
                <thead>
                    <tr><th>Name</th><th>Type</th><th>Severity</th><th>Predicate</th><th>Enabled</th><th class="text-end">Actions</th></tr>
                </thead>
                <tbody>
                    @foreach (var a in _alarms)
                    {
                        <tr @key="a.ScriptedAlarmId">
                            <td>@a.Name</td>
                            <td>@a.AlarmType</td>
                            <td>@a.Severity</td>
                            <td class="mono">@a.PredicateScriptId</td>
                            <td>@(a.Enabled ? "Yes" : "No")</td>
                            <td class="text-end">
                                <button type="button" class="btn btn-outline-secondary btn-sm me-1" @onclick="() => OpenEditAlarm(a.ScriptedAlarmId)">Edit</button>
                                <button type="button" class="btn btn-outline-danger btn-sm" @onclick="() => DeleteAlarm(a.ScriptedAlarmId)">Delete</button>
                            </td>
                        </tr>
                    }
                </tbody>
            </table>
        }

        <ScriptedAlarmModal Visible="_alarmModalVisible" IsNew="_alarmModalIsNew" EquipmentId="@EquipmentId"
                            Existing="_alarmModalExisting" Scripts="_alarmScriptOptions"
                            OnSaved="OnAlarmSavedAsync" OnCancel="@(() => { _alarmModalVisible = false; })" />
    }
}

@code {
    /// <summary>The equipment id from the route; null/empty on the <c>/new</c> route (create mode).</summary>
    [Parameter] public string? EquipmentId { get; set; }

    /// <summary>Optional parent line id supplied as a query string on create, used to default the line select.</summary>
    [SupplyParameterFromQuery] public string? LineId { get; set; }

    private bool IsNew => string.IsNullOrEmpty(EquipmentId);

    private string _activeTab = "details";
    private bool _loading = true;
    private bool _busy;
    private string? _error;
    private EquipmentEditDto? _equipment;
    private FormModel _form = new();
    private IReadOnlyList<(string Id, string Display)> _lineOptions = Array.Empty<(string, string)>();

    // --- Tags tab state (v3 reference-only). _refs is null until the tab is first activated (lazy load +
    // spinner). _overrideEdits carries the per-row editable display-name override, keyed by reference id. ---
    private IReadOnlyList<EquipmentReferenceRow>? _refs;
    private readonly Dictionary<string, string?> _overrideEdits = new(StringComparer.Ordinal);
    private string? _refError;
    private bool _refModalVisible;

    // --- Virtual Tags tab state. _vtags is null until the tab is first activated. ---
    private IReadOnlyList<EquipmentVirtualTagRow>? _vtags;
    private string? _vtagError;
    private bool _vtagModalVisible;
    private bool _vtagModalIsNew;
    private VirtualTagEditDto? _vtagModalExisting;
    private IReadOnlyList<(string Id, string Display)> _vtagScriptOptions = Array.Empty<(string, string)>();

    // --- Alarms tab state. _alarms is null until the tab is first activated. ---
    private IReadOnlyList<EquipmentAlarmRow>? _alarms;
    private string? _alarmError;
    private bool _alarmModalVisible;
    private bool _alarmModalIsNew;
    private ScriptedAlarmEditDto? _alarmModalExisting;
    private IReadOnlyList<(string Id, string Display)> _alarmScriptOptions = Array.Empty<(string, string)>();

    private string TabClass(string tab) => _activeTab == tab ? "active" : "";

    /// <summary>
    /// Switches to a tab, lazily loading its list on first activation. The Tags/Virtual Tags lists are
    /// null until first shown (and are reset to null in OnParametersSetAsync when the equipment changes),
    /// so the fetch runs once per equipment rather than on every render. Equipment is fixed to
    /// <see cref="EquipmentId"/>; the tabs are disabled while IsNew so this is only ever reached with a
    /// persisted equipment.
    /// </summary>
    private async Task ShowTabAsync(string tab)
    {
        _activeTab = tab;
        if (IsNew) { return; }
        if (tab == "tags" && _refs is null) { await ReloadReferencesAsync(); }
        else if (tab == "vtags" && _vtags is null) { await ReloadVirtualTagsAsync(); }
        else if (tab == "alarms" && _alarms is null) { await ReloadAlarmsAsync(); }
    }

    // --- Tags tab handlers (v3 reference-only; the owning equipment is fixed = EquipmentId) ---

    private async Task ReloadReferencesAsync()
    {
        _refs = await Svc.LoadReferencesForEquipmentAsync(EquipmentId!);
        // Seed the per-row override edit buffer so each row's <input> binds to a live value.
        _overrideEdits.Clear();
        foreach (var r in _refs) { _overrideEdits[r.UnsTagReferenceId] = r.DisplayNameOverride; }
    }

    private void OpenAddReference()
    {
        _refError = null;
        _refModalVisible = true;
    }

    private async Task OnReferencesCommittedAsync()
    {
        _refModalVisible = false;
        await ReloadReferencesAsync();
    }

    private async Task SaveOverride(EquipmentReferenceRow r)
    {
        _refError = null;
        var edited = _overrideEdits.GetValueOrDefault(r.UnsTagReferenceId);
        var res = await Svc.SetReferenceOverrideAsync(r.UnsTagReferenceId, edited, r.RowVersion);
        if (res.Ok) { await ReloadReferencesAsync(); }
        else { _refError = res.Error; }
    }

    private async Task RemoveReference(EquipmentReferenceRow r)
    {
        _refError = null;
        var res = await Svc.RemoveReferenceAsync(r.UnsTagReferenceId, r.RowVersion);
        if (res.Ok) { await ReloadReferencesAsync(); }
        else { _refError = res.Error; }
    }

    // --- Virtual Tags tab handlers ---

    private async Task ReloadVirtualTagsAsync()
    {
        _vtags = await Svc.LoadVirtualTagsForEquipmentAsync(EquipmentId!);
    }

    private async Task OpenAddVirtualTag()
    {
        _vtagError = null;
        _vtagModalIsNew = true;
        _vtagModalExisting = null;
        _vtagScriptOptions = await Svc.LoadScriptsAsync();
        _vtagModalVisible = true;
    }

    private async Task OpenEditVirtualTag(string vtagId)
    {
        _vtagError = null;
        var dto = await Svc.LoadVirtualTagAsync(vtagId);
        if (dto is null) { _vtagError = "That virtual tag no longer exists; the list was refreshed."; await ReloadVirtualTagsAsync(); return; }
        _vtagModalIsNew = false;
        _vtagModalExisting = dto;
        _vtagScriptOptions = await Svc.LoadScriptsAsync();
        _vtagModalVisible = true;
    }

    private async Task OnVirtualTagSavedAsync()
    {
        _vtagModalVisible = false;
        await ReloadVirtualTagsAsync();
    }

    private async Task DeleteVirtualTag(string vtagId)
    {
        _vtagModalVisible = false;
        _vtagError = null;
        // Load the virtual tag fresh to capture its current RowVersion for the concurrency-guarded delete.
        var dto = await Svc.LoadVirtualTagAsync(vtagId);
        if (dto is null) { await ReloadVirtualTagsAsync(); return; }
        var r = await Svc.DeleteVirtualTagAsync(vtagId, dto.RowVersion);
        if (r.Ok) { await ReloadVirtualTagsAsync(); }
        else { _vtagError = r.Error; }
    }

    // --- Alarms tab handlers (mirror the Tags/Virtual Tags tabs; the owning equipment is fixed = EquipmentId) ---

    private async Task ReloadAlarmsAsync()
    {
        _alarms = await Svc.LoadAlarmsForEquipmentAsync(EquipmentId!);
    }

    private async Task OpenAddAlarm()
    {
        _alarmError = null;
        _alarmModalIsNew = true;
        _alarmModalExisting = null;
        _alarmScriptOptions = await Svc.LoadScriptsAsync();
        _alarmModalVisible = true;
    }

    private async Task OpenEditAlarm(string scriptedAlarmId)
    {
        _alarmError = null;
        var dto = await Svc.LoadScriptedAlarmAsync(scriptedAlarmId);
        if (dto is null) { _alarmError = "That alarm no longer exists; the list was refreshed."; await ReloadAlarmsAsync(); return; }
        _alarmModalIsNew = false;
        _alarmModalExisting = dto;
        _alarmScriptOptions = await Svc.LoadScriptsAsync();
        _alarmModalVisible = true;
    }

    private async Task OnAlarmSavedAsync()
    {
        _alarmModalVisible = false;
        await ReloadAlarmsAsync();
    }

    private async Task DeleteAlarm(string scriptedAlarmId)
    {
        _alarmModalVisible = false;
        _alarmError = null;
        // Load the alarm fresh to capture its current RowVersion for the concurrency-guarded delete.
        var dto = await Svc.LoadScriptedAlarmAsync(scriptedAlarmId);
        if (dto is null) { await ReloadAlarmsAsync(); return; }
        var r = await Svc.DeleteScriptedAlarmAsync(scriptedAlarmId, dto.RowVersion);
        if (r.Ok) { await ReloadAlarmsAsync(); }
        else { _alarmError = r.Error; }
    }

    protected override async Task OnParametersSetAsync()
    {
        _loading = true;
        _error = null;
        // _activeTab is intentionally NOT reset here: an in-place save reloads the page (re-runs
        // OnParametersSetAsync) and the user's tab selection should survive that. The create→redirect
        // path lands on Details because the field initializes to "details" and a fresh page instance
        // starts with that initial value. The Tags/Virtual Tags lists are reset to null below so the
        // lazy loaders re-fetch for the (possibly different) equipment this parameter set targets.
        _refs = null;
        _vtags = null;
        _alarms = null;
        if (!IsNew)
        {
            _equipment = await Svc.LoadEquipmentAsync(EquipmentId!);
            if (_equipment is not null)
            {
                LoadFormFrom(_equipment);
                var ctx = await Svc.LoadEquipmentPickContextAsync(_equipment.UnsLineId);
                _lineOptions = ctx.Lines;
            }
        }
        else
        {
            _form = new FormModel { UnsLineId = LineId ?? "" };
            var ctx = await Svc.LoadEquipmentPickContextAsync(LineId);
            _lineOptions = ctx.Lines;
        }
        _loading = false;
    }

    /// <summary>Maps a loaded equipment's fields into the working form (mirrors EquipmentModal's edit branch).</summary>
    private void LoadFormFrom(EquipmentEditDto e)
    {
        _form = new FormModel
        {
            Name = e.Name,
            MachineCode = e.MachineCode,
            UnsLineId = e.UnsLineId,
            ZTag = e.ZTag,
            SAPID = e.SAPID,
            Manufacturer = e.Manufacturer,
            Model = e.Model,
            SerialNumber = e.SerialNumber,
            HardwareRevision = e.HardwareRevision,
            SoftwareRevision = e.SoftwareRevision,
            YearOfConstruction = e.YearOfConstruction,
            AssetLocation = e.AssetLocation,
            ManufacturerUri = e.ManufacturerUri,
            DeviceManualUri = e.DeviceManualUri,
            Enabled = e.Enabled,
        };
    }

    private async Task SaveAsync()
    {
        _busy = true;
        _error = null;
        try
        {
            var input = new EquipmentInput(
                _form.Name,
                _form.MachineCode,
                _form.UnsLineId,
                _form.ZTag,
                _form.SAPID,
                _form.Manufacturer,
                _form.Model,
                _form.SerialNumber,
                _form.HardwareRevision,
                _form.SoftwareRevision,
                _form.YearOfConstruction,
                _form.AssetLocation,
                _form.ManufacturerUri,
                _form.DeviceManualUri,
                _form.Enabled);

            var result = IsNew
                ? await Svc.CreateEquipmentAsync(input)
                : await Svc.UpdateEquipmentAsync(_equipment!.EquipmentId, input, _equipment.RowVersion);

            if (!result.Ok) { _error = result.Error; return; }

            if (IsNew)
            {
                // Redirect to the persisted editor so the other tabs (disabled while new) become available.
                if (string.IsNullOrEmpty(result.CreatedId)) { _error = "Equipment was created but no id was returned."; return; }
                Nav.NavigateTo($"/uns/equipment/{result.CreatedId}");
            }
            else
            {
                // Reload to pick up the fresh RowVersion for the next save.
                _equipment = await Svc.LoadEquipmentAsync(EquipmentId!);
                if (_equipment is not null) { LoadFormFrom(_equipment); }
            }
        }
        finally
        {
            _busy = false;
        }
    }

    /// <summary>The working form for the Details tab — identical to EquipmentModal.FormModel.</summary>
    private sealed class FormModel
    {
        [Required, RegularExpression("^[a-z0-9-]{1,32}$", ErrorMessage = "Lowercase letters, digits, dashes only; max 32 chars.")]
        public string Name { get; set; } = "";
        [Required] public string MachineCode { get; set; } = "";
        [Required] public string UnsLineId { get; set; } = "";
        public string? ZTag { get; set; }
        public string? SAPID { get; set; }
        public string? Manufacturer { get; set; }
        public string? Model { get; set; }
        public string? SerialNumber { get; set; }
        public string? HardwareRevision { get; set; }
        public string? SoftwareRevision { get; set; }
        public short? YearOfConstruction { get; set; }
        public string? AssetLocation { get; set; }
        public string? ManufacturerUri { get; set; }
        public string? DeviceManualUri { get; set; }
        public bool Enabled { get; set; } = true;
    }
}
