@using EntKube.Web.Data
@using EntKube.Web.Services
@inject KubernetesOperationsService K8sOps

@* ═══════════════════════════════════════════════════════════════════
   ResourceTreePanel — ArgoCD-style resource ownership tree.

   Each node renders as a card with a health-coloured left border,
   kind icon, kind badge, resource name, status and health label.
   Children are indented beneath a dashed vertical guide line,
   matching the ArgoCD Application detail layout.
   ═══════════════════════════════════════════════════════════════════ *@

<style>
    .argo-tree { font-size: .84rem; }

    .argo-node-card {
        display: flex;
        align-items: center;
        gap: 8px;
        border: 1px solid #e9ecef;
        border-left: 3px solid var(--hc, #adb5bd);
        border-radius: 6px;
        padding: 5px 10px;
        background: white;
        box-shadow: 0 1px 3px rgba(0,0,0,.06);
        margin-bottom: 4px;
        min-width: 0;
        transition: background .1s;
    }
    .argo-node-card:hover { background: #f8f9ff; }
    .argo-node-card.panel-open { background: #f0f4ff; border-left-color: #6ea8fe; }

    .argo-children {
        margin-left: 22px;
        padding-left: 14px;
        border-left: 1px dashed #ced4da;
        padding-bottom: 2px;
    }

    .argo-kind-badge {
        font-size: .65rem;
        font-weight: 600;
        letter-spacing: .03em;
        border: 1px solid #dee2e6;
        border-radius: 3px;
        padding: 1px 5px;
        background: #f8f9fa;
        color: #495057;
        white-space: nowrap;
        flex-shrink: 0;
    }

    .argo-action-panel {
        margin-left: 36px;
        margin-bottom: 6px;
        border-radius: 6px;
        border: 1px solid #3a3a4e;
        background: #1e1e2e;
        overflow: hidden;
    }
    .argo-action-toolbar {
        display: flex;
        align-items: center;
        justify-content: space-between;
        padding: 4px 10px;
        background: #2a2a3e;
        border-bottom: 1px solid #3a3a4e;
    }
</style>

@if (Loading)
{
    <div class="text-center py-4">
        <div class="spinner-border spinner-border-sm text-primary" role="status"></div>
        <p class="text-muted small mt-2 mb-0">Querying cluster…</p>
    </div>
}
else if (Error is not null)
{
    <div class="alert alert-warning py-2 small mb-0">
        <i class="bi bi-exclamation-triangle me-1"></i>@Error
    </div>
}
else if (Resources is null || Resources.Count == 0)
{
    <div class="text-center py-4">
        <i class="bi bi-diagram-3 text-muted" style="font-size: 2rem;"></i>
        <p class="text-muted small mt-2 mb-0">
            No resources found in namespace <code>@Namespace</code>.
        </p>
    </div>
}
else
{
    @if (_actionFeedback is not null)
    {
        <div class="alert @(_actionFeedbackOk ? "alert-success" : "alert-danger") alert-dismissible py-2 small mb-3">
            <i class="bi @(_actionFeedbackOk ? "bi-check-circle" : "bi-exclamation-triangle") me-1"></i>
            @_actionFeedback
            <button type="button" class="btn-close btn-close-sm" @onclick="() => _actionFeedback = null"></button>
        </div>
    }

    <div class="argo-tree">
        @foreach (DeploymentResource root in Resources)
        {
            @RenderNode(root)
        }
    </div>
}

@code {
    [Parameter] public bool Loading { get; set; }
    [Parameter] public string? Error { get; set; }
    [Parameter] public List<DeploymentResource>? Resources { get; set; }
    [Parameter] public string? Namespace { get; set; }
    [Parameter] public Guid DeploymentId { get; set; }
    /// <summary>Null = full admin access (tenant view).</summary>
    [Parameter] public CustomerAccessRole? AccessRole { get; set; }

    private bool CanLogs    => AccessRole is null || AccessRole >= CustomerAccessRole.Viewer;
    private bool CanEvents  => AccessRole is null || AccessRole >= CustomerAccessRole.Viewer;
    private bool CanRestart => AccessRole is null || AccessRole >= CustomerAccessRole.Operator;
    private bool CanDelete  => AccessRole is null || AccessRole >= CustomerAccessRole.Operator;
    private bool CanScale   => AccessRole is null || AccessRole >= CustomerAccessRole.Admin;

    private Guid? _activePanelId;
    private string? _panelMode;
    private bool _panelLoading;
    private string? _panelText;
    private string? _panelError;
    private List<string> _containers = [];
    private string? _selectedContainer;
    private int _scaleValue = 1;
    private bool _opBusy;
    private string? _actionFeedback;
    private bool _actionFeedbackOk;

    // ── Static visual helpers ────────────────────────────────────────────────

    private static string HealthColor(HealthStatus h) => h switch
    {
        HealthStatus.Healthy     => "#198754",
        HealthStatus.Progressing => "#0d6efd",
        HealthStatus.Degraded    => "#fd7e14",
        HealthStatus.Missing     => "#dc3545",
        HealthStatus.Suspended   => "#6c757d",
        _                        => "#adb5bd",
    };

    private static string HealthLabel(HealthStatus h) => h switch
    {
        HealthStatus.Healthy     => "Healthy",
        HealthStatus.Progressing => "Progressing",
        HealthStatus.Degraded    => "Degraded",
        HealthStatus.Missing     => "Missing",
        HealthStatus.Suspended   => "Suspended",
        _                        => "Unknown",
    };

    private static string KindIcon(string kind) => kind switch
    {
        "Deployment"            => "bi-layers",
        "StatefulSet"           => "bi-database",
        "DaemonSet"             => "bi-broadcast",
        "ReplicaSet"            => "bi-files",
        "Pod"                   => "bi-cpu",
        "Service"               => "bi-share",
        "Ingress"               => "bi-globe",
        "HTTPRoute"             => "bi-signpost-split",
        "PersistentVolumeClaim" => "bi-hdd",
        "ConfigMap"             => "bi-file-code",
        "Secret"                => "bi-key",
        "Job"                   => "bi-lightning",
        "CronJob"               => "bi-clock",
        _                       => "bi-box",
    };

    private static string KindColor(string kind) => kind switch
    {
        "Deployment" or "StatefulSet" or "DaemonSet" => "text-primary",
        "ReplicaSet"                                  => "text-secondary",
        "Pod"                                         => "text-success",
        "Service" or "Ingress" or "HTTPRoute"         => "text-info",
        "Job" or "CronJob"                            => "text-warning",
        "PersistentVolumeClaim"                       => "text-danger",
        _                                             => "text-muted",
    };

    // ── Panel open/close ─────────────────────────────────────────────────────

    private void ClosePanel()
    {
        _activePanelId = null;
        _panelMode = null;
        _panelText = null;
        _panelError = null;
        _containers = [];
        _selectedContainer = null;
    }

    private bool IsPanelOpen(Guid id, string mode) =>
        _activePanelId == id && _panelMode == mode;

    // ── Action handlers ──────────────────────────────────────────────────────

    private async Task OpenLogPanel(DeploymentResource node)
    {
        if (_activePanelId == node.Id && _panelMode == "logs") { ClosePanel(); return; }
        ClosePanel();
        _activePanelId = node.Id;
        _panelMode = "logs";
        _panelLoading = true;
        StateHasChanged();

        var cr = await K8sOps.GetPodContainersAsync(DeploymentId, node.Name);
        if (!cr.IsSuccess) { _panelError = cr.Error; _panelLoading = false; return; }

        _containers = cr.Data ?? [];
        _selectedContainer = _containers.Count > 0 ? _containers[0] : null;
        await FetchLogs(node.Name);
    }

    private async Task FetchLogs(string podName)
    {
        _panelLoading = true;
        _panelText = null;
        _panelError = null;
        StateHasChanged();

        var r = await K8sOps.GetPodLogsAsync(DeploymentId, podName, _selectedContainer);
        _panelLoading = false;
        if (r.IsSuccess) _panelText = r.Data ?? "(no output)";
        else _panelError = r.Error;
    }

    private async Task OpenEventsPanel(DeploymentResource node)
    {
        if (_activePanelId == node.Id && _panelMode == "events") { ClosePanel(); return; }
        ClosePanel();
        _activePanelId = node.Id;
        _panelMode = "events";
        _panelLoading = true;
        StateHasChanged();

        var r = await K8sOps.GetResourceEventsAsync(DeploymentId, node.Kind, node.Name);
        _panelLoading = false;
        if (r.IsSuccess)
            _panelText = r.Data is { Count: > 0 } lines ? string.Join("\n", lines) : "(no events)";
        else _panelError = r.Error;
    }

    private void OpenScalePanel(DeploymentResource node)
    {
        if (_activePanelId == node.Id && _panelMode == "scale") { ClosePanel(); return; }
        ClosePanel();
        _activePanelId = node.Id;
        _panelMode = "scale";
        _scaleValue = ParseDesiredReplicas(node.StatusMessage) ?? 1;
    }

    private async Task ApplyScale(DeploymentResource node)
    {
        _opBusy = true;
        StateHasChanged();
        var r = await K8sOps.ScaleWorkloadAsync(DeploymentId, node.Kind, node.Name, _scaleValue);
        _opBusy = false;
        ClosePanel();
        Feedback(r.IsSuccess, r.IsSuccess
            ? $"{node.Kind} {node.Name} scaled to {_scaleValue}."
            : r.Error ?? "Scale failed.");
    }

    private void OpenRestartConfirm(DeploymentResource node)
    {
        if (_activePanelId == node.Id && _panelMode == "restart-confirm") { ClosePanel(); return; }
        ClosePanel();
        _activePanelId = node.Id;
        _panelMode = "restart-confirm";
    }

    private async Task ConfirmRestart(DeploymentResource node)
    {
        _opBusy = true;
        StateHasChanged();
        var r = await K8sOps.RestartWorkloadAsync(DeploymentId, node.Kind, node.Name);
        _opBusy = false;
        ClosePanel();
        Feedback(r.IsSuccess, r.IsSuccess
            ? $"Rolling restart triggered for {node.Name}."
            : r.Error ?? "Restart failed.");
    }

    private void OpenDeleteConfirm(DeploymentResource node)
    {
        if (_activePanelId == node.Id && _panelMode == "delete-confirm") { ClosePanel(); return; }
        ClosePanel();
        _activePanelId = node.Id;
        _panelMode = "delete-confirm";
    }

    private async Task ConfirmDelete(DeploymentResource node)
    {
        _opBusy = true;
        StateHasChanged();
        var r = await K8sOps.DeleteResourceAsync(DeploymentId, node.Kind, node.Name);
        _opBusy = false;
        ClosePanel();
        Feedback(r.IsSuccess, r.IsSuccess
            ? $"{node.Kind} {node.Name} deleted."
            : r.Error ?? "Delete failed.");
    }

    private void Feedback(bool ok, string msg)
    {
        _actionFeedbackOk = ok;
        _actionFeedback = msg;
        StateHasChanged();
    }

    private static int? ParseDesiredReplicas(string? s)
    {
        if (string.IsNullOrEmpty(s)) return null;
        int slash = s.IndexOf('/');
        if (slash < 0) return null;
        string after = s[(slash + 1)..].Split(' ')[0];
        return int.TryParse(after, out int n) ? n : null;
    }

    // ── Recursive card renderer ──────────────────────────────────────────────
    //
    // Each call emits one node card, then (if its panel is open) the action
    // panel, then recursively all children inside .argo-children.
    //
    // IMPORTANT: keep this method free of async lambdas and complex captures.
    // Only use simple @onclick="() => SyncMethod(node)" references here.

    private RenderFragment RenderNode(DeploymentResource node) => __builder =>
    {
        string hColor   = HealthColor(node.HealthStatus);
        bool panelOpen  = _activePanelId == node.Id;
        bool hasKids    = node.ChildResources is { Count: > 0 };

        // ── Card ─────────────────────────────────────────────────────────────
        <div class="argo-node-card @(panelOpen ? "panel-open" : "")"
             style="--hc: @hColor">

            <i class="bi @KindIcon(node.Kind) @KindColor(node.Kind)"
               style="font-size: .95rem; flex-shrink: 0;"></i>

            <span class="argo-kind-badge">@node.Kind</span>

            <span class="fw-semibold text-truncate" style="flex: 1 1 0; min-width: 0;"
                  title="@node.Name">@node.Name</span>

            @if (!string.IsNullOrEmpty(node.StatusMessage))
            {
                <span class="text-muted small text-nowrap">@node.StatusMessage</span>
            }

            <span class="small text-nowrap" style="color: @hColor; flex-shrink: 0;">
                ● @HealthLabel(node.HealthStatus)
            </span>

            <div class="d-flex gap-1 flex-shrink-0">
                @if (node.Kind == "Pod" && CanLogs)
                {
                    <button class="btn btn-sm py-0 px-1 @(IsPanelOpen(node.Id, "logs") ? "btn-dark" : "btn-outline-secondary")"
                            title="Logs" @onclick="() => OpenLogPanel(node)">
                        <i class="bi bi-terminal" style="font-size: .72rem;"></i>
                    </button>
                }
                @if (CanEvents)
                {
                    <button class="btn btn-sm py-0 px-1 @(IsPanelOpen(node.Id, "events") ? "btn-secondary" : "btn-outline-secondary")"
                            title="Events" @onclick="() => OpenEventsPanel(node)">
                        <i class="bi bi-list-ul" style="font-size: .72rem;"></i>
                    </button>
                }
                @if (node.Kind is "Deployment" or "StatefulSet" or "DaemonSet" && CanRestart)
                {
                    <button class="btn btn-sm py-0 px-1 @(IsPanelOpen(node.Id, "restart-confirm") ? "btn-warning" : "btn-outline-warning")"
                            title="Restart" @onclick="() => OpenRestartConfirm(node)">
                        <i class="bi bi-arrow-repeat" style="font-size: .72rem;"></i>
                    </button>
                }
                @if (node.Kind is "Deployment" or "StatefulSet" or "ReplicaSet" && CanScale)
                {
                    <button class="btn btn-sm py-0 px-1 @(IsPanelOpen(node.Id, "scale") ? "btn-primary" : "btn-outline-primary")"
                            title="Scale" @onclick="() => OpenScalePanel(node)">
                        <i class="bi bi-sliders" style="font-size: .72rem;"></i>
                    </button>
                }
                @if (node.Kind == "Pod" && CanDelete)
                {
                    <button class="btn btn-sm py-0 px-1 @(IsPanelOpen(node.Id, "delete-confirm") ? "btn-danger" : "btn-outline-danger")"
                            title="Delete pod" @onclick="() => OpenDeleteConfirm(node)">
                        <i class="bi bi-trash" style="font-size: .72rem;"></i>
                    </button>
                }
                @if (node.Kind == "Job" && CanScale)
                {
                    <button class="btn btn-sm py-0 px-1 @(IsPanelOpen(node.Id, "delete-confirm") ? "btn-danger" : "btn-outline-danger")"
                            title="Delete job" @onclick="() => OpenDeleteConfirm(node)">
                        <i class="bi bi-trash" style="font-size: .72rem;"></i>
                    </button>
                }
            </div>
        </div>

        @* ── Action panel (between card and children) ─────────────────────── *@
        @if (panelOpen && _panelMode is not null)
        {
            @RenderActionPanel(node)
        }

        @* ── Children ─────────────────────────────────────────────────────── *@
        @if (hasKids)
        {
            <div class="argo-children">
                @foreach (DeploymentResource child in node.ChildResources!)
                {
                    @RenderNode(child)
                }
            </div>
        }
    };

    // Separate method so the heavy panel HTML is not inside the recursive lambda.
    private RenderFragment RenderActionPanel(DeploymentResource node) => __builder =>
    {
        <div class="argo-action-panel">
            <div class="argo-action-toolbar">
                <span class="text-white small fw-medium">
                    @if (_panelMode == "logs")
                    {
                        <i class="bi bi-terminal me-1"></i>@:Logs — @node.Name
                    }
                    else if (_panelMode == "events")
                    {
                        <i class="bi bi-list-ul me-1"></i>@:Events — @node.Name
                    }
                    else if (_panelMode == "scale")
                    {
                        <i class="bi bi-sliders me-1"></i>@:Scale — @node.Name
                    }
                    else if (_panelMode == "restart-confirm")
                    {
                        <i class="bi bi-arrow-repeat me-1"></i>@:Restart — @node.Name
                    }
                    else if (_panelMode == "delete-confirm")
                    {
                        <i class="bi bi-trash me-1"></i>@:Delete — @node.Name
                    }
                </span>
                <button class="btn btn-sm btn-link text-white py-0 px-1" @onclick="ClosePanel">
                    <i class="bi bi-x"></i>
                </button>
            </div>

            @if (_panelMode == "logs")
            {
                @if (_containers.Count > 1)
                {
                    <div class="px-2 py-1 d-flex gap-2 align-items-center"
                         style="background:#2a2a3e;border-bottom:1px solid #333;">
                        <span class="text-muted small">Container:</span>
                        @foreach (string c in _containers)
                        {
                            string containerName = c;
                            <button class="btn btn-sm py-0 px-2 @(_selectedContainer == containerName ? "btn-primary" : "btn-outline-secondary")"
                                    style="font-size:.7rem;"
                                    @onclick="() => SwitchContainer(node.Name, containerName)">@containerName</button>
                        }
                    </div>
                }
                @if (_panelLoading)
                {
                    <div class="text-center py-3">
                        <div class="spinner-border spinner-border-sm text-light"></div>
                    </div>
                }
                else if (_panelError is not null)
                {
                    <div class="alert alert-warning m-2 py-1 small">@_panelError</div>
                }
                else
                {
                    <pre class="m-0 p-2 small text-light"
                         style="max-height:380px;overflow-y:auto;white-space:pre-wrap;word-break:break-all;font-size:.73rem;background:transparent;">@_panelText</pre>
                }
            }

            @if (_panelMode == "events")
            {
                @if (_panelLoading)
                {
                    <div class="text-center py-3">
                        <div class="spinner-border spinner-border-sm text-light"></div>
                    </div>
                }
                else if (_panelError is not null)
                {
                    <div class="alert alert-warning m-2 py-1 small">@_panelError</div>
                }
                else
                {
                    <pre class="m-0 p-2 small text-light"
                         style="max-height:260px;overflow-y:auto;white-space:pre-wrap;word-break:break-all;font-size:.73rem;background:transparent;">@_panelText</pre>
                }
            }

            @if (_panelMode == "scale")
            {
                <div class="p-3 d-flex align-items-center gap-2 flex-wrap">
                    <span class="text-light small">Replicas for <strong>@node.Name</strong></span>
                    <input type="number" class="form-control form-control-sm"
                           style="width:70px;background:#2a2a3e;border-color:#555;color:white;"
                           min="0" max="99" @bind="_scaleValue" />
                    <button class="btn btn-sm btn-primary" disabled="@_opBusy"
                            @onclick="() => ApplyScale(node)">
                        @if (_opBusy) { <span class="spinner-border spinner-border-sm me-1"></span> }
                        Apply
                    </button>
                    <button class="btn btn-sm btn-outline-secondary" @onclick="ClosePanel">Cancel</button>
                </div>
            }

            @if (_panelMode == "restart-confirm")
            {
                <div class="p-3 d-flex align-items-center gap-2 flex-wrap">
                    <span class="text-light small">Rolling restart <strong>@node.Name</strong>?</span>
                    <button class="btn btn-sm btn-warning" disabled="@_opBusy"
                            @onclick="() => ConfirmRestart(node)">
                        @if (_opBusy) { <span class="spinner-border spinner-border-sm me-1"></span> }
                        <i class="bi bi-arrow-repeat me-1"></i>Restart
                    </button>
                    <button class="btn btn-sm btn-outline-secondary" @onclick="ClosePanel">Cancel</button>
                </div>
            }

            @if (_panelMode == "delete-confirm")
            {
                <div class="p-3 d-flex align-items-center gap-2 flex-wrap">
                    <span class="text-light small">
                        Delete <strong>@node.Kind @node.Name</strong>?
                        @if (node.Kind == "Pod")
                        {
                            <span class="text-muted"> K8s will restart it automatically.</span>
                        }
                    </span>
                    <button class="btn btn-sm btn-danger" disabled="@_opBusy"
                            @onclick="() => ConfirmDelete(node)">
                        @if (_opBusy) { <span class="spinner-border spinner-border-sm me-1"></span> }
                        <i class="bi bi-trash me-1"></i>Delete
                    </button>
                    <button class="btn btn-sm btn-outline-secondary" @onclick="ClosePanel">Cancel</button>
                </div>
            }
        </div>
    };

    // Non-async wrapper to avoid async lambdas inside RenderFragment.
    private void SwitchContainer(string podName, string containerName)
    {
        _selectedContainer = containerName;
        _ = FetchLogs(podName);
    }
}
