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

@* ═══════════════════════════════════════════════════════════════════
   AppResourcesPanel — app-level resource overview.

   Shows each deployment as an ArgoCD-style Application card. Clicking
   a card expands its resource tree inline. Multiple cards can be open
   simultaneously.

   Card layout mirrors the ArgoCD Application grid:
     ┌──────────────────────────────────────┐
     │ [icon]  deployment-name              │
     │         [type] env · cluster · ns    │
     │         ● Healthy  ○ Synced          │
     └──────────────────────────────────────┘
   ═══════════════════════════════════════════════════════════════════ *@

<style>
    .app-argo-grid {
        display: grid;
        grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
        gap: 12px;
        margin-bottom: 24px;
    }

    .app-card {
        border: 1px solid #e9ecef;
        border-top: 3px solid var(--hc, #adb5bd);
        border-radius: 8px;
        background: white;
        box-shadow: 0 1px 4px rgba(0,0,0,.07);
        cursor: pointer;
        transition: box-shadow .15s, border-color .15s;
        padding: 12px 14px;
        display: flex;
        flex-direction: column;
        gap: 6px;
        user-select: none;
    }
    .app-card:hover { box-shadow: 0 3px 10px rgba(0,0,0,.12); }
    .app-card.expanded {
        border-color: #6ea8fe;
        box-shadow: 0 0 0 2px rgba(13,110,253,.15), 0 2px 8px rgba(0,0,0,.08);
    }

    .app-card-header {
        display: flex;
        align-items: flex-start;
        gap: 10px;
    }

    .app-card-icon {
        width: 36px;
        height: 36px;
        border-radius: 8px;
        background: #f0f4ff;
        display: flex;
        align-items: center;
        justify-content: center;
        flex-shrink: 0;
        font-size: 1.1rem;
    }

    .app-card-title {
        font-weight: 600;
        font-size: .88rem;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
        max-width: 180px;
    }

    .app-card-meta {
        font-size: .73rem;
        color: #6c757d;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }

    .app-card-status {
        display: flex;
        align-items: center;
        gap: 8px;
        margin-top: 2px;
    }

    .argo-badge-health, .argo-badge-sync {
        display: inline-flex;
        align-items: center;
        gap: 3px;
        font-size: .7rem;
        font-weight: 500;
        padding: 2px 7px;
        border-radius: 20px;
        border: 1px solid;
        white-space: nowrap;
    }

    .tree-section {
        background: #f8f9fb;
        border: 1px solid #e9ecef;
        border-radius: 8px;
        padding: 16px;
        margin-bottom: 12px;
    }
    .tree-section-header {
        display: flex;
        align-items: center;
        justify-content: space-between;
        margin-bottom: 12px;
    }
</style>

<div class="app-argo-grid">
    @if (deployments is null)
    {
        @for (int i = 0; i < 3; i++)
        {
            <div class="app-card" style="opacity:.5;pointer-events:none;">
                <div class="app-card-header">
                    <div class="app-card-icon"><i class="bi bi-rocket-takeoff text-primary"></i></div>
                    <div style="flex:1;">
                        <div class="app-card-title text-muted">Loading…</div>
                        <div class="app-card-meta">—</div>
                    </div>
                </div>
            </div>
        }
    }
    else if (deployments.Count == 0)
    {
        <div style="grid-column: 1/-1;" class="text-center py-5">
            <i class="bi bi-rocket-takeoff text-muted" style="font-size: 2.5rem;"></i>
            <p class="text-muted small mt-2 mb-0">No deployments yet. Create one in the Deployments tab.</p>
        </div>
    }
    else
    {
        @foreach (AppDeployment d in deployments)
        {
            string hc = HealthColor(d.HealthStatus);
            bool open = expandedIds.Contains(d.Id);

            <div class="app-card @(open ? "expanded" : "")"
                 style="--hc: @hc;"
                 @onclick="() => ToggleDeployment(d.Id)">

                <div class="app-card-header">
                    <div class="app-card-icon">
                        <i class="bi @TypeIcon(d.Type) text-primary"></i>
                    </div>
                    <div style="flex: 1; min-width: 0;">
                        <div class="app-card-title" title="@d.Name">@d.Name</div>
                        <div class="app-card-meta">
                            @TypeLabel(d.Type) · @d.Environment?.Name · @d.Namespace
                        </div>
                    </div>
                    <i class="bi @(open ? "bi-chevron-up" : "bi-chevron-down") text-muted small"></i>
                </div>

                <div class="app-card-status">
                    @{
                        string hcol = HealthColor(d.HealthStatus);
                        string hlbl = HealthLabel(d.HealthStatus);
                        var (scol, sico, slbl) = SyncInfo(d.SyncStatus);
                    }
                    <span class="argo-badge-health" style="color:@hcol;border-color:@hcol;">
                        ● @hlbl
                    </span>
                    <span class="argo-badge-sync" style="color:@scol;border-color:@scol;">
                        <i class="bi @sico"></i> @slbl
                    </span>
                    @if (d.GitRepositoryId is not null && d.GitLastSyncedCommit is not null)
                    {
                        <span class="badge bg-secondary" style="font-size:.65rem;">
                            @d.GitLastSyncedCommit[..7]
                        </span>
                    }
                </div>

                @if (d.Cluster is not null)
                {
                    <div style="font-size:.72rem; color:#6c757d;">
                        <i class="bi bi-hdd-network me-1"></i>@d.Cluster.Name
                    </div>
                }
            </div>
        }
    }
</div>

@* ── Expanded resource trees ─────────────────────────────────────────────── *@
@if (deployments is not null)
{
    @foreach (AppDeployment d in deployments.Where(d => expandedIds.Contains(d.Id)))
    {
        <div class="tree-section">
            <div class="tree-section-header">
                <div class="d-flex align-items-center gap-2">
                    <i class="bi bi-diagram-3 text-primary"></i>
                    <strong class="small">@d.Name</strong>
                    <span class="text-muted small">/ @d.Namespace</span>
                    @if (loadingIds.Contains(d.Id))
                    {
                        <div class="spinner-border spinner-border-sm text-primary" style="width:.9rem;height:.9rem;"></div>
                    }
                </div>
                <button class="btn btn-sm btn-link text-muted p-0" @onclick="() => expandedIds.Remove(d.Id)" @onclick:stopPropagation>
                    <i class="bi bi-x-lg"></i>
                </button>
            </div>

            @if (treeErrors.TryGetValue(d.Id, out string? err))
            {
                <div class="alert alert-warning py-1 small mb-0">
                    <i class="bi bi-exclamation-triangle me-1"></i>@err
                </div>
            }
            else
            {
                <ResourceTreePanel Loading="@loadingIds.Contains(d.Id)"
                                   Error="@(treeErrors.TryGetValue(d.Id, out var e2) ? e2 : null)"
                                   Resources="@(trees.TryGetValue(d.Id, out var t) ? t : null)"
                                   Namespace="@d.Namespace"
                                   DeploymentId="@d.Id"
                                   AccessRole="@null" />
            }
        </div>
    }
}

@code {
    [Parameter, EditorRequired] public Guid AppId { get; set; }

    private List<AppDeployment>? deployments;
    private HashSet<Guid> expandedIds = [];
    private HashSet<Guid> loadingIds = [];
    private Dictionary<Guid, List<DeploymentResource>> trees = [];
    private Dictionary<Guid, string> treeErrors = [];

    protected override async Task OnInitializedAsync()
    {
        deployments = await DeploymentService.GetDeploymentsAsync(AppId);
    }

    private async Task ToggleDeployment(Guid id)
    {
        if (expandedIds.Contains(id))
        {
            expandedIds.Remove(id);
            return;
        }

        expandedIds.Add(id);

        if (trees.ContainsKey(id)) return;

        loadingIds.Add(id);
        treeErrors.Remove(id);
        StateHasChanged();

        KubernetesOperationResult<List<DeploymentResource>> result =
            await K8sOps.GetLiveResourcesAsync(id);

        loadingIds.Remove(id);

        if (result.IsSuccess && result.Data is not null)
        {
            trees[id] = result.Data;
            (SyncStatus sync, HealthStatus health) = KubernetesOperationsService.ComputeStatusFromResources(result.Data);
            AppDeployment? d = deployments?.FirstOrDefault(x => x.Id == id);
            if (d is not null) { d.SyncStatus = sync; d.HealthStatus = health; }
        }
        else
        {
            treeErrors[id] = result.Error ?? "Failed to fetch resources.";
        }
    }

    // ── Badge / label 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 color, string icon, string label) SyncInfo(SyncStatus s) => s switch
    {
        SyncStatus.Synced    => ("#198754", "bi-check-circle",      "Synced"),
        SyncStatus.OutOfSync => ("#fd7e14", "bi-arrow-left-right",  "OutOfSync"),
        SyncStatus.Syncing   => ("#0d6efd", "bi-arrow-repeat",      "Syncing"),
        SyncStatus.Failed    => ("#dc3545", "bi-x-circle",          "Failed"),
        _                    => ("#adb5bd", "bi-question-circle",    "Unknown"),
    };

    private static string TypeIcon(DeploymentType t) => t switch
    {
        DeploymentType.HelmChart   => "bi-box-seam",
        DeploymentType.GitYaml     => "bi-git",
        DeploymentType.GitHelm     => "bi-git",
        DeploymentType.GitAppOfApps => "bi-diagram-2",
        _                          => "bi-rocket-takeoff",
    };

    private static string TypeLabel(DeploymentType t) => t switch
    {
        DeploymentType.Manual      => "Manual",
        DeploymentType.Yaml        => "YAML",
        DeploymentType.HelmChart   => "Helm",
        DeploymentType.GitYaml     => "Git/YAML",
        DeploymentType.GitHelm     => "Git/Helm",
        DeploymentType.GitAppOfApps => "App of Apps",
        _                          => t.ToString(),
    };
}
