@using ZB.MOM.WW.OtOpcUa.Admin.Services
@using ZB.MOM.WW.OtOpcUa.Configuration.Entities
@using ZB.MOM.WW.OtOpcUa.Core.Abstractions
@using ZB.MOM.WW.OtOpcUa.Core.Scripting
@inject ScriptService ScriptSvc
@inject ScriptTestHarnessService Harness

<div class="d-flex justify-content-between align-items-center mb-3">
    <div>
        <h4 class="mb-0">Scripts</h4>
        <small class="text-muted">C# (Roslyn). Used by virtual tags + scripted alarms.</small>
    </div>
    <button class="btn btn-primary" @onclick="StartNew">+ New script</button>
</div>

<script src="/js/monaco-loader.js"></script>

@if (_loading) { <p class="text-muted">Loading…</p> }
else if (_scripts.Count == 0 && _editing is null)
{
    <div class="alert alert-info">No scripts yet in this draft.</div>
}
else
{
    <div class="row">
        <div class="col-md-4">
            <div class="list-group">
                @foreach (var s in _scripts)
                {
                    <button class="list-group-item list-group-item-action @(_editing?.ScriptId == s.ScriptId ? "active" : "")"
                            @onclick="() => Open(s)">
                        <strong>@s.Name</strong>
                        <div class="small text-muted font-monospace">@s.ScriptId</div>
                    </button>
                }
            </div>
        </div>
        <div class="col-md-8">
            @if (_editing is not null)
            {
                <div class="card">
                    <div class="card-header d-flex justify-content-between align-items-center">
                        <strong>@(_isNew ? "New script" : _editing.Name)</strong>
                        <div>
                            @if (!_isNew)
                            {
                                <button class="btn btn-sm btn-outline-danger me-2" @onclick="DeleteAsync">Delete</button>
                            }
                            <button class="btn btn-sm btn-primary" disabled="@_busy" @onclick="SaveAsync">Save</button>
                        </div>
                    </div>
                    <div class="card-body">
                        <div class="mb-2">
                            <label class="form-label">Name</label>
                            <input class="form-control" @bind="_editing.Name"/>
                        </div>
                        <label class="form-label">Source</label>
                        <ScriptEditor @bind-Source="_editing.SourceCode"/>

                        <div class="mt-3">
                            <button class="btn btn-sm btn-outline-secondary" @onclick="PreviewDependencies">Analyze dependencies</button>
                            <button class="btn btn-sm btn-outline-info ms-2" @onclick="RunHarnessAsync" disabled="@_harnessBusy">Run test harness</button>
                        </div>

                        @if (_dependencies is not null)
                        {
                            <div class="mt-3">
                                <strong>Inferred reads</strong>
                                @if (_dependencies.Reads.Count == 0) { <span class="text-muted ms-2">none</span> }
                                else
                                {
                                    <ul class="mb-1">
                                        @foreach (var r in _dependencies.Reads) { <li><code>@r</code></li> }
                                    </ul>
                                }
                                <strong>Inferred writes</strong>
                                @if (_dependencies.Writes.Count == 0) { <span class="text-muted ms-2">none</span> }
                                else
                                {
                                    <ul class="mb-1">
                                        @foreach (var w in _dependencies.Writes) { <li><code>@w</code></li> }
                                    </ul>
                                }
                                @if (_dependencies.Rejections.Count > 0)
                                {
                                    <div class="alert alert-danger mt-2">
                                        <strong>Non-literal paths rejected:</strong>
                                        <ul class="mb-0">
                                            @foreach (var r in _dependencies.Rejections) { <li>@r.Message</li> }
                                        </ul>
                                    </div>
                                }
                            </div>
                        }

                        @if (_testResult is not null)
                        {
                            <div class="mt-3 border-top pt-3">
                                <strong>Harness result:</strong> <span class="badge bg-secondary">@_testResult.Outcome</span>
                                @if (_testResult.Outcome == ScriptTestOutcome.Success)
                                {
                                    <div>Output: <code>@(_testResult.Output?.ToString() ?? "null")</code></div>
                                    @if (_testResult.Writes.Count > 0)
                                    {
                                        <div class="mt-1"><strong>Writes:</strong>
                                            <ul class="mb-0">
                                                @foreach (var kv in _testResult.Writes) { <li><code>@kv.Key</code> = <code>@(kv.Value?.ToString() ?? "null")</code></li> }
                                            </ul>
                                        </div>
                                    }
                                }
                                @if (_testResult.Errors.Count > 0)
                                {
                                    <div class="alert alert-warning mt-2 mb-0">
                                        @foreach (var e in _testResult.Errors) { <div>@e</div> }
                                    </div>
                                }
                                @if (_testResult.LogEvents.Count > 0)
                                {
                                    <div class="mt-2"><strong>Script log output:</strong>
                                        <ul class="small mb-0">
                                            @foreach (var e in _testResult.LogEvents) { <li>[@e.Level] @e.RenderMessage()</li> }
                                        </ul>
                                    </div>
                                }
                            </div>
                        }
                    </div>
                </div>
            }
        </div>
    </div>
}

@code {
    [Parameter] public long GenerationId { get; set; }
    [Parameter] public string ClusterId { get; set; } = string.Empty;

    private bool _loading = true;
    private bool _busy;
    private bool _harnessBusy;
    private bool _isNew;
    private List<Script> _scripts = [];
    private Script? _editing;
    private DependencyExtractionResult? _dependencies;
    private ScriptTestResult? _testResult;

    protected override async Task OnParametersSetAsync()
    {
        _loading = true;
        _scripts = await ScriptSvc.ListAsync(GenerationId, CancellationToken.None);
        _loading = false;
    }

    private void Open(Script s)
    {
        _editing = new Script
        {
            ScriptRowId = s.ScriptRowId, GenerationId = s.GenerationId,
            ScriptId = s.ScriptId, Name = s.Name, SourceCode = s.SourceCode,
            SourceHash = s.SourceHash, Language = s.Language,
        };
        _isNew = false;
        _dependencies = null;
        _testResult = null;
    }

    private void StartNew()
    {
        _editing = new Script
        {
            GenerationId = GenerationId, ScriptId = "",
            Name = "new-script", SourceCode = "return 0;", SourceHash = "",
        };
        _isNew = true;
        _dependencies = null;
        _testResult = null;
    }

    private async Task SaveAsync()
    {
        if (_editing is null) return;
        _busy = true;
        try
        {
            if (_isNew)
                await ScriptSvc.AddAsync(GenerationId, _editing.Name, _editing.SourceCode, CancellationToken.None);
            else
                await ScriptSvc.UpdateAsync(GenerationId, _editing.ScriptId, _editing.Name, _editing.SourceCode, CancellationToken.None);
            _scripts = await ScriptSvc.ListAsync(GenerationId, CancellationToken.None);
            _isNew = false;
        }
        finally { _busy = false; }
    }

    private async Task DeleteAsync()
    {
        if (_editing is null || _isNew) return;
        await ScriptSvc.DeleteAsync(GenerationId, _editing.ScriptId, CancellationToken.None);
        _editing = null;
        _scripts = await ScriptSvc.ListAsync(GenerationId, CancellationToken.None);
    }

    private void PreviewDependencies()
    {
        if (_editing is null) return;
        _dependencies = DependencyExtractor.Extract(_editing.SourceCode);
    }

    private async Task RunHarnessAsync()
    {
        if (_editing is null) return;
        _harnessBusy = true;
        try
        {
            _dependencies ??= DependencyExtractor.Extract(_editing.SourceCode);
            var inputs = new Dictionary<string, DataValueSnapshot>();
            foreach (var read in _dependencies.Reads)
                inputs[read] = new DataValueSnapshot(0.0, 0u, DateTime.UtcNow, DateTime.UtcNow);
            _testResult = await Harness.RunVirtualTagAsync(_editing.SourceCode, inputs, CancellationToken.None);
        }
        finally { _harnessBusy = false; }
    }
}
