@using EntKube.Web.Data
@using EntKube.Web.Services
@using Microsoft.EntityFrameworkCore
@implements IAsyncDisposable
@inject TenantService TenantService
@inject DeploymentService DeploymentService
@inject CnpgService CnpgService
@inject KubernetesOperationsService K8sOps
@inject PrometheusService PrometheusService
@inject AuditService AuditService
@inject RedisService RedisService
@inject GitRepositoryService GitRepoService
@inject GitSyncService GitSyncService
@inject IDbContextFactory<ApplicationDbContext> DbFactory
@inject IJSRuntime JS

@* ═══════════════════════════════════════════════════════════════════
   App Detail — a full-page view for a single application.
   Shows app info, environment links, and is the extension point
   for future app-level features (config, deployments, secrets, etc.).
   ═══════════════════════════════════════════════════════════════════ *@

@* --- Back button --- *@
<nav class="mb-3">
    <button class="btn btn-sm btn-link text-decoration-none p-0" @onclick="OnBack">
        <i class="bi bi-arrow-left me-1"></i>Back to @CustomerName
    </button>
</nav>

@* --- App header --- *@
<div class="card shadow-sm mb-4">
    <div class="card-body">
        <div class="d-flex align-items-start justify-content-between">
            <div class="d-flex align-items-start">
                <i class="bi bi-app-indicator fs-3 me-3 text-primary"></i>
                <div>
                    <h4 class="mb-1">@App.Name</h4>
                    <div class="d-flex flex-wrap gap-2 text-muted small">
                        <span><i class="bi bi-person me-1"></i>@CustomerName</span>
                        <span><i class="bi bi-calendar me-1"></i>Created @App.CreatedAt.ToString("MMM d, yyyy")</span>
                    </div>
                </div>
            </div>

            @if (!confirmDelete)
            {
                <button class="btn btn-sm btn-outline-danger" @onclick="() => confirmDelete = true" title="Delete app">
                    <i class="bi bi-trash me-1"></i>Delete
                </button>
            }
        </div>

        @if (confirmDelete)
        {
            <div class="mt-3 p-2 bg-danger bg-opacity-10 rounded d-flex align-items-center justify-content-between">
                <span class="text-danger small">
                    <i class="bi bi-exclamation-triangle me-1"></i>
                    Permanently delete <strong>@App.Name</strong> and all its data?
                </span>
                <div>
                    <button class="btn btn-sm btn-danger me-1" @onclick="DeleteApp">Yes, delete</button>
                    <button class="btn btn-sm btn-outline-secondary" @onclick="() => confirmDelete = false">Cancel</button>
                </div>
            </div>
        }
    </div>
</div>

@* --- App sub-sections (tabs for future expansion) --- *@
<ul class="nav nav-pills mb-3 gap-1">
    <li class="nav-item">
        <button class="nav-link @(section == "environments" ? "active" : "")" @onclick='() => section = "environments"'>
            <i class="bi bi-layers me-1"></i>Environments
        </button>
    </li>
    <li class="nav-item">
        <button class="nav-link @(section == "deployments" ? "active" : "")" @onclick="SwitchToDeployments">
            <i class="bi bi-rocket-takeoff me-1"></i>Deployments
            @if (deployments is not null && deployments.Count > 0)
            {
                <span class="badge bg-primary ms-1">@deployments.Count</span>
            }
        </button>
    </li>
    <li class="nav-item">
        <button class="nav-link @(section == "app-resources" ? "active" : "")" @onclick='() => section = "app-resources"'>
            <i class="bi bi-diagram-3 me-1"></i>Resources
        </button>
    </li>
    <li class="nav-item">
        <button class="nav-link @(section == "governance" ? "active" : "")" @onclick='() => section = "governance"'>
            <i class="bi bi-shield-check me-1"></i>Governance
        </button>
    </li>
    <li class="nav-item">
        <button class="nav-link @(section == "app-metrics" ? "active" : "")" @onclick="OpenAppMetricsSection">
            <i class="bi bi-bar-chart-line me-1"></i>Metrics
        </button>
    </li>
</ul>

@if (section == "environments")
{
    <div class="card shadow-sm">
        <div class="card-header bg-white py-2">
            <div class="d-flex align-items-center">
                <i class="bi bi-layers me-2 text-primary"></i>
                <strong>Environment Links</strong>
            </div>
            <small class="text-muted">Select which environments this app is deployed to.</small>
        </div>
        <div class="card-body">
            @if (environments is null)
            {
                <div class="text-center py-3">
                    <div class="spinner-border spinner-border-sm text-primary" role="status"></div>
                </div>
            }
            else if (environments.Count == 0)
            {
                <div class="text-center py-4">
                    <i class="bi bi-layers text-muted" style="font-size: 2rem;"></i>
                    <p class="text-muted small mt-2 mb-0">No environments exist for this tenant yet. Create environments first.</p>
                </div>
            }
            else
            {
                <div class="row row-cols-1 row-cols-md-2 row-cols-lg-3 g-2">
                    @foreach (Data.Environment env in environments)
                    {
                        bool isLinked = linkedEnvIds.Contains(env.Id);

                        <div class="col">
                            <div class="card @(isLinked ? "border-success bg-success bg-opacity-10" : "border-light")"
                                 role="button" style="cursor: pointer;"
                                 @onclick="() => ToggleEnvironment(env.Id, isLinked)">
                                <div class="card-body py-2 d-flex align-items-center">
                                    <i class="bi @(isLinked ? "bi-check-circle-fill text-success" : "bi-circle text-muted") me-2 fs-5"></i>
                                    <div class="flex-grow-1">
                                        <span class="fw-medium">@env.Name</span>
                                    </div>
                                    @if (isLinked)
                                    {
                                        <span class="badge bg-success">Active</span>
                                    }
                                </div>
                            </div>
                        </div>
                    }
                </div>
            }
        </div>
    </div>
}

@* ═══════════════════════════════════════════════════════════════════
   Deployments Tab — manage deployments (Manual, YAML, Helm) targeting
   specific clusters. Shows ArgoCD-style sync/health status.
   ═══════════════════════════════════════════════════════════════════ *@
@if (section == "deployments")
{
    @* --- Deployment detail view (drill-down into a single deployment) --- *@
    @if (selectedDeployment is not null)
    {
        <nav class="mb-3">
            <button class="btn btn-sm btn-link text-decoration-none p-0" @onclick="() => selectedDeployment = null">
                <i class="bi bi-arrow-left me-1"></i>Back to deployments
            </button>
        </nav>

        <div class="card shadow-sm mb-3">
            <div class="card-body">
                <div class="d-flex align-items-start justify-content-between">
                    <div>
                        <h5 class="mb-1">
                            <i class="bi bi-rocket-takeoff me-2 text-primary"></i>@selectedDeployment.Name
                        </h5>
                        <div class="d-flex flex-wrap gap-2 text-muted small">
                            <span>@GetTypeBadge(selectedDeployment.Type)</span>
                            <span><i class="bi bi-layers me-1"></i>@selectedDeployment.Environment?.Name</span>
                            <span><i class="bi bi-hdd-network me-1"></i>@selectedDeployment.Cluster?.Name</span>
                            <span><i class="bi bi-box me-1"></i>@selectedDeployment.Namespace</span>
                        </div>
                    </div>
                    <div class="d-flex align-items-start gap-1">
                        @GetSyncBadge(selectedDeployment.SyncStatus)
                        @GetHealthBadge(selectedDeployment.HealthStatus)

                        <button class="btn btn-sm btn-outline-secondary ms-2"
                                @onclick="StartEditDeployment" title="Edit deployment">
                            <i class="bi bi-pencil"></i>
                        </button>

                        @if (!confirmDeleteDeployment)
                        {
                            <button class="btn btn-sm btn-outline-danger" @onclick="() => confirmDeleteDeployment = true" title="Delete deployment">
                                <i class="bi bi-trash"></i>
                            </button>
                        }
                    </div>
                </div>

                @if (showEditDeployment)
                {
                    <div class="mt-3 p-3 bg-light rounded">
                        @if (editDeployError is not null)
                        {
                            <div class="alert alert-danger py-1 small mb-2">@editDeployError</div>
                        }
                        <div class="row g-2 mb-2">
                            <div class="col-md-6">
                                <label class="form-label small">Name</label>
                                <input class="form-control form-control-sm" @bind="editDeployName" />
                            </div>
                            <div class="col-md-6">
                                <label class="form-label small">Namespace</label>
                                <input class="form-control form-control-sm" @bind="editDeployNamespace" />
                            </div>
                            @if (selectedDeployment.Type == DeploymentType.HelmChart)
                            {
                                <div class="col-md-4">
                                    <label class="form-label small">Helm Repo URL</label>
                                    <input class="form-control form-control-sm" @bind="editHelmRepoUrl" />
                                </div>
                                <div class="col-md-4">
                                    <label class="form-label small">Chart Name</label>
                                    <input class="form-control form-control-sm" @bind="editHelmChartName" />
                                </div>
                                <div class="col-md-4">
                                    <label class="form-label small">Chart Version</label>
                                    <input class="form-control form-control-sm" @bind="editHelmChartVersion" />
                                </div>
                            }
                        </div>
                        <div class="d-flex gap-1">
                            <button class="btn btn-sm btn-primary" @onclick="SaveDeployment"
                                    disabled="@(string.IsNullOrWhiteSpace(editDeployName) || string.IsNullOrWhiteSpace(editDeployNamespace))">
                                Save
                            </button>
                            <button class="btn btn-sm btn-outline-secondary" @onclick="() => showEditDeployment = false">Cancel</button>
                        </div>
                    </div>
                }

                @if (confirmDeleteDeployment)
                {
                    <div class="mt-3 p-2 bg-danger bg-opacity-10 rounded d-flex align-items-center justify-content-between">
                        <span class="text-danger small">
                            <i class="bi bi-exclamation-triangle me-1"></i>
                            Permanently delete <strong>@selectedDeployment.Name</strong> and all its manifests and resources?
                        </span>
                        <div>
                            <button class="btn btn-sm btn-danger me-1" @onclick="DeleteDeployment">Yes, delete</button>
                            <button class="btn btn-sm btn-outline-secondary" @onclick="() => confirmDeleteDeployment = false">Cancel</button>
                        </div>
                    </div>
                }

                @if (!showEditDeployment && selectedDeployment.Type == DeploymentType.HelmChart)
                {
                    <div class="mt-3 p-2 bg-light rounded">
                        <small class="text-muted">
                            <i class="bi bi-box-seam me-1"></i>
                            @selectedDeployment.HelmChartName
                            <span class="mx-1">@selectedDeployment.HelmChartVersion</span>
                            <span class="text-muted">from @selectedDeployment.HelmRepoUrl</span>
                        </small>
                    </div>
                }

                @if (!showEditDeployment && selectedDeployment.GitRepositoryId is not null)
                {
                    <div class="mt-2 p-2 bg-light rounded d-flex align-items-center justify-content-between flex-wrap gap-2">
                        <div class="small text-muted">
                            <i class="bi bi-git me-1"></i>
                            <strong>@selectedDeployment.GitRepository?.Name</strong>
                            <span class="ms-1">@(selectedDeployment.GitRevision ?? selectedDeployment.GitRepository?.DefaultBranch)</span>
                            @if (!string.IsNullOrEmpty(selectedDeployment.GitPath) && selectedDeployment.GitPath != ".")
                            {
                                <span class="ms-1 text-muted">→ <code>@selectedDeployment.GitPath</code></span>
                            }
                            @if (selectedDeployment.GitLastSyncedCommit is not null)
                            {
                                <span class="ms-2 badge bg-secondary">@selectedDeployment.GitLastSyncedCommit[..7]</span>
                            }
                            @if (selectedDeployment.GitLastSyncedAt is not null)
                            {
                                <span class="ms-1">· synced @selectedDeployment.GitLastSyncedAt.Value.ToString("yyyy-MM-dd HH:mm")</span>
                            }
                            @if (selectedDeployment.GitAutoSync)
                            {
                                <span class="badge bg-success-subtle text-success border border-success-subtle ms-1">auto-sync</span>
                            }
                        </div>
                        <button class="btn btn-sm btn-outline-primary" @onclick="TriggerGitSync" disabled="@syncingGit">
                            @if (syncingGit) { <span class="spinner-border spinner-border-sm me-1"></span> }
                            else { <i class="bi bi-arrow-repeat me-1"></i> }
                            Sync now
                        </button>
                    </div>
                    @if (gitSyncResult is not null)
                    {
                        <div class="mt-1 alert @(gitSyncSuccess ? "alert-success" : "alert-danger") py-1 small">
                            <i class="bi @(gitSyncSuccess ? "bi-check-circle" : "bi-exclamation-triangle") me-1"></i>@gitSyncResult
                        </div>
                    }
                }
            </div>
        </div>

        @* --- Sub-tabs: Manifests / Resources / Helm Values --- *@
        <ul class="nav nav-tabs mb-3">
            @if (selectedDeployment.Type is DeploymentType.Manual or DeploymentType.Yaml or DeploymentType.GitYaml)
            {
                <li class="nav-item">
                    <button class="nav-link @(deploymentSection == "manifests" ? "active" : "")"
                            @onclick='() => deploymentSection = "manifests"'>
                        <i class="bi bi-file-earmark-code me-1"></i>Manifests
                    </button>
                </li>
            }

            @if (selectedDeployment.Type is DeploymentType.HelmChart or DeploymentType.GitHelm)
            {
                <li class="nav-item">
                    <button class="nav-link @(deploymentSection == "helm-values" ? "active" : "")"
                            @onclick='() => deploymentSection = "helm-values"'>
                        <i class="bi bi-sliders me-1"></i>Values
                    </button>
                </li>
            }

            <li class="nav-item">
                <button class="nav-link @(deploymentSection == "resources" ? "active" : "")"
                        @onclick="OpenResourcesTab">
                    <i class="bi bi-diagram-3 me-1"></i>Resources
                </button>
            </li>
            <li class="nav-item">
                <button class="nav-link @(deploymentSection == "databases" ? "active" : "")"
                        @onclick="OpenDatabasesTab">
                    <i class="bi bi-database me-1"></i>Databases
                    @if (databaseBindings is not null && databaseBindings.Count > 0)
                    {
                        <span class="badge bg-primary ms-1">@databaseBindings.Count</span>
                    }
                </button>
            </li>
            <li class="nav-item">
                <button class="nav-link @(deploymentSection == "cache" ? "active" : "")"
                        @onclick="OpenCacheTab">
                    <i class="bi bi-lightning-charge me-1"></i>Cache
                    @if (cacheBindings is not null && cacheBindings.Count > 0)
                    {
                        <span class="badge bg-warning text-dark ms-1">@cacheBindings.Count</span>
                    }
                </button>
            </li>
            <li class="nav-item">
                <button class="nav-link @(deploymentSection == "metrics" ? "active" : "")"
                        @onclick="OpenMetricsTab">
                    <i class="bi bi-bar-chart-line me-1"></i>Metrics
                </button>
            </li>
            <li class="nav-item">
                <button class="nav-link @(deploymentSection == "activity" ? "active" : "")"
                        @onclick="OpenActivityTab">
                    <i class="bi bi-clock-history me-1"></i>Activity
                </button>
            </li>
        </ul>

        @* ── Manifests sub-tab ── *@
        @if (deploymentSection == "manifests")
        {
            <div class="card shadow-sm">
                <div class="card-header bg-white py-2 d-flex align-items-center justify-content-between">
                    <div>
                        <i class="bi bi-file-earmark-code me-2 text-primary"></i>
                        <strong>Manifests</strong>
                    </div>
                    <div class="d-flex gap-1">
                        <button class="btn btn-sm btn-success" @onclick="ApplyYamlDeployment"
                                disabled="@(applyingYaml || manifests is null || manifests.Count == 0)">
                            @if (applyingYaml)
                            {
                                <span class="spinner-border spinner-border-sm me-1"></span>
                                <span>Applying…</span>
                            }
                            else
                            {
                                <i class="bi bi-cloud-upload me-1"></i>
                                <span>Apply to Cluster</span>
                            }
                        </button>
                        <button class="btn btn-sm btn-outline-primary" @onclick="() => showAddManifest = !showAddManifest">
                            <i class="bi bi-plus me-1"></i>Add Manifest
                        </button>
                    </div>
                </div>
                <div class="card-body">
                    @if (showAddManifest)
                    {
                        <div class="card border-primary mb-3">
                            <div class="card-body">
                                <h6 class="mb-3"><i class="bi bi-plus-circle me-1"></i>Add YAML Manifest</h6>
                                <div class="row g-2 mb-2">
                                    <div class="col-md-4">
                                        <label class="form-label small">Kind</label>
                                        <input class="form-control form-control-sm" @bind="newManifestKind" placeholder="e.g. Deployment" />
                                    </div>
                                    <div class="col-md-4">
                                        <label class="form-label small">Name</label>
                                        <input class="form-control form-control-sm" @bind="newManifestName" placeholder="e.g. billing-api" />
                                    </div>
                                    <div class="col-md-4">
                                        <label class="form-label small">Sort Order</label>
                                        <input class="form-control form-control-sm" type="number" @bind="newManifestSortOrder" />
                                    </div>
                                </div>
                                <div class="mb-2">
                                    <label class="form-label small">YAML Content</label>
                                    <textarea id="new-manifest-yaml" class="form-control form-control-sm font-monospace" rows="8"
                                              @bind="newManifestYaml"
                                              placeholder="apiVersion: v1&#10;kind: Service&#10;..."></textarea>
                                </div>
                                <div class="d-flex gap-1">
                                    <button class="btn btn-sm btn-primary" @onclick="AddManifest"
                                            disabled="@(string.IsNullOrWhiteSpace(newManifestKind) || string.IsNullOrWhiteSpace(newManifestYaml) || savingManifest)">
                                        @if (savingManifest) { <span class="spinner-border spinner-border-sm me-1"></span> }
                                        Add
                                    </button>
                                    <button class="btn btn-sm btn-outline-secondary" @onclick="() => showAddManifest = false">Cancel</button>
                                </div>
                            </div>
                        </div>
                    }

                    @if (manifests is null)
                    {
                        <div class="text-center py-3">
                            <div class="spinner-border spinner-border-sm text-primary" role="status"></div>
                        </div>
                    }
                    else if (manifests.Count == 0)
                    {
                        <div class="text-center py-4">
                            <i class="bi bi-file-earmark-code text-muted" style="font-size: 2rem;"></i>
                            <p class="text-muted small mt-2 mb-0">No manifests yet. Add YAML manifests to define what gets deployed.</p>
                        </div>
                    }
                    else
                    {
                        @foreach (DeploymentManifest manifest in manifests)
                        {
                            <div class="card mb-2">
                                <div class="card-header bg-white py-2 d-flex align-items-center justify-content-between">
                                    <div>
                                        <span class="badge bg-secondary me-1">@manifest.Kind</span>
                                        <span class="fw-medium">@manifest.Name</span>
                                        <span class="text-muted small ms-2">#@manifest.SortOrder</span>
                                    </div>
                                    <div class="d-flex gap-1">
                                        @if (editingManifestId == manifest.Id)
                                        {
                                            <button class="btn btn-sm btn-primary" @onclick="() => SaveManifest(manifest.Id)" disabled="@savingManifest">
                                                @if (savingManifest) { <span class="spinner-border spinner-border-sm me-1"></span> }
                                                Save
                                            </button>
                                            <button class="btn btn-sm btn-outline-secondary" @onclick="() => editingManifestId = null" disabled="@savingManifest">Cancel</button>
                                        }
                                        else
                                        {
                                            <button class="btn btn-sm btn-outline-primary" @onclick="() => StartEditManifest(manifest)">
                                                <i class="bi bi-pencil"></i>
                                            </button>
                                            <button class="btn btn-sm btn-outline-danger" @onclick="() => DeleteManifest(manifest.Id)">
                                                <i class="bi bi-trash"></i>
                                            </button>
                                        }
                                    </div>
                                </div>

                                @if (editingManifestId == manifest.Id)
                                {
                                    <div class="card-body p-2">
                                        <textarea id="edit-manifest-yaml-@manifest.Id" class="form-control form-control-sm font-monospace" rows="10"
                                                  @bind="editManifestYaml"></textarea>
                                    </div>
                                }
                                else
                                {
                                    <div class="card-body p-2">
                                        <pre class="mb-0 small" style="max-height: 200px; overflow-y: auto;">@manifest.YamlContent</pre>
                                    </div>
                                }
                            </div>
                        }
                    }

                    @if (yamlApplyOutput is not null)
                    {
                        <div class="mt-3">
                            <div class="d-flex align-items-center justify-content-between mb-1">
                                <span class="small fw-medium @(yamlApplySuccess == true ? "text-success" : "text-danger")">
                                    <i class="bi @(yamlApplySuccess == true ? "bi-check-circle" : "bi-x-circle") me-1"></i>
                                    @(yamlApplySuccess == true ? "Applied to cluster successfully" : "Apply failed")
                                </span>
                                <button class="btn btn-sm btn-link text-muted py-0" @onclick="() => yamlApplyOutput = null">
                                    <i class="bi bi-x"></i>
                                </button>
                            </div>
                            <pre class="bg-dark text-light p-2 rounded small mb-0"
                                 style="max-height: 300px; overflow-y: auto; white-space: pre-wrap; word-break: break-all;">@yamlApplyOutput</pre>
                        </div>
                    }
                </div>
            </div>
        }

        @* ── Helm Values sub-tab ── *@
        @if (deploymentSection == "helm-values")
        {
            <div class="card shadow-sm">
                <div class="card-header bg-white py-2">
                    <i class="bi bi-sliders me-2 text-primary"></i>
                    <strong>Helm Values</strong>
                </div>
                <div class="card-body">
                    <p class="text-muted small mb-2">Override the chart's default values (YAML format).</p>
                    @if (helmValuesError is not null)
                    {
                        <div class="alert alert-danger py-1 small mb-2">@helmValuesError</div>
                    }
                    <textarea id="helm-values-editor" class="form-control font-monospace" rows="12"
                              @bind="helmValuesYaml"
                              placeholder="replicas: 3&#10;persistence:&#10;  size: 10Gi"></textarea>
                    <div class="d-flex align-items-center gap-2 mt-2 flex-wrap">
                        <button class="btn btn-sm btn-primary" @onclick="SaveHelmValues" disabled="@(savingHelmValues || installingHelm)">
                            @if (savingHelmValues) { <span class="spinner-border spinner-border-sm me-1"></span> }
                            <i class="bi bi-floppy me-1"></i>Save Values
                        </button>
                        <button class="btn btn-sm btn-success" @onclick="InstallOrUpgradeHelm" disabled="@(installingHelm || savingHelmValues)">
                            @if (installingHelm)
                            {
                                <span class="spinner-border spinner-border-sm me-1"></span>
                                <span>Running helm upgrade…</span>
                            }
                            else
                            {
                                <i class="bi bi-cloud-upload me-1"></i>
                                <span>Install / Upgrade Release</span>
                            }
                        </button>
                        @if (helmValuesSaved)
                        {
                            <span class="text-success small"><i class="bi bi-check-circle me-1"></i>Saved</span>
                        }
                    </div>

                    @if (helmInstallOutput is not null)
                    {
                        <div class="mt-3">
                            <div class="d-flex align-items-center justify-content-between mb-1">
                                <span class="small fw-medium @(helmInstallSuccess == true ? "text-success" : "text-danger")">
                                    <i class="bi @(helmInstallSuccess == true ? "bi-check-circle" : "bi-x-circle") me-1"></i>
                                    @(helmInstallSuccess == true ? "Release applied successfully" : "Helm operation failed")
                                </span>
                                <button class="btn btn-sm btn-link text-muted py-0" @onclick="() => helmInstallOutput = null">
                                    <i class="bi bi-x"></i>
                                </button>
                            </div>
                            <pre class="bg-dark text-light p-2 rounded small mb-0"
                                 style="max-height: 300px; overflow-y: auto; white-space: pre-wrap; word-break: break-all;">@helmInstallOutput</pre>
                        </div>
                    }
                </div>
            </div>
        }

        @* ── Resources sub-tab (ArgoCD-style ownership tree) ── *@
        @if (deploymentSection == "resources")
        {
            <div class="card shadow-sm">
                <div class="card-header bg-white py-2">
                    <i class="bi bi-diagram-3 me-2 text-primary"></i>
                    <strong>Resource Tree</strong>
                </div>
                <div class="card-body">
                    <ResourceTreePanel Loading="@(resourceTree is null)"
                                       Error="@resourcesError"
                                       Resources="@resourceTree"
                                       Namespace="@selectedDeployment?.Namespace"
                                       DeploymentId="@(selectedDeployment?.Id ?? Guid.Empty)"
                                       AccessRole="@null" />
                </div>
            </div>
        }

        @* ── Databases sub-tab ── *@
        @if (deploymentSection == "databases")
        {
            <div class="card shadow-sm">
                <div class="card-header bg-white py-2 d-flex align-items-center justify-content-between">
                    <div>
                        <i class="bi bi-database me-2 text-primary"></i>
                        <strong>Database Bindings</strong>
                    </div>
                    <button class="btn btn-sm btn-outline-primary" @onclick="() => showAddBinding = !showAddBinding">
                        <i class="bi bi-plus me-1"></i>Attach Database
                    </button>
                </div>
                <div class="card-body">
                    @if (!string.IsNullOrEmpty(bindingError))
                    {
                        <div class="alert alert-danger py-1 small mb-2">@bindingError</div>
                    }

                    @* --- Add binding form --- *@
                    @if (showAddBinding)
                    {
                        <div class="card border-primary mb-3">
                            <div class="card-body">
                                <h6 class="mb-3"><i class="bi bi-plus-circle me-1"></i>Attach a PostgreSQL Database</h6>
                                <div class="row g-2 mb-2">
                                    <div class="col-md-6">
                                        <label class="form-label small">Database</label>
                                        <select class="form-select form-select-sm" @bind="newBindingDatabaseId">
                                            <option value="">Select database...</option>
                                            @if (availableCnpgDatabases is not null)
                                            {
                                                @foreach ((CnpgCluster cluster, CnpgDatabase database) in availableCnpgDatabases)
                                                {
                                                    <option value="@database.Id">@cluster.Name / @database.Name</option>
                                                }
                                            }
                                        </select>
                                    </div>
                                    <div class="col-md-6">
                                        <label class="form-label small">Secret name in app namespace</label>
                                        <input class="form-control form-control-sm" @bind="newBindingSecretName"
                                               placeholder="e.g. my-app-db" />
                                        <div class="form-text">The K8s Secret created in <code>@selectedDeployment?.Namespace</code>.</div>
                                    </div>
                                </div>
                                <div class="d-flex gap-1">
                                    <button class="btn btn-sm btn-primary" @onclick="AddDatabaseBinding"
                                            disabled="@(newBindingDatabaseId == Guid.Empty || string.IsNullOrWhiteSpace(newBindingSecretName))">
                                        Attach &amp; Sync
                                    </button>
                                    <button class="btn btn-sm btn-outline-secondary" @onclick="() => showAddBinding = false">Cancel</button>
                                </div>
                            </div>
                        </div>
                    }

                    @* --- Binding list --- *@
                    @if (databaseBindings is null)
                    {
                        <div class="text-center py-3">
                            <div class="spinner-border spinner-border-sm text-primary" role="status"></div>
                        </div>
                    }
                    else if (databaseBindings.Count == 0)
                    {
                        <div class="text-center py-4">
                            <i class="bi bi-database text-muted" style="font-size: 2rem;"></i>
                            <p class="text-muted small mt-2 mb-0">No databases attached. Attach a database to have its credentials automatically synced to this deployment's namespace.</p>
                        </div>
                    }
                    else
                    {
                        <table class="table table-sm mb-0">
                            <thead class="table-light">
                                <tr>
                                    <th class="small">Database</th>
                                    <th class="small">Secret name</th>
                                    <th class="small">Last synced</th>
                                    <th></th>
                                </tr>
                            </thead>
                            <tbody>
                                @foreach (DatabaseBinding binding in databaseBindings)
                                {
                                    <tr>
                                        <td class="small">
                                            @if (binding.CnpgDatabase is not null)
                                            {
                                                <i class="bi bi-database me-1 text-primary"></i>
                                                @binding.CnpgDatabase.CnpgCluster.Name<span class="text-muted"> / </span>@binding.CnpgDatabase.Name
                                            }
                                            else if (binding.MongoDatabase is not null)
                                            {
                                                <i class="bi bi-database me-1 text-success"></i>
                                                @binding.MongoDatabase.MongoCluster.Name<span class="text-muted"> / </span>@binding.MongoDatabase.Name
                                            }
                                        </td>
                                        <td><code class="small">@binding.KubernetesSecretName</code></td>
                                        <td class="small text-muted">
                                            @(binding.LastSyncedAt.HasValue ? binding.LastSyncedAt.Value.ToString("yyyy-MM-dd HH:mm") : "Never")
                                        </td>
                                        <td>
                                            <button class="btn btn-link btn-sm text-danger p-0" title="Detach"
                                                    @onclick="() => RemoveDatabaseBinding(binding.Id)">
                                                <i class="bi bi-x-circle" style="font-size:0.85rem;"></i>
                                            </button>
                                        </td>
                                    </tr>
                                }
                            </tbody>
                        </table>
                    }
                </div>
            </div>
        }

        @* ── Cache bindings sub-tab ── *@
        @if (deploymentSection == "cache")
        {
            <div class="card shadow-sm">
                <div class="card-header bg-white py-2 d-flex align-items-center justify-content-between">
                    <div>
                        <i class="bi bi-lightning-charge me-2 text-warning"></i>
                        <strong>Cache Bindings</strong>
                    </div>
                    <button class="btn btn-sm btn-outline-warning" @onclick="() => showAddCacheBinding = !showAddCacheBinding">
                        <i class="bi bi-plus me-1"></i>Attach Redis Cluster
                    </button>
                </div>
                <div class="card-body">
                    @if (!string.IsNullOrEmpty(cacheBindingError))
                    {
                        <div class="alert alert-danger py-1 small mb-2">@cacheBindingError</div>
                    }

                    @if (showAddCacheBinding)
                    {
                        <div class="card border-warning mb-3">
                            <div class="card-body">
                                <h6 class="mb-3"><i class="bi bi-plus-circle me-1"></i>Attach a Redis Cluster</h6>
                                <div class="row g-2 mb-2">
                                    <div class="col-md-6">
                                        <label class="form-label small">Redis Cluster</label>
                                        <select class="form-select form-select-sm" @bind="newCacheBindingClusterId">
                                            <option value="@Guid.Empty">Select cluster...</option>
                                            @if (availableRedisClusters is not null)
                                            {
                                                @foreach (RedisCluster rc in availableRedisClusters)
                                                {
                                                    <option value="@rc.Id">@rc.Name (@rc.Namespace)</option>
                                                }
                                            }
                                        </select>
                                    </div>
                                    <div class="col-md-6">
                                        <label class="form-label small">Secret name in app namespace</label>
                                        <input class="form-control form-control-sm" @bind="newCacheBindingSecretName"
                                               placeholder="redis-cache" />
                                        <div class="form-text">The K8s Secret created in <code>@selectedDeployment?.Namespace</code>.</div>
                                    </div>
                                </div>
                                <div class="d-flex gap-1">
                                    <button class="btn btn-sm btn-warning" @onclick="AddCacheBinding"
                                            disabled="@(newCacheBindingClusterId == Guid.Empty || string.IsNullOrWhiteSpace(newCacheBindingSecretName))">
                                        Attach &amp; Sync
                                    </button>
                                    <button class="btn btn-sm btn-outline-secondary" @onclick="() => showAddCacheBinding = false">Cancel</button>
                                </div>
                            </div>
                        </div>
                    }

                    @if (cacheBindings is null)
                    {
                        <div class="text-center py-3">
                            <div class="spinner-border spinner-border-sm text-warning" role="status"></div>
                        </div>
                    }
                    else if (cacheBindings.Count == 0)
                    {
                        <div class="text-center py-4">
                            <i class="bi bi-lightning-charge text-muted" style="font-size: 2rem;"></i>
                            <p class="text-muted small mt-2 mb-0">No Redis clusters attached. Attach one to have REDIS_HOST, REDIS_PORT, and REDIS_PASSWORD synced into this deployment's namespace.</p>
                        </div>
                    }
                    else
                    {
                        <table class="table table-sm mb-0">
                            <thead class="table-light">
                                <tr>
                                    <th class="small">Redis Cluster</th>
                                    <th class="small">Secret name</th>
                                    <th class="small">Last synced</th>
                                    <th></th>
                                </tr>
                            </thead>
                            <tbody>
                                @foreach (CacheBinding binding in cacheBindings)
                                {
                                    <tr>
                                        <td class="small">
                                            <i class="bi bi-lightning-charge me-1 text-warning"></i>
                                            @binding.RedisCluster.Name
                                            <span class="text-muted small ms-1">@binding.RedisCluster.KubernetesCluster.Name</span>
                                        </td>
                                        <td><code class="small">@binding.KubernetesSecretName</code></td>
                                        <td class="small text-muted">
                                            @(binding.LastSyncedAt.HasValue ? binding.LastSyncedAt.Value.ToString("yyyy-MM-dd HH:mm") : "Never")
                                        </td>
                                        <td>
                                            <button class="btn btn-link btn-sm text-danger p-0" title="Detach"
                                                    @onclick="() => RemoveCacheBinding(binding.Id)">
                                                <i class="bi bi-x-circle" style="font-size:0.85rem;"></i>
                                            </button>
                                        </td>
                                    </tr>
                                }
                            </tbody>
                        </table>
                    }
                </div>
            </div>
        }

        @* ── Metrics sub-tab ── *@
        @if (deploymentSection == "metrics")
        {
            <div class="card shadow-sm">
                <div class="card-header bg-white py-2">
                    <i class="bi bi-bar-chart-line me-2 text-primary"></i><strong>Namespace Metrics</strong>
                    <span class="text-muted small ms-2">@selectedDeployment.Namespace</span>
                </div>
                <div class="card-body">
                    @if (metricsLoading)
                    {
                        <div class="text-center py-4"><div class="spinner-border spinner-border-sm text-primary"></div></div>
                    }
                    else if (metricsError is not null)
                    {
                        <div class="alert alert-warning small py-2 mb-0">
                            <i class="bi bi-exclamation-triangle me-1"></i>@metricsError
                        </div>
                    }
                    else if (deploymentMetrics is not null)
                    {
                        <div class="row g-3 mb-2">
                            <div class="col-sm-6 col-lg-3">
                                <div class="border rounded text-center p-3">
                                    <div class="fs-3 fw-bold text-primary">@(deploymentMetrics.CpuCores >= 1 ? $"{(int)Math.Round(deploymentMetrics.CpuCores)} cores" : $"{(int)Math.Round(deploymentMetrics.CpuCores * 1000)}m")</div>
                                    <div class="small text-muted">CPU cores (5 m avg)</div>
                                </div>
                            </div>
                            <div class="col-sm-6 col-lg-3">
                                <div class="border rounded text-center p-3">
                                    <div class="fs-3 fw-bold text-info">@deploymentMetrics.MemoryMiB.ToString("F0") <small class="fs-6">MiB</small></div>
                                    <div class="small text-muted">Memory (working set)</div>
                                </div>
                            </div>
                            <div class="col-sm-6 col-lg-3">
                                <div class="border rounded text-center p-3">
                                    <div class="fs-3 fw-bold text-success">@deploymentMetrics.PodCount</div>
                                    <div class="small text-muted">Pods in namespace</div>
                                </div>
                            </div>
                            <div class="col-sm-6 col-lg-3">
                                <div class="border rounded text-center p-3">
                                    <div class="fs-3 fw-bold @(deploymentMetrics.RestartCount > 0 ? "text-warning" : "text-success")">@deploymentMetrics.RestartCount</div>
                                    <div class="small text-muted">Container restarts (total)</div>
                                </div>
                            </div>
                        </div>
                        <div class="text-muted small">
                            <i class="bi bi-clock me-1"></i>Queried @deploymentMetrics.QueriedAt.ToLocalTime().ToString("HH:mm:ss")
                        </div>
                    }
                </div>
            </div>
        }

        @* ── Activity sub-tab ── *@
        @if (deploymentSection == "activity")
        {
            <div class="card shadow-sm">
                <div class="card-header bg-white py-2">
                    <i class="bi bi-clock-history me-2 text-primary"></i><strong>Activity Log</strong>
                </div>
                <div class="card-body p-0">
                    @if (activityLoading)
                    {
                        <div class="text-center py-4"><div class="spinner-border spinner-border-sm text-primary"></div></div>
                    }
                    else if (deploymentAuditEvents is not null && deploymentAuditEvents.Count == 0)
                    {
                        <div class="text-muted small py-4 text-center">No activity recorded yet.</div>
                    }
                    else if (deploymentAuditEvents is not null)
                    {
                        <div class="list-group list-group-flush">
                            @foreach (AuditEvent ev in deploymentAuditEvents)
                            {
                                <div class="list-group-item px-3 py-2">
                                    <div class="d-flex justify-content-between align-items-start">
                                        <div>
                                            <span class="badge bg-secondary me-2">@ev.ResourceKind</span>
                                            <strong>@ev.Action</strong>
                                            @if (!string.IsNullOrEmpty(ev.ResourceName))
                                            {
                                                <span class="text-muted ms-1 font-monospace small">@ev.ResourceName</span>
                                            }
                                            @if (!string.IsNullOrEmpty(ev.Details))
                                            {
                                                <span class="text-muted ms-2 small">— @ev.Details</span>
                                            }
                                        </div>
                                        <div class="text-end text-nowrap ms-3">
                                            <div class="small text-muted">@ev.OccurredAt.ToLocalTime().ToString("MMM d HH:mm")</div>
                                            @if (!string.IsNullOrEmpty(ev.PerformedBy))
                                            {
                                                <div class="small text-muted">@ev.PerformedBy</div>
                                            }
                                        </div>
                                    </div>
                                </div>
                            }
                        </div>
                    }
                </div>
            </div>
        }
    }
    else
    {
        @* --- Deployment list view --- *@
        <div class="card shadow-sm">
            <div class="card-header bg-white py-2 d-flex align-items-center justify-content-between">
                <div>
                    <i class="bi bi-rocket-takeoff me-2 text-primary"></i>
                    <strong>Deployments</strong>
                </div>
                <button class="btn btn-sm btn-outline-primary" @onclick="() => showCreateDeployment = !showCreateDeployment">
                    <i class="bi bi-plus me-1"></i>New Deployment
                </button>
            </div>
            <div class="card-body">
                @* --- Create deployment form --- *@
                @if (showCreateDeployment)
                {
                    <div class="card border-primary mb-3">
                        <div class="card-body">
                            <h6 class="mb-3"><i class="bi bi-plus-circle me-1"></i>Create Deployment</h6>
                            <div class="row g-2 mb-2">
                                <div class="col-md-6">
                                    <label class="form-label small">Name</label>
                                    <input class="form-control form-control-sm" @bind="newDeployName" placeholder="e.g. billing-api-prod" />
                                </div>
                                <div class="col-md-6">
                                    <label class="form-label small">Type</label>
                                    <select class="form-select form-select-sm" @bind="newDeployType" @bind:after="OnNewDeployTypeChanged">
                                        <option value="@DeploymentType.Manual">Manual</option>
                                        <option value="@DeploymentType.Yaml">YAML</option>
                                        <option value="@DeploymentType.HelmChart">Helm Chart</option>
                                        <option value="@DeploymentType.GitYaml">Git — YAML</option>
                                        <option value="@DeploymentType.GitHelm">Git — Helm</option>
                                        <option value="@DeploymentType.GitAppOfApps">Git — App of Apps</option>
                                    </select>
                                </div>
                            </div>

                            <div class="row g-2 mb-2">
                                <div class="col-md-4">
                                    <label class="form-label small">Environment</label>
                                    <select class="form-select form-select-sm" @bind="newDeployEnvId">
                                        <option value="">Select...</option>
                                        @if (environments is not null)
                                        {
                                            @foreach (Data.Environment env in environments)
                                            {
                                                <option value="@env.Id">@env.Name</option>
                                            }
                                        }
                                    </select>
                                </div>
                                <div class="col-md-4">
                                    <label class="form-label small">Cluster</label>
                                    <select class="form-select form-select-sm" @bind="newDeployClusterId">
                                        <option value="">Select...</option>
                                        @if (clusters is not null)
                                        {
                                            @foreach (KubernetesCluster cluster in clusters.Where(c => newDeployEnvId == Guid.Empty || c.EnvironmentId == newDeployEnvId))
                                            {
                                                <option value="@cluster.Id">@cluster.Name</option>
                                            }
                                        }
                                    </select>
                                </div>
                                <div class="col-md-4">
                                    <label class="form-label small">Namespace</label>
                                    <input class="form-control form-control-sm" @bind="newDeployNamespace" placeholder="e.g. billing" />
                                </div>
                            </div>

                            @if (newDeployType == DeploymentType.HelmChart)
                            {
                                <div class="row g-2 mb-2">
                                    <div class="col-md-4">
                                        <label class="form-label small">Helm Repo URL</label>
                                        <input class="form-control form-control-sm" @bind="newHelmRepoUrl"
                                               placeholder="https://charts.bitnami.com/bitnami" />
                                    </div>
                                    <div class="col-md-4">
                                        <label class="form-label small">Chart Name</label>
                                        <input class="form-control form-control-sm" @bind="newHelmChartName"
                                               placeholder="e.g. postgresql" />
                                    </div>
                                    <div class="col-md-4">
                                        <label class="form-label small">Chart Version</label>
                                        <input class="form-control form-control-sm" @bind="newHelmChartVersion"
                                               placeholder="e.g. 15.5.0" />
                                    </div>
                                </div>
                            }

                            @if (newDeployType is DeploymentType.GitYaml or DeploymentType.GitHelm or DeploymentType.GitAppOfApps)
                            {
                                <div class="row g-2 mb-2">
                                    <div class="col-md-5">
                                        <label class="form-label small">Git Repository</label>
                                        <select class="form-select form-select-sm" @bind="newGitRepoId">
                                            <option value="@Guid.Empty">Select repository...</option>
                                            @if (gitRepos is not null)
                                            {
                                                @foreach (GitRepository r in gitRepos)
                                                {
                                                    <option value="@r.Id">@r.Name</option>
                                                }
                                            }
                                        </select>
                                        @if (gitRepos is not null && gitRepos.Count == 0)
                                        {
                                            <div class="form-text text-warning">
                                                <i class="bi bi-exclamation-triangle me-1"></i>No repositories registered. Add one in the <strong>Git</strong> tab first.
                                            </div>
                                        }
                                    </div>
                                    <div class="col-md-3">
                                        <label class="form-label small">Path</label>
                                        <input class="form-control form-control-sm" @bind="newGitPath" placeholder="." />
                                        <div class="form-text">Path inside the repo (use <code>.</code> for root).</div>
                                    </div>
                                    <div class="col-md-4">
                                        <label class="form-label small">Branch / Tag / Commit</label>
                                        <input class="form-control form-control-sm" @bind="newGitRevision"
                                               placeholder="leave blank for repo default" />
                                    </div>
                                </div>
                                <div class="mb-2">
                                    <div class="form-check form-check-sm">
                                        <input class="form-check-input" type="checkbox" id="newGitAutoSync"
                                               @bind="newGitAutoSync" />
                                        <label class="form-check-label small" for="newGitAutoSync">
                                            Auto-sync (poll every 3 minutes for new commits)
                                        </label>
                                    </div>
                                </div>
                            }

                            @if (!string.IsNullOrEmpty(createDeployError))
                            {
                                <div class="alert alert-danger py-1 small mb-2">@createDeployError</div>
                            }

                            <div class="d-flex gap-1">
                                <button class="btn btn-sm btn-primary" @onclick="CreateDeployment"
                                        disabled="@(string.IsNullOrWhiteSpace(newDeployName) || newDeployEnvId == Guid.Empty || newDeployClusterId == Guid.Empty)">
                                    Create
                                </button>
                                <button class="btn btn-sm btn-outline-secondary" @onclick="() => showCreateDeployment = false">Cancel</button>
                            </div>
                        </div>
                    </div>
                }

                @* --- Deployment list --- *@
                @if (deployments is null)
                {
                    <div class="text-center py-3">
                        <div class="spinner-border spinner-border-sm text-primary" role="status"></div>
                    </div>
                }
                else if (deployments.Count == 0)
                {
                    <div class="text-center py-4">
                        <i class="bi bi-rocket-takeoff text-muted" style="font-size: 2rem;"></i>
                        <p class="text-muted small mt-2 mb-0">No deployments yet. Create one to start deploying to Kubernetes.</p>
                    </div>
                }
                else
                {
                    <div class="row row-cols-1 row-cols-lg-2 g-2">
                        @foreach (AppDeployment deploy in deployments)
                        {
                            <div class="col">
                                <div class="card border-light h-100" role="button" style="cursor: pointer;"
                                     @onclick="() => SelectDeployment(deploy)">
                                    <div class="card-body py-2">
                                        <div class="d-flex align-items-center justify-content-between mb-1">
                                            <span class="fw-medium">
                                                <i class="bi bi-rocket-takeoff me-1 text-primary"></i>@deploy.Name
                                            </span>
                                            <div class="d-flex gap-1">
                                                @GetSyncBadge(deploy.SyncStatus)
                                                @GetHealthBadge(deploy.HealthStatus)
                                            </div>
                                        </div>
                                        <div class="d-flex flex-wrap gap-2 text-muted small">
                                            @GetTypeBadge(deploy.Type)
                                            <span><i class="bi bi-layers me-1"></i>@deploy.Environment?.Name</span>
                                            <span><i class="bi bi-hdd-network me-1"></i>@deploy.Cluster?.Name</span>
                                            <span><i class="bi bi-box me-1"></i>@deploy.Namespace</span>
                                        </div>

                                        @if (!string.IsNullOrEmpty(deploy.StatusMessage))
                                        {
                                            <div class="text-muted small mt-1 text-truncate">@deploy.StatusMessage</div>
                                        }
                                    </div>
                                </div>
                            </div>
                        }
                    </div>
                }
            </div>
        </div>
    }
}

@* ═══════════════════════════════════════════════════════════════════
   App Resources Tab — ArgoCD-style grid of all deployments with live trees.
   ═══════════════════════════════════════════════════════════════════ *@
@if (section == "app-resources")
{
    <AppResourcesPanel AppId="App.Id" />
}

@* ═══════════════════════════════════════════════════════════════════
   Governance Tab — namespace, quotas, network policies, RBAC.
   ═══════════════════════════════════════════════════════════════════ *@
@if (section == "governance")
{
    <GovernanceTab AppId="App.Id" TenantId="TenantId" />
}

@* ═══════════════════════════════════════════════════════════════════
   App Metrics Tab — aggregate CPU, memory, and pods across all deployments.
   ═══════════════════════════════════════════════════════════════════ *@
@if (section == "app-metrics")
{
    <div class="card shadow-sm">
        <div class="card-header bg-white py-2 d-flex justify-content-between align-items-center">
            <div>
                <i class="bi bi-bar-chart-line me-2 text-primary"></i>
                <strong>App Metrics</strong>
                <span class="text-muted small ms-2">aggregate across all deployments</span>
            </div>
            <button class="btn btn-sm btn-outline-secondary" @onclick="OpenAppMetricsSection" disabled="@appMetricsLoading">
                <i class="bi bi-arrow-clockwise me-1"></i>Refresh
            </button>
        </div>
        <div class="card-body">
            @if (appMetricsLoading)
            {
                <div class="text-center py-4"><div class="spinner-border spinner-border-sm text-primary"></div></div>
            }
            else if (appMetricsError is not null)
            {
                <div class="alert alert-warning small py-2 mb-0">
                    <i class="bi bi-exclamation-triangle me-1"></i>@appMetricsError
                </div>
            }
            else if (appMetrics is not null)
            {
                <div class="row g-3 mb-2">
                    <div class="col-sm-6 col-lg-3">
                        <div class="border rounded text-center p-3">
                            <div class="fs-3 fw-bold text-primary">
                                @(appMetrics.CpuCores >= 1 ? $"{(int)Math.Round(appMetrics.CpuCores)} cores" : $"{(int)Math.Round(appMetrics.CpuCores * 1000)}m")
                            </div>
                            <div class="small text-muted">CPU (5 m avg)</div>
                        </div>
                    </div>
                    <div class="col-sm-6 col-lg-3">
                        <div class="border rounded text-center p-3">
                            <div class="fs-3 fw-bold text-info">@appMetrics.MemoryMiB.ToString("F0") <small class="fs-6">MiB</small></div>
                            <div class="small text-muted">Memory (working set)</div>
                        </div>
                    </div>
                    <div class="col-sm-6 col-lg-3">
                        <div class="border rounded text-center p-3">
                            <div class="fs-3 fw-bold text-success">@appMetrics.PodCount</div>
                            <div class="small text-muted">Pods running</div>
                        </div>
                    </div>
                    <div class="col-sm-6 col-lg-3">
                        <div class="border rounded text-center p-3">
                            <div class="fs-3 fw-bold @(appMetrics.RestartCount > 0 ? "text-warning" : "text-success")">@appMetrics.RestartCount</div>
                            <div class="small text-muted">Container restarts</div>
                        </div>
                    </div>
                </div>
                <div class="text-muted small">
                    <i class="bi bi-clock me-1"></i>Queried @appMetrics.QueriedAt.ToLocalTime().ToString("HH:mm:ss")
                </div>
            }
        </div>
    </div>
}

@code {
    [Parameter] public required Data.App App { get; set; }
    [Parameter] public Guid TenantId { get; set; }
    [Parameter] public string CustomerName { get; set; } = "";
    [Parameter] public EventCallback OnBack { get; set; }
    [Parameter] public EventCallback OnDeleted { get; set; }

    private string section = "environments";
    private bool confirmDelete;

    // Environments
    private List<Data.Environment>? environments;
    private HashSet<Guid> linkedEnvIds = new();

    // Deployments
    private List<AppDeployment>? deployments;
    private List<KubernetesCluster>? clusters;
    private AppDeployment? selectedDeployment;
    private string deploymentSection = "manifests";
    private bool confirmDeleteDeployment;

    // Create deployment form
    private bool showCreateDeployment;
    private string newDeployName = "";
    private DeploymentType newDeployType = DeploymentType.Manual;
    private Guid newDeployEnvId;
    private Guid newDeployClusterId;
    private string newDeployNamespace = "";
    private string newHelmRepoUrl = "";
    private string newHelmChartName = "";
    private string newHelmChartVersion = "";
    private string? createDeployError;

    // Git fields for create form
    private List<GitRepository>? gitRepos;
    private Guid newGitRepoId;
    private string newGitPath = ".";
    private string newGitRevision = "";
    private bool newGitAutoSync = true;

    // Git sync panel on deployment detail
    private bool syncingGit;
    private string? gitSyncResult;
    private bool gitSyncSuccess;

    // Edit deployment form
    private bool showEditDeployment;
    private string editDeployName = "";
    private string editDeployNamespace = "";
    private string editHelmRepoUrl = "";
    private string editHelmChartName = "";
    private string editHelmChartVersion = "";
    private string? editDeployError;

    // Manifest management
    private List<DeploymentManifest>? manifests;
    private bool showAddManifest;
    private bool savingManifest;
    private string newManifestKind = "";
    private string newManifestName = "";
    private string newManifestYaml = "";
    private int newManifestSortOrder;
    private Guid? editingManifestId;
    private string editManifestYaml = "";

    // Helm values
    private string helmValuesYaml = "";
    private bool savingHelmValues;
    private bool helmValuesSaved;
    private string? helmValuesError;

    // Helm install / upgrade
    private bool installingHelm;
    private bool? helmInstallSuccess;
    private string? helmInstallOutput;

    // YAML apply
    private bool applyingYaml;
    private bool? yamlApplySuccess;
    private string? yamlApplyOutput;

    // JS module for reading live textarea values
    private IJSObjectReference? jsModule;

    // Resource tree
    private List<DeploymentResource>? resourceTree;
    private string? resourcesError;

    // Metrics
    private DeploymentMetricsSummary? deploymentMetrics;
    private bool metricsLoading;
    private string? metricsError;

    // Activity
    private List<AuditEvent>? deploymentAuditEvents;
    private bool activityLoading;

    // App-level aggregate metrics
    private DeploymentMetricsSummary? appMetrics;
    private bool appMetricsLoading;
    private string? appMetricsError;

    // Database bindings
    private List<DatabaseBinding>? databaseBindings;
    private List<(CnpgCluster Cluster, CnpgDatabase Database)>? availableCnpgDatabases;
    private bool showAddBinding;
    private Guid newBindingDatabaseId;
    private string newBindingSecretName = "";
    private string? bindingError;

    // Cache bindings
    private List<CacheBinding>? cacheBindings;
    private List<RedisCluster>? availableRedisClusters;
    private bool showAddCacheBinding;
    private Guid newCacheBindingClusterId;
    private string newCacheBindingSecretName = "redis-cache";
    private string? cacheBindingError;

    protected override async Task OnInitializedAsync()
    {
        await LoadEnvironments();
    }

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            jsModule = await JS.InvokeAsync<IJSObjectReference>(
                "import", "./Components/Pages/Tenants/AppDetail.razor.js");
        }
    }

    public async ValueTask DisposeAsync()
    {
        if (jsModule is not null)
            await jsModule.DisposeAsync();
    }

    // ──────── App ────────

    private async Task DeleteApp()
    {
        await TenantService.DeleteAppAsync(App.Id);
        await OnDeleted.InvokeAsync();
    }

    // ──────── Environments ────────

    private async Task LoadEnvironments()
    {
        environments = await TenantService.GetEnvironmentsAsync(TenantId);

        // Refresh the app to get current environment links.
        List<Data.App> apps = await TenantService.GetAppsAsync(App.CustomerId);
        Data.App? freshApp = apps.FirstOrDefault(a => a.Id == App.Id);

        linkedEnvIds = freshApp?.AppEnvironments.Select(ae => ae.EnvironmentId).ToHashSet() ?? new();
    }

    private async Task ToggleEnvironment(Guid envId, bool currentlyLinked)
    {
        if (currentlyLinked)
        {
            await TenantService.UnlinkAppFromEnvironmentAsync(App.Id, envId);
        }
        else
        {
            await TenantService.LinkAppToEnvironmentAsync(App.Id, envId);
        }

        await LoadEnvironments();
    }

    // ──────── Deployments ────────

    private async Task SwitchToDeployments()
    {
        section = "deployments";

        if (deployments is null)
        {
            await LoadDeployments();
        }

        if (clusters is null)
        {
            clusters = await TenantService.GetClustersAsync(TenantId);
        }
    }

    private async Task LoadDeployments()
    {
        deployments = await DeploymentService.GetDeploymentsAsync(App.Id);
    }

    private async Task OnNewDeployTypeChanged()
    {
        bool isGit = newDeployType is DeploymentType.GitYaml
            or DeploymentType.GitHelm or DeploymentType.GitAppOfApps;

        if (isGit && gitRepos is null)
            gitRepos = await GitRepoService.GetRepositoriesAsync(TenantId);
    }

    private async Task CreateDeployment()
    {
        createDeployError = null;

        bool isGit = newDeployType is DeploymentType.GitYaml
            or DeploymentType.GitHelm or DeploymentType.GitAppOfApps;

        if (isGit && newGitRepoId == Guid.Empty)
        {
            createDeployError = "Select a Git repository.";
            return;
        }

        try
        {
            await DeploymentService.CreateDeploymentAsync(
                App.Id, newDeployName, newDeployType,
                newDeployEnvId, newDeployClusterId, newDeployNamespace,
                newDeployType == DeploymentType.HelmChart ? newHelmRepoUrl : null,
                newDeployType == DeploymentType.HelmChart ? newHelmChartName : null,
                newDeployType == DeploymentType.HelmChart ? newHelmChartVersion : null,
                gitRepositoryId: isGit ? newGitRepoId : null,
                gitPath: isGit ? newGitPath : null,
                gitRevision: isGit && !string.IsNullOrWhiteSpace(newGitRevision) ? newGitRevision : null,
                gitAutoSync: isGit && newGitAutoSync);

            showCreateDeployment = false;
            newDeployName = ""; newDeployNamespace = "";
            newHelmRepoUrl = ""; newHelmChartName = ""; newHelmChartVersion = "";
            newGitRepoId = Guid.Empty; newGitPath = "."; newGitRevision = ""; newGitAutoSync = true;
            await LoadDeployments();
        }
        catch (DbUpdateException)
        {
            createDeployError = $"A deployment named '{newDeployName}' already exists for this app.";
        }
    }

    private async Task TriggerGitSync()
    {
        if (selectedDeployment is null) return;
        syncingGit = true;
        gitSyncResult = null;
        StateHasChanged();
        try
        {
            GitSyncResult result = await GitSyncService.SyncDeploymentAsync(selectedDeployment.Id);
            gitSyncSuccess = result.IsSuccess;
            gitSyncResult = result.AlreadyCurrent
                ? "Already up to date."
                : result.IsSuccess
                    ? $"Synced to {result.CommitSha[..Math.Min(7, result.CommitSha.Length)]} — {result.CommitMessage}"
                    : result.Error ?? "Sync failed.";

            if (result.IsSuccess)
            {
                // Reload to get updated LastSyncedAt / commit
                await LoadDeployments();
                selectedDeployment = deployments?.FirstOrDefault(d => d.Id == selectedDeployment.Id)
                    ?? selectedDeployment;
            }
        }
        catch (Exception ex) { gitSyncSuccess = false; gitSyncResult = ex.Message; }
        finally { syncingGit = false; }
    }

    private async Task SelectDeployment(AppDeployment deploy)
    {
        selectedDeployment = deploy;
        confirmDeleteDeployment = false;
        helmValuesSaved = false;
        helmValuesError = null;
        helmInstallOutput = null;
        helmInstallSuccess = null;
        yamlApplyOutput = null;
        yamlApplySuccess = null;
        savingManifest = false;
        editingManifestId = null;
        resourceTree = null;
        resourcesError = null;
        deploymentMetrics = null;
        metricsError = null;
        deploymentAuditEvents = null;

        gitSyncResult = null;
        syncingGit = false;

        // Default to the appropriate sub-tab based on type.
        if (deploy.Type == DeploymentType.HelmChart || deploy.Type == DeploymentType.GitHelm)
        {
            deploymentSection = "helm-values";
            helmValuesYaml = deploy.HelmValues ?? "";
        }
        else if (deploy.Type == DeploymentType.GitAppOfApps)
        {
            deploymentSection = "resources";
            await OpenResourcesTab();
        }
        else
        {
            deploymentSection = "manifests";
            await LoadManifests();
        }
    }

    private async Task DeleteDeployment()
    {
        if (selectedDeployment is not null)
        {
            await DeploymentService.DeleteDeploymentAsync(selectedDeployment.Id);
            selectedDeployment = null;
            confirmDeleteDeployment = false;
            await LoadDeployments();
        }
    }

    private void StartEditDeployment()
    {
        if (selectedDeployment is null) return;
        editDeployName = selectedDeployment.Name;
        editDeployNamespace = selectedDeployment.Namespace;
        editHelmRepoUrl = selectedDeployment.HelmRepoUrl ?? "";
        editHelmChartName = selectedDeployment.HelmChartName ?? "";
        editHelmChartVersion = selectedDeployment.HelmChartVersion ?? "";
        editDeployError = null;
        showEditDeployment = true;
        confirmDeleteDeployment = false;
    }

    private async Task SaveDeployment()
    {
        if (selectedDeployment is null) return;

        editDeployError = null;

        try
        {
            await DeploymentService.UpdateDeploymentAsync(
                selectedDeployment.Id,
                editDeployName,
                editDeployNamespace,
                selectedDeployment.Type == DeploymentType.HelmChart ? editHelmRepoUrl : null,
                selectedDeployment.Type == DeploymentType.HelmChart ? editHelmChartName : null,
                selectedDeployment.Type == DeploymentType.HelmChart ? editHelmChartVersion : null);

            await LoadDeployments();
            selectedDeployment = deployments?.FirstOrDefault(d => d.Id == selectedDeployment.Id) ?? selectedDeployment;
            showEditDeployment = false;
        }
        catch (Exception ex)
        {
            editDeployError = ex.Message;
        }
    }

    // ──────── Manifests ────────

    private async Task LoadManifests()
    {
        if (selectedDeployment is not null)
        {
            manifests = await DeploymentService.GetManifestsAsync(selectedDeployment.Id);
        }
    }

    private async Task AddManifest()
    {
        if (selectedDeployment is null) return;

        if (jsModule is not null)
            newManifestYaml = await jsModule.InvokeAsync<string>("getElementValue", "new-manifest-yaml");

        savingManifest = true;
        try
        {
            await DeploymentService.AddManifestAsync(
                selectedDeployment.Id, newManifestKind, newManifestName, newManifestYaml, newManifestSortOrder);
            showAddManifest = false;
            newManifestKind = "";
            newManifestName = "";
            newManifestYaml = "";
            newManifestSortOrder = 0;
            await LoadManifests();
        }
        finally { savingManifest = false; }
    }

    private void StartEditManifest(DeploymentManifest manifest)
    {
        editingManifestId = manifest.Id;
        editManifestYaml = manifest.YamlContent;
    }

    private async Task SaveManifest(Guid manifestId)
    {
        if (jsModule is not null)
            editManifestYaml = await jsModule.InvokeAsync<string>("getElementValue", $"edit-manifest-yaml-{manifestId}");

        savingManifest = true;
        try
        {
            await DeploymentService.UpdateManifestAsync(manifestId, editManifestYaml);
            editingManifestId = null;
            await LoadManifests();
        }
        finally { savingManifest = false; }
    }

    private async Task DeleteManifest(Guid manifestId)
    {
        await DeploymentService.DeleteManifestAsync(manifestId);
        await LoadManifests();
    }

    // ──────── YAML Apply ────────

    private async Task ApplyYamlDeployment()
    {
        if (selectedDeployment is null) return;

        applyingYaml = true;
        yamlApplyOutput = null;
        yamlApplySuccess = null;

        try
        {
            KubernetesOperationResult<string> result =
                await K8sOps.ApplyYamlDeploymentAsync(selectedDeployment.Id);

            yamlApplySuccess = result.IsSuccess;
            yamlApplyOutput = result.IsSuccess ? result.Data : result.Error;
        }
        finally { applyingYaml = false; }
    }

    // ──────── Helm Install / Upgrade ────────

    private async Task InstallOrUpgradeHelm()
    {
        if (selectedDeployment is null) return;

        installingHelm = true;
        helmInstallOutput = null;
        helmInstallSuccess = null;

        try
        {
            KubernetesOperationResult<string> result =
                await K8sOps.HelmInstallOrUpgradeAsync(selectedDeployment.Id);

            helmInstallSuccess = result.IsSuccess;
            helmInstallOutput = result.IsSuccess ? result.Data : result.Error;
        }
        finally { installingHelm = false; }
    }

    // ──────── Helm Values ────────

    private async Task SaveHelmValues()
    {
        // Read the live DOM value so we always have what the user actually typed,
        // regardless of whether @bind's onchange fired before this click.
        if (jsModule is not null)
            helmValuesYaml = await jsModule.InvokeAsync<string>("getElementValue", "helm-values-editor");

        savingHelmValues = true;
        helmValuesSaved = false;
        helmValuesError = null;
        try
        {
            if (selectedDeployment is not null)
            {
                await DeploymentService.UpdateHelmValuesAsync(selectedDeployment.Id, helmValuesYaml);
                selectedDeployment.HelmValues = helmValuesYaml;
            }
            helmValuesSaved = true;
        }
        catch (Exception ex) { helmValuesError = ex.Message; }
        finally { savingHelmValues = false; }
    }

    // ──────── Resources ────────

    private async Task OpenResourcesTab()
    {
        deploymentSection = "resources";
        resourceTree = null; // trigger spinner
        resourcesError = null;

        if (selectedDeployment is not null)
        {
            KubernetesOperationResult<List<DeploymentResource>> result =
                await K8sOps.GetLiveResourcesAsync(selectedDeployment.Id);

            if (result.IsSuccess)
            {
                resourceTree = result.Data ?? [];

                // Derive live status from the resource tree and persist it so
                // the header badges (and the deployment list card) show real values.
                (SyncStatus sync, HealthStatus health) =
                    KubernetesOperationsService.ComputeStatusFromResources(resourceTree);

                await DeploymentService.UpdateDeploymentStatusAsync(
                    selectedDeployment.Id, sync, health);

                // Update in-memory objects so UI refreshes immediately without a reload.
                selectedDeployment.SyncStatus = sync;
                selectedDeployment.HealthStatus = health;

                AppDeployment? listEntry = deployments?.FirstOrDefault(d => d.Id == selectedDeployment.Id);
                if (listEntry is not null)
                {
                    listEntry.SyncStatus = sync;
                    listEntry.HealthStatus = health;
                }
            }
            else
            {
                resourcesError = result.Error;
                resourceTree = [];
            }
        }
    }

    // ──────── Database bindings ────────

    private async Task OpenDatabasesTab()
    {
        deploymentSection = "databases";

        if (selectedDeployment is not null)
        {
            databaseBindings = await CnpgService.GetDatabaseBindingsAsync(selectedDeployment.Id);

            if (availableCnpgDatabases is null)
            {
                List<CnpgCluster> clusters = await CnpgService.GetClustersAsync(TenantId);
                availableCnpgDatabases = clusters
                    .SelectMany(c => c.Databases.Select(d => (c, d)))
                    .ToList();
            }
        }
    }

    private async Task OpenMetricsTab()
    {
        deploymentSection = "metrics";
        if (selectedDeployment is null) return;

        metricsLoading = true;
        metricsError = null;
        deploymentMetrics = null;
        StateHasChanged();

        KubernetesOperationResult<DeploymentMetricsSummary> result =
            await PrometheusService.GetDeploymentMetricsAsync(selectedDeployment.Id);

        if (result.IsSuccess)
            deploymentMetrics = result.Data;
        else
            metricsError = result.Error;

        metricsLoading = false;
    }

    private async Task OpenActivityTab()
    {
        deploymentSection = "activity";
        if (selectedDeployment is null) return;

        activityLoading = true;
        deploymentAuditEvents = null;
        StateHasChanged();

        deploymentAuditEvents = await AuditService.GetDeploymentEventsAsync(selectedDeployment.Id);
        activityLoading = false;
    }

    private async Task OpenAppMetricsSection()
    {
        section = "app-metrics";
        appMetricsLoading = true;
        appMetricsError = null;
        appMetrics = null;
        StateHasChanged();

        KubernetesOperationResult<DeploymentMetricsSummary> result =
            await PrometheusService.GetAppMetricsAsync(App.Id);

        if (result.IsSuccess)
            appMetrics = result.Data;
        else
            appMetricsError = result.Error;

        appMetricsLoading = false;
    }

    private async Task AddDatabaseBinding()
    {
        if (selectedDeployment is null || newBindingDatabaseId == Guid.Empty)
        {
            return;
        }

        bindingError = null;

        try
        {
            DatabaseBinding binding = await CnpgService.AddCnpgDatabaseBindingAsync(
                selectedDeployment.Id, newBindingDatabaseId, newBindingSecretName);

            // Find the cluster that owns this database so we can call sync.
            (CnpgCluster cluster, CnpgDatabase _)? match = availableCnpgDatabases?
                .FirstOrDefault(x => x.Database.Id == newBindingDatabaseId);

            if (match.HasValue)
            {
                await CnpgService.SyncDatabaseCredentialsToK8sAsync(
                    TenantId, match.Value.cluster.Id, newBindingDatabaseId);
            }

            showAddBinding = false;
            newBindingDatabaseId = Guid.Empty;
            newBindingSecretName = "";
            databaseBindings = await CnpgService.GetDatabaseBindingsAsync(selectedDeployment.Id);
        }
        catch (Exception ex)
        {
            bindingError = $"Failed to attach database: {ex.Message}";
        }
    }

    private async Task RemoveDatabaseBinding(Guid bindingId)
    {
        bindingError = null;

        try
        {
            await CnpgService.RemoveDatabaseBindingAsync(bindingId);

            if (selectedDeployment is not null)
            {
                databaseBindings = await CnpgService.GetDatabaseBindingsAsync(selectedDeployment.Id);
            }
        }
        catch (Exception ex)
        {
            bindingError = $"Failed to detach database: {ex.Message}";
        }
    }

    // ──────── Cache bindings ────────

    private async Task OpenCacheTab()
    {
        deploymentSection = "cache";

        if (cacheBindings is null && selectedDeployment is not null)
        {
            cacheBindings = await RedisService.GetCacheBindingsForDeploymentAsync(selectedDeployment.Id);
            availableRedisClusters = await RedisService.GetClustersAsync(TenantId);
        }
    }

    private async Task AddCacheBinding()
    {
        if (selectedDeployment is null || newCacheBindingClusterId == Guid.Empty) return;

        cacheBindingError = null;

        try
        {
            await RedisService.CreateCacheBindingAsync(
                TenantId, newCacheBindingClusterId, selectedDeployment.Id,
                newCacheBindingSecretName.Trim());

            showAddCacheBinding = false;
            newCacheBindingClusterId = Guid.Empty;
            newCacheBindingSecretName = "redis-cache";
            cacheBindings = await RedisService.GetCacheBindingsForDeploymentAsync(selectedDeployment.Id);
        }
        catch (Exception ex)
        {
            cacheBindingError = $"Failed to attach Redis cluster: {ex.Message}";
        }
    }

    private async Task RemoveCacheBinding(Guid bindingId)
    {
        cacheBindingError = null;

        try
        {
            await RedisService.DeleteCacheBindingAsync(TenantId, bindingId);

            if (selectedDeployment is not null)
                cacheBindings = await RedisService.GetCacheBindingsForDeploymentAsync(selectedDeployment.Id);
        }
        catch (Exception ex)
        {
            cacheBindingError = $"Failed to detach: {ex.Message}";
        }
    }

    // ──────── Rendering helpers ────────

    private RenderFragment GetTypeBadge(DeploymentType type) => type switch
    {
        DeploymentType.Manual => @<span class="badge bg-info">Manual</span>,
        DeploymentType.Yaml => @<span class="badge bg-warning text-dark">YAML</span>,
        DeploymentType.HelmChart => @<span class="badge bg-purple text-white" style="background-color: #6f42c1 !important;">Helm</span>,
        _ => @<span class="badge bg-secondary">Unknown</span>
    };

    private RenderFragment GetSyncBadge(SyncStatus status) => status switch
    {
        SyncStatus.Synced => @<span class="badge bg-success"><i class="bi bi-check-circle me-1"></i>Synced</span>,
        SyncStatus.OutOfSync => @<span class="badge bg-warning text-dark"><i class="bi bi-exclamation-circle me-1"></i>OutOfSync</span>,
        SyncStatus.Syncing => @<span class="badge bg-info"><i class="bi bi-arrow-repeat me-1"></i>Syncing</span>,
        SyncStatus.Failed => @<span class="badge bg-danger"><i class="bi bi-x-circle me-1"></i>Failed</span>,
        _ => @<span class="badge bg-secondary">Unknown</span>
    };

    private RenderFragment GetHealthBadge(HealthStatus status) => status switch
    {
        HealthStatus.Healthy => @<span class="badge bg-success"><i class="bi bi-heart-fill me-1"></i>Healthy</span>,
        HealthStatus.Progressing => @<span class="badge bg-info"><i class="bi bi-hourglass-split me-1"></i>Progressing</span>,
        HealthStatus.Degraded => @<span class="badge bg-warning text-dark"><i class="bi bi-exclamation-triangle me-1"></i>Degraded</span>,
        HealthStatus.Missing => @<span class="badge bg-danger"><i class="bi bi-question-circle me-1"></i>Missing</span>,
        HealthStatus.Suspended => @<span class="badge bg-secondary"><i class="bi bi-pause-circle me-1"></i>Suspended</span>,
        _ => @<span class="badge bg-secondary">Unknown</span>
    };

}
