@using EntKube.Web.Data
@using EntKube.Web.Services
@inject VaultService VaultService
@inject TenantService TenantService
@inject DeploymentService DeploymentService
@inject CnpgService CnpgService
@inject MongoService MongoService
@inject RabbitMQService RabbitMQService
@inject RedisService RedisService
@using EntKube.Web.Components.Pages.Shared

@* ═══════════════════════════════════════════════════════════════════
   App Secrets — customer portal view for managing vault secrets and
   connected infrastructure credentials scoped to a single app.

   Tabs:
     App Secrets  — vault secrets tied directly to the app
     Databases    — CNPG / MongoDB / Registered Postgres bindings
     Messaging    — RabbitMQ bindings (vhost / queue / exchange)
     Cache        — Redis bindings
     Registries   — Docker pull secrets

   Access rules:
     Viewer+  — list and reveal values
     Admin    — add / update / delete secrets, trigger syncs
   ═══════════════════════════════════════════════════════════════════ *@

<div class="d-flex align-items-center mb-3">
    <i class="bi bi-shield-lock fs-4 me-2 text-primary"></i>
    <div>
        <h5 class="mb-0">Secrets — @App.Name</h5>
        <small class="text-muted">Application secrets and connected infrastructure credentials.</small>
    </div>
</div>

@if (!vaultInitialized)
{
    <div class="alert alert-warning py-2 small">
        <i class="bi bi-shield-exclamation me-1"></i>
        No vault has been set up for this tenant. Ask your platform administrator to initialize it.
    </div>
}
else
{
    @* ── Tab navigation ── *@
    <ul class="nav nav-tabs mb-3">
        <li class="nav-item">
            <button class="nav-link @(scope == "app" ? "active" : "")" @onclick='() => SetScope("app")'>
                <i class="bi bi-key me-1"></i>App Secrets
            </button>
        </li>
        <li class="nav-item">
            <button class="nav-link @(scope == "database" ? "active" : "")" @onclick='() => SetScope("database")'>
                <i class="bi bi-database me-1"></i>Databases
            </button>
        </li>
        <li class="nav-item">
            <button class="nav-link @(scope == "messaging" ? "active" : "")" @onclick='() => SetScope("messaging")'>
                <i class="bi bi-send me-1"></i>Messaging
            </button>
        </li>
        <li class="nav-item">
            <button class="nav-link @(scope == "cache" ? "active" : "")" @onclick='() => SetScope("cache")'>
                <i class="bi bi-lightning me-1"></i>Cache
            </button>
        </li>
        <li class="nav-item">
            <button class="nav-link @(scope == "docker" ? "active" : "")" @onclick='() => SetScope("docker")'>
                <i class="bi bi-box-seam me-1"></i>Registries
            </button>
        </li>
    </ul>

    @* ════════════════════════════════════════════════════════════════
       Tab: App Secrets
       ════════════════════════════════════════════════════════════════ *@
    @if (scope == "app")
    {
        @* ── Add Secret form (Admin only) ── *@
        @if (AccessRole >= CustomerAccessRole.Admin)
        {
            <div class="card shadow-sm mb-3">
                <div class="card-header bg-white py-2">
                    <i class="bi bi-plus-circle me-1 text-primary"></i><strong>Add / Update Secret</strong>
                </div>
                <div class="card-body">
                    <div class="row g-2 align-items-end">
                        <div class="col-md-4">
                            <label class="form-label small">Name</label>
                            <input type="text" class="form-control form-control-sm"
                                   placeholder="e.g. API_KEY, DB_PASSWORD"
                                   @bind="newSecretName" @bind:event="oninput" />
                        </div>
                        <div class="col-md-5">
                            <label class="form-label small">Value</label>
                            <input type="password" class="form-control form-control-sm"
                                   placeholder="Secret value"
                                   @bind="newSecretValue" @bind:event="oninput" />
                        </div>
                        <div class="col-auto">
                            <button class="btn btn-sm btn-primary" @onclick="AddSecret"
                                    disabled="@(string.IsNullOrWhiteSpace(newSecretName) || string.IsNullOrWhiteSpace(newSecretValue) || saving)">
                                @if (saving) { <span class="spinner-border spinner-border-sm me-1"></span> }
                                <i class="bi bi-plus-lg me-1"></i>Set Secret
                            </button>
                        </div>
                    </div>
                    <div class="form-text">
                        If a secret with this name already exists it will be updated in place.
                    </div>
                    @if (errorMessage is not null)
                    {
                        <div class="alert alert-danger py-1 small mt-2 mb-0">
                            <i class="bi bi-exclamation-triangle me-1"></i>@errorMessage
                        </div>
                    }
                    @if (successMessage is not null)
                    {
                        <div class="alert alert-success py-1 small mt-2 mb-0">
                            <i class="bi bi-check-circle me-1"></i>@successMessage
                        </div>
                    }
                </div>
            </div>
        }

        @* ── Secrets list ── *@
        <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-lock me-2 text-primary"></i>
                    <strong>Stored Secrets</strong>
                    @if (secrets is not null)
                    {
                        <span class="badge bg-secondary ms-1">@secrets.Count</span>
                    }
                </div>
                @if (AccessRole >= CustomerAccessRole.Admin && secrets?.Any(s => s.SyncToKubernetes) == true)
                {
                    <button class="btn btn-sm btn-outline-success" @onclick="SyncAllToKubernetes" disabled="@syncingSecrets">
                        @if (syncingSecrets) { <span class="spinner-border spinner-border-sm me-1"></span> }
                        else { <i class="bi bi-cloud-arrow-up me-1"></i> }
                        Sync All to K8s
                    </button>
                }
            </div>
            <div class="card-body p-0">
                <LoadingPanel Loading="@(secrets is null)">
                @if (secrets is not null && secrets.Count == 0)
                {
                    <EmptyState Icon="bi-lock"
                                Message="@(AccessRole >= CustomerAccessRole.Admin ? "No secrets stored yet. Use the form above to add one." : "No secrets stored for this app yet.")" />
                }
                else if (secrets is not null)
                {
                    <div class="table-responsive">
                        <table class="table table-hover align-middle mb-0">
                            <thead class="table-light">
                                <tr>
                                    <th>Name</th>
                                    <th>K8s Sync</th>
                                    <th>K8s Secret</th>
                                    <th>Namespace</th>
                                    <th>Updated</th>
                                    <th class="text-end" style="min-width: 120px;">Actions</th>
                                </tr>
                            </thead>
                            <tbody>
                                @foreach (VaultSecret secret in secrets)
                                {
                                    <tr>
                                        <td><code>@secret.Name</code></td>
                                        <td>
                                            @if (secret.SyncToKubernetes)
                                            {
                                                <span class="badge bg-success"><i class="bi bi-cloud-check me-1"></i>Enabled</span>
                                            }
                                            else
                                            {
                                                <span class="badge bg-secondary">Off</span>
                                            }
                                        </td>
                                        <td><small class="text-muted">@(secret.KubernetesSecretName ?? "—")</small></td>
                                        <td><small class="text-muted">@(secret.KubernetesNamespace ?? "—")</small></td>
                                        <td><small class="text-muted">@secret.UpdatedAt.ToString("MMM d, HH:mm")</small></td>
                                        <td class="text-end">
                                            <button class="btn btn-sm btn-outline-secondary me-1"
                                                    @onclick="() => RevealSecret(secret)"
                                                    title="@(revealedSecretId == secret.Id ? "Hide value" : "Reveal value")">
                                                <i class="bi @(revealedSecretId == secret.Id ? "bi-eye-slash" : "bi-eye")"></i>
                                            </button>

                                            @if (AccessRole >= CustomerAccessRole.Admin)
                                            {
                                                <button class="btn btn-sm btn-outline-warning me-1"
                                                        @onclick="() => StartEdit(secret)" title="Update value">
                                                    <i class="bi bi-pencil"></i>
                                                </button>
                                                <button class="btn btn-sm btn-outline-info me-1"
                                                        @onclick="() => ToggleSync(secret)"
                                                        title="@(secret.SyncToKubernetes ? "Disable K8s sync" : "Configure K8s sync")">
                                                    <i class="bi @(secret.SyncToKubernetes ? "bi-cloud-slash" : "bi-cloud-arrow-up")"></i>
                                                </button>
                                                <button class="btn btn-sm btn-outline-danger"
                                                        @onclick="() => DeleteSecret(secret.Id)" title="Delete secret">
                                                    <i class="bi bi-trash"></i>
                                                </button>
                                            }
                                        </td>
                                    </tr>

                                    @if (revealedSecretId == secret.Id)
                                    {
                                        <tr class="table-light">
                                            <td colspan="6">
                                                <div class="d-flex align-items-center px-2 py-1 gap-2">
                                                    <span class="text-muted small">Value:</span>
                                                    @if (revealLoading)
                                                    {
                                                        <div class="spinner-border spinner-border-sm text-primary" role="status"></div>
                                                    }
                                                    else
                                                    {
                                                        <code class="user-select-all">@revealedValue</code>
                                                    }
                                                </div>
                                            </td>
                                        </tr>
                                    }

                                    @if (editSecretId == secret.Id)
                                    {
                                        <tr class="table-light">
                                            <td colspan="6">
                                                <div class="row g-2 p-2 align-items-center">
                                                    <div class="col-md-6">
                                                        <input type="password" class="form-control form-control-sm"
                                                               placeholder="New secret value"
                                                               @bind="editSecretValue" />
                                                    </div>
                                                    <div class="col-auto">
                                                        <button class="btn btn-sm btn-success" @onclick="SaveEdit"
                                                                disabled="@(string.IsNullOrWhiteSpace(editSecretValue) || saving)">
                                                            @if (saving) { <span class="spinner-border spinner-border-sm me-1"></span> }
                                                            <i class="bi bi-check-lg me-1"></i>Update
                                                        </button>
                                                        <button class="btn btn-sm btn-outline-secondary ms-1" @onclick="CancelEdit">
                                                            Cancel
                                                        </button>
                                                    </div>
                                                </div>
                                            </td>
                                        </tr>
                                    }

                                    @if (syncConfigSecretId == secret.Id)
                                    {
                                        <tr class="table-light">
                                            <td colspan="6">
                                                <div class="row g-2 p-2 align-items-center">
                                                    @if (clusters is not null)
                                                    {
                                                        <div class="col-md-3">
                                                            <select class="form-select form-select-sm" @bind="syncClusterId">
                                                                <option value="@Guid.Empty">Target cluster…</option>
                                                                @foreach (KubernetesCluster cluster in clusters)
                                                                {
                                                                    <option value="@cluster.Id">@cluster.Name</option>
                                                                }
                                                            </select>
                                                        </div>
                                                    }
                                                    <div class="col-md-3">
                                                        <input type="text" class="form-control form-control-sm"
                                                               placeholder="K8s Secret name"
                                                               @bind="syncSecretName" />
                                                    </div>
                                                    <div class="col-md-3">
                                                        <input type="text" class="form-control form-control-sm"
                                                               placeholder="Namespace"
                                                               @bind="syncNamespace" />
                                                    </div>
                                                    <div class="col-auto">
                                                        <button class="btn btn-sm btn-success" @onclick="SaveSync">
                                                            <i class="bi bi-check-lg me-1"></i>Save
                                                        </button>
                                                        <button class="btn btn-sm btn-outline-secondary ms-1"
                                                                @onclick="() => syncConfigSecretId = null">
                                                            Cancel
                                                        </button>
                                                    </div>
                                                </div>
                                            </td>
                                        </tr>
                                    }
                                }
                            </tbody>
                        </table>
                    </div>
                }
                </LoadingPanel>
                @if (syncOutput is not null)
                {
                    <div class="m-3 p-2 bg-dark text-white rounded font-monospace small" style="white-space: pre-wrap; max-height: 200px; overflow-y: auto;">@syncOutput</div>
                }
            </div>
        </div>
    }

    @* ════════════════════════════════════════════════════════════════
       Tab: Databases
       ════════════════════════════════════════════════════════════════ *@
    else if (scope == "database")
    {
        <LoadingPanel Loading="@(!dbLoaded)">
        @if (dbLoaded)
        {
            bool anyDbBindings = dbBindingsByDeployment.Values.Any(b => b.Count > 0);

            @if (!anyDbBindings)
            {
                <EmptyState Icon="bi-database"
                            Message="No databases are connected to this app's deployments yet." />
            }
            else
            {
                @foreach (AppDeployment deployment in deployments!)
                {
                    List<DatabaseBinding> bindings = dbBindingsByDeployment.GetValueOrDefault(deployment.Id, []);
                    if (bindings.Count == 0) continue;

                    <div class="card shadow-sm mb-3">
                        <div class="card-header bg-white py-2">
                            <div class="d-flex align-items-center gap-2">
                                <i class="bi bi-rocket-takeoff text-primary"></i>
                                <strong>@deployment.Name</strong>
                                <span class="text-muted small">
                                    <i class="bi bi-hdd-network me-1"></i>@deployment.Cluster?.Name
                                    <i class="bi bi-box ms-2 me-1"></i>@deployment.Namespace
                                </span>
                            </div>
                        </div>
                        <div class="card-body p-0">
                            <div class="table-responsive">
                                <table class="table table-hover align-middle mb-0">
                                    <thead class="table-light">
                                        <tr>
                                            <th>Type</th>
                                            <th>Database</th>
                                            <th>K8s Secret</th>
                                            <th>Last Synced</th>
                                            @if (AccessRole >= CustomerAccessRole.Admin)
                                            {
                                                <th class="text-end">Actions</th>
                                            }
                                        </tr>
                                    </thead>
                                    <tbody>
                                        @foreach (DatabaseBinding binding in bindings)
                                        {
                                            <tr>
                                                <td>@DbTypeBadge(binding)</td>
                                                <td>
                                                    <span class="fw-medium">@DbDisplayName(binding)</span>
                                                    @if (binding.CnpgDatabase?.CnpgCluster is not null)
                                                    {
                                                        <br /><small class="text-muted">@binding.CnpgDatabase.CnpgCluster.Name</small>
                                                    }
                                                    else if (binding.MongoDatabase?.MongoCluster is not null)
                                                    {
                                                        <br /><small class="text-muted">@binding.MongoDatabase.MongoCluster.Name</small>
                                                    }
                                                </td>
                                                <td>
                                                    <code class="small">@binding.KubernetesSecretName</code>
                                                    <br />
                                                    <small class="text-muted">@deployment.Namespace</small>
                                                </td>
                                                <td>
                                                    @if (binding.LastSyncedAt is not null)
                                                    {
                                                        <small class="text-muted">@binding.LastSyncedAt.Value.ToString("MMM d, HH:mm")</small>
                                                    }
                                                    else
                                                    {
                                                        <span class="badge bg-warning text-dark small">Never synced</span>
                                                    }
                                                </td>
                                                @if (AccessRole >= CustomerAccessRole.Admin)
                                                {
                                                    <td class="text-end">
                                                        @if (binding.CnpgDatabaseId.HasValue || binding.MongoDatabaseId.HasValue)
                                                        {
                                                            <button class="btn btn-sm btn-outline-success"
                                                                    @onclick="() => SyncDatabaseBinding(binding)"
                                                                    disabled="@syncingBindingIds.Contains(binding.Id)"
                                                                    title="Sync credentials to K8s namespace">
                                                                @if (syncingBindingIds.Contains(binding.Id))
                                                                {
                                                                    <span class="spinner-border spinner-border-sm me-1"></span>
                                                                }
                                                                else
                                                                {
                                                                    <i class="bi bi-cloud-arrow-up me-1"></i>
                                                                }
                                                                Sync
                                                            </button>
                                                        }
                                                        @if (bindingSyncErrors.TryGetValue(binding.Id, out string? dbErr) && dbErr is not null)
                                                        {
                                                            <div class="text-danger small mt-1">@dbErr</div>
                                                        }
                                                    </td>
                                                }
                                            </tr>
                                        }
                                    </tbody>
                                </table>
                            </div>
                        </div>
                    </div>
                }
            }
        }
        </LoadingPanel>
    }

    @* ════════════════════════════════════════════════════════════════
       Tab: Messaging (RabbitMQ)
       ════════════════════════════════════════════════════════════════ *@
    else if (scope == "messaging")
    {
        <LoadingPanel Loading="@(!msgLoaded)">
        @if (msgLoaded)
        {
            bool anyMsgBindings = msgBindingsByDeployment.Values.Any(b => b.Count > 0);

            @if (!anyMsgBindings)
            {
                <EmptyState Icon="bi-send"
                            Message="No RabbitMQ connections are configured for this app's deployments yet." />
            }
            else
            {
                @foreach (AppDeployment deployment in deployments!)
                {
                    List<MessagingBinding> bindings = msgBindingsByDeployment.GetValueOrDefault(deployment.Id, []);
                    if (bindings.Count == 0) continue;

                    <div class="card shadow-sm mb-3">
                        <div class="card-header bg-white py-2">
                            <div class="d-flex align-items-center gap-2">
                                <i class="bi bi-rocket-takeoff text-primary"></i>
                                <strong>@deployment.Name</strong>
                                <span class="text-muted small">
                                    <i class="bi bi-hdd-network me-1"></i>@deployment.Cluster?.Name
                                    <i class="bi bi-box ms-2 me-1"></i>@deployment.Namespace
                                </span>
                            </div>
                        </div>
                        <div class="card-body p-0">
                            <div class="table-responsive">
                                <table class="table table-hover align-middle mb-0">
                                    <thead class="table-light">
                                        <tr>
                                            <th>Cluster</th>
                                            <th>Vhost</th>
                                            <th>Queue / Exchange</th>
                                            <th>K8s Secret</th>
                                            <th>Last Synced</th>
                                            @if (AccessRole >= CustomerAccessRole.Admin)
                                            {
                                                <th class="text-end">Actions</th>
                                            }
                                        </tr>
                                    </thead>
                                    <tbody>
                                        @foreach (MessagingBinding binding in bindings)
                                        {
                                            <tr>
                                                <td><small>@binding.Cluster?.Name</small></td>
                                                <td><code class="small">@binding.Vhost</code></td>
                                                <td>
                                                    @if (binding.QueueName is not null)
                                                    {
                                                        <span class="badge bg-info-subtle text-info border border-info-subtle me-1">
                                                            <i class="bi bi-collection me-1"></i>Queue
                                                        </span>
                                                        <code class="small">@binding.QueueName</code>
                                                    }
                                                    @if (binding.ExchangeName is not null)
                                                    {
                                                        <span class="badge bg-warning-subtle text-warning border border-warning-subtle me-1">
                                                            <i class="bi bi-arrow-left-right me-1"></i>Exchange
                                                        </span>
                                                        <code class="small">@binding.ExchangeName</code>
                                                    }
                                                    @if (binding.QueueName is null && binding.ExchangeName is null)
                                                    {
                                                        <span class="text-muted small">vhost only</span>
                                                    }
                                                </td>
                                                <td>
                                                    <code class="small">@binding.KubernetesSecretName</code>
                                                    <br />
                                                    <small class="text-muted">@deployment.Namespace</small>
                                                </td>
                                                <td>
                                                    @if (binding.LastSyncedAt is not null)
                                                    {
                                                        <small class="text-muted">@binding.LastSyncedAt.Value.ToString("MMM d, HH:mm")</small>
                                                    }
                                                    else
                                                    {
                                                        <span class="badge bg-warning text-dark small">Never synced</span>
                                                    }
                                                </td>
                                                @if (AccessRole >= CustomerAccessRole.Admin)
                                                {
                                                    <td class="text-end">
                                                        <button class="btn btn-sm btn-outline-success"
                                                                @onclick="() => SyncMessagingBinding(binding)"
                                                                disabled="@syncingBindingIds.Contains(binding.Id)"
                                                                title="Sync AMQP connection details to K8s namespace">
                                                            @if (syncingBindingIds.Contains(binding.Id))
                                                            {
                                                                <span class="spinner-border spinner-border-sm me-1"></span>
                                                            }
                                                            else
                                                            {
                                                                <i class="bi bi-cloud-arrow-up me-1"></i>
                                                            }
                                                            Sync
                                                        </button>
                                                        @if (bindingSyncErrors.TryGetValue(binding.Id, out string? msgErr) && msgErr is not null)
                                                        {
                                                            <div class="text-danger small mt-1">@msgErr</div>
                                                        }
                                                    </td>
                                                }
                                            </tr>
                                        }
                                    </tbody>
                                </table>
                            </div>
                        </div>
                    </div>
                }
            }
        }
        </LoadingPanel>
    }

    @* ════════════════════════════════════════════════════════════════
       Tab: Cache (Redis)
       ════════════════════════════════════════════════════════════════ *@
    else if (scope == "cache")
    {
        <LoadingPanel Loading="@(!cacheLoaded)">
        @if (cacheLoaded)
        {
            bool anyCacheBindings = cacheBindingsByDeployment.Values.Any(b => b.Count > 0);

            @if (!anyCacheBindings)
            {
                <EmptyState Icon="bi-lightning"
                            Message="No Redis cache connections are configured for this app's deployments yet." />
            }
            else
            {
                @foreach (AppDeployment deployment in deployments!)
                {
                    List<CacheBinding> bindings = cacheBindingsByDeployment.GetValueOrDefault(deployment.Id, []);
                    if (bindings.Count == 0) continue;

                    <div class="card shadow-sm mb-3">
                        <div class="card-header bg-white py-2">
                            <div class="d-flex align-items-center gap-2">
                                <i class="bi bi-rocket-takeoff text-primary"></i>
                                <strong>@deployment.Name</strong>
                                <span class="text-muted small">
                                    <i class="bi bi-hdd-network me-1"></i>@deployment.Cluster?.Name
                                    <i class="bi bi-box ms-2 me-1"></i>@deployment.Namespace
                                </span>
                            </div>
                        </div>
                        <div class="card-body p-0">
                            <div class="table-responsive">
                                <table class="table table-hover align-middle mb-0">
                                    <thead class="table-light">
                                        <tr>
                                            <th>Redis Cluster</th>
                                            <th>K8s Secret</th>
                                            <th>Last Synced</th>
                                            @if (AccessRole >= CustomerAccessRole.Admin)
                                            {
                                                <th class="text-end">Actions</th>
                                            }
                                        </tr>
                                    </thead>
                                    <tbody>
                                        @foreach (CacheBinding binding in bindings)
                                        {
                                            <tr>
                                                <td>
                                                    <i class="bi bi-lightning text-warning me-1"></i>
                                                    <span class="fw-medium">@binding.RedisCluster.Name</span>
                                                    @if (binding.RedisCluster.KubernetesCluster is not null)
                                                    {
                                                        <br /><small class="text-muted">@binding.RedisCluster.KubernetesCluster.Name</small>
                                                    }
                                                </td>
                                                <td>
                                                    <code class="small">@binding.KubernetesSecretName</code>
                                                    <br />
                                                    <small class="text-muted">@deployment.Namespace</small>
                                                </td>
                                                <td>
                                                    @if (binding.LastSyncedAt is not null)
                                                    {
                                                        <small class="text-muted">@binding.LastSyncedAt.Value.ToString("MMM d, HH:mm")</small>
                                                    }
                                                    else
                                                    {
                                                        <span class="badge bg-warning text-dark small">Never synced</span>
                                                    }
                                                </td>
                                                @if (AccessRole >= CustomerAccessRole.Admin)
                                                {
                                                    <td class="text-end">
                                                        <button class="btn btn-sm btn-outline-success"
                                                                @onclick="() => SyncCacheBinding(binding)"
                                                                disabled="@syncingBindingIds.Contains(binding.Id)"
                                                                title="Sync Redis connection details to K8s namespace">
                                                            @if (syncingBindingIds.Contains(binding.Id))
                                                            {
                                                                <span class="spinner-border spinner-border-sm me-1"></span>
                                                            }
                                                            else
                                                            {
                                                                <i class="bi bi-cloud-arrow-up me-1"></i>
                                                            }
                                                            Sync
                                                        </button>
                                                        @if (bindingSyncErrors.TryGetValue(binding.Id, out string? cacheErr) && cacheErr is not null)
                                                        {
                                                            <div class="text-danger small mt-1">@cacheErr</div>
                                                        }
                                                    </td>
                                                }
                                            </tr>
                                        }
                                    </tbody>
                                </table>
                            </div>
                        </div>
                    </div>
                }
            }
        }
        </LoadingPanel>
    }

    @* ════════════════════════════════════════════════════════════════
       Tab: Docker Registries
       ════════════════════════════════════════════════════════════════ *@
    else if (scope == "docker")
    {
        <DockerRegistriesPanel
            TenantId="TenantId"
            AppId="App.Id"
            IsAdmin="AccessRole >= CustomerAccessRole.Admin" />
    }
}

@code {
    [Parameter] public required Data.App App { get; set; }
    [Parameter] public Guid TenantId { get; set; }
    [Parameter] public CustomerAccessRole AccessRole { get; set; }

    private bool vaultInitialized;
    private string scope = "app";

    // ── App Secrets ──────────────────────────────────────────────────
    private List<VaultSecret>? secrets;
    private List<KubernetesCluster>? clusters;

    private string newSecretName = "";
    private string newSecretValue = "";
    private bool saving;
    private string? errorMessage;
    private string? successMessage;

    private Guid? revealedSecretId;
    private string? revealedValue;
    private bool revealLoading;

    private Guid? editSecretId;
    private string editSecretValue = "";

    private Guid? syncConfigSecretId;
    private string syncSecretName = "";
    private string syncNamespace = "";
    private Guid syncClusterId;

    private bool syncingSecrets;
    private string? syncOutput;

    // ── Shared binding state ─────────────────────────────────────────
    private List<AppDeployment>? deployments;
    private HashSet<Guid> syncingBindingIds = [];
    private Dictionary<Guid, string?> bindingSyncErrors = new();

    // ── Databases ────────────────────────────────────────────────────
    private Dictionary<Guid, List<DatabaseBinding>> dbBindingsByDeployment = new();
    private bool dbLoaded;

    // ── Messaging ────────────────────────────────────────────────────
    private Dictionary<Guid, List<MessagingBinding>> msgBindingsByDeployment = new();
    private bool msgLoaded;

    // ── Cache ────────────────────────────────────────────────────────
    private Dictionary<Guid, List<CacheBinding>> cacheBindingsByDeployment = new();
    private bool cacheLoaded;

    protected override async Task OnInitializedAsync()
    {
        SecretVault? vault = await VaultService.GetVaultAsync(TenantId);
        vaultInitialized = vault is not null;

        if (vaultInitialized)
        {
            await LoadSecrets();
        }

        clusters = await TenantService.GetClustersAsync(TenantId);
    }

    // ── Scope switching ──────────────────────────────────────────────

    private async Task SetScope(string newScope)
    {
        scope = newScope;
        errorMessage = null;
        successMessage = null;

        if (newScope == "database" && !dbLoaded)
            await LoadDatabaseBindings();
        else if (newScope == "messaging" && !msgLoaded)
            await LoadMessagingBindings();
        else if (newScope == "cache" && !cacheLoaded)
            await LoadCacheBindings();
    }

    private async Task EnsureDeployments()
    {
        if (deployments is null)
            deployments = await DeploymentService.GetDeploymentsAsync(App.Id);
    }

    private async Task LoadDatabaseBindings()
    {
        await EnsureDeployments();
        dbBindingsByDeployment.Clear();

        foreach (AppDeployment deployment in deployments!)
        {
            List<DatabaseBinding> bindings = await CnpgService.GetDatabaseBindingsAsync(deployment.Id);
            dbBindingsByDeployment[deployment.Id] = bindings;
        }

        dbLoaded = true;
    }

    private async Task LoadMessagingBindings()
    {
        await EnsureDeployments();
        msgBindingsByDeployment.Clear();

        foreach (AppDeployment deployment in deployments!)
        {
            List<MessagingBinding> bindings = await RabbitMQService.GetMessagingBindingsForDeploymentAsync(deployment.Id);
            msgBindingsByDeployment[deployment.Id] = bindings;
        }

        msgLoaded = true;
    }

    private async Task LoadCacheBindings()
    {
        await EnsureDeployments();
        cacheBindingsByDeployment.Clear();

        foreach (AppDeployment deployment in deployments!)
        {
            List<CacheBinding> bindings = await RedisService.GetCacheBindingsForDeploymentAsync(deployment.Id);
            cacheBindingsByDeployment[deployment.Id] = bindings;
        }

        cacheLoaded = true;
    }

    // ── App Secrets: Add ─────────────────────────────────────────────

    private async Task LoadSecrets()
    {
        secrets = await VaultService.GetAppSecretsAsync(TenantId, App.Id);
    }

    private async Task AddSecret()
    {
        errorMessage = null;
        successMessage = null;
        saving = true;

        try
        {
            await VaultService.SetAppSecretAsync(TenantId, App.Id, newSecretName.Trim(), newSecretValue.Trim());
            successMessage = $"Secret '{newSecretName.Trim()}' saved.";
            newSecretName = "";
            newSecretValue = "";
            await LoadSecrets();
        }
        catch (Exception ex)
        {
            errorMessage = ex.Message;
        }
        finally { saving = false; }
    }

    // ── App Secrets: Reveal ──────────────────────────────────────────

    private async Task RevealSecret(VaultSecret secret)
    {
        if (revealedSecretId == secret.Id)
        {
            revealedSecretId = null;
            revealedValue = null;
            return;
        }

        revealLoading = true;
        revealedSecretId = secret.Id;
        revealedValue = null;
        revealedValue = await VaultService.GetSecretValueByIdAsync(secret.Id);
        revealLoading = false;
    }

    // ── App Secrets: Edit ────────────────────────────────────────────

    private void StartEdit(VaultSecret secret)
    {
        editSecretId = secret.Id;
        editSecretValue = "";
        revealedSecretId = null;
        revealedValue = null;
    }

    private void CancelEdit()
    {
        editSecretId = null;
        editSecretValue = "";
    }

    private async Task SaveEdit()
    {
        if (editSecretId is null || string.IsNullOrWhiteSpace(editSecretValue)) return;

        saving = true;
        errorMessage = null;

        try
        {
            bool updated = await VaultService.UpdateSecretValueAsync(editSecretId.Value, editSecretValue.Trim());
            successMessage = updated ? "Secret value updated." : null;
            errorMessage = updated ? null : "Failed to update secret.";
        }
        finally { saving = false; }

        editSecretId = null;
        editSecretValue = "";
        await LoadSecrets();
    }

    // ── App Secrets: Delete ──────────────────────────────────────────

    private async Task DeleteSecret(Guid secretId)
    {
        errorMessage = null;
        (bool canDelete, string? reason) = await VaultService.CanDeleteSecretAsync(secretId);

        if (!canDelete)
        {
            errorMessage = reason;
            return;
        }

        await VaultService.DeleteSecretAsync(secretId);
        revealedSecretId = null;
        editSecretId = null;
        await LoadSecrets();
    }

    // ── App Secrets: K8s sync ────────────────────────────────────────

    private void ToggleSync(VaultSecret secret)
    {
        if (secret.SyncToKubernetes)
        {
            _ = DisableSync(secret.Id);
        }
        else
        {
            syncConfigSecretId = secret.Id;
            syncSecretName = secret.KubernetesSecretName ?? "";
            syncNamespace = secret.KubernetesNamespace ?? "";
            syncClusterId = secret.KubernetesClusterId ?? Guid.Empty;
        }
    }

    private async Task DisableSync(Guid secretId)
    {
        await VaultService.ConfigureKubernetesSyncAsync(secretId, syncEnabled: false, secretName: null, ns: null);
        await LoadSecrets();
    }

    private async Task SaveSync()
    {
        if (syncConfigSecretId is null) return;

        Guid? clusterId = syncClusterId != Guid.Empty ? syncClusterId : (Guid?)null;

        await VaultService.ConfigureKubernetesSyncAsync(
            syncConfigSecretId.Value,
            syncEnabled: true,
            secretName: syncSecretName.Trim(),
            ns: syncNamespace.Trim(),
            clusterId: clusterId);

        syncConfigSecretId = null;
        await LoadSecrets();
    }

    private async Task SyncAllToKubernetes()
    {
        syncingSecrets = true;
        syncOutput = null;

        try
        {
            HelmExecutionResult result = await VaultService.SyncAppSecretsToKubernetesAsync(TenantId, App.Id);
            syncOutput = result.Output;
        }
        finally
        {
            syncingSecrets = false;
        }
    }

    // ── Database binding sync ────────────────────────────────────────

    private async Task SyncDatabaseBinding(DatabaseBinding binding)
    {
        syncingBindingIds.Add(binding.Id);
        bindingSyncErrors.Remove(binding.Id);

        try
        {
            if (binding.CnpgDatabaseId.HasValue && binding.CnpgDatabase is not null)
            {
                await CnpgService.SyncDatabaseCredentialsToK8sAsync(
                    TenantId, binding.CnpgDatabase.CnpgClusterId, binding.CnpgDatabase.Id);
            }
            else if (binding.MongoDatabaseId.HasValue && binding.MongoDatabase is not null)
            {
                await MongoService.SyncDatabaseCredentialsToK8sAsync(
                    TenantId, binding.MongoDatabase.MongoClusterId, binding.MongoDatabase.Id);
            }

            // Refresh to show updated LastSyncedAt.
            await LoadDatabaseBindings();
        }
        catch (Exception ex)
        {
            bindingSyncErrors[binding.Id] = ex.Message;
        }
        finally
        {
            syncingBindingIds.Remove(binding.Id);
        }
    }

    // ── Messaging binding sync ───────────────────────────────────────

    private async Task SyncMessagingBinding(MessagingBinding binding)
    {
        syncingBindingIds.Add(binding.Id);
        bindingSyncErrors.Remove(binding.Id);

        try
        {
            await RabbitMQService.SyncMessagingBindingAsync(TenantId, binding.Id);
            await LoadMessagingBindings();
        }
        catch (Exception ex)
        {
            bindingSyncErrors[binding.Id] = ex.Message;
        }
        finally
        {
            syncingBindingIds.Remove(binding.Id);
        }
    }

    // ── Cache binding sync ───────────────────────────────────────────

    private async Task SyncCacheBinding(CacheBinding binding)
    {
        syncingBindingIds.Add(binding.Id);
        bindingSyncErrors.Remove(binding.Id);

        try
        {
            await RedisService.SyncCacheBindingAsync(TenantId, binding.Id);
            await LoadCacheBindings();
        }
        catch (Exception ex)
        {
            bindingSyncErrors[binding.Id] = ex.Message;
        }
        finally
        {
            syncingBindingIds.Remove(binding.Id);
        }
    }

    // ── Display helpers ──────────────────────────────────────────────

    private RenderFragment DbTypeBadge(DatabaseBinding binding)
    {
        if (binding.CnpgDatabaseId.HasValue)
            return @<span class="badge bg-primary-subtle text-primary border border-primary-subtle">
                       <i class="bi bi-database me-1"></i>PostgreSQL
                   </span>;

        if (binding.MongoDatabaseId.HasValue)
            return @<span class="badge bg-success-subtle text-success border border-success-subtle">
                       <i class="bi bi-database me-1"></i>MongoDB
                   </span>;

        if (binding.RegisteredPostgresDatabaseId.HasValue)
            return @<span class="badge bg-info-subtle text-info border border-info-subtle">
                       <i class="bi bi-database me-1"></i>Postgres (registered)
                   </span>;

        return @<span class="badge bg-secondary">Unknown</span>;
    }

    private static string DbDisplayName(DatabaseBinding binding)
    {
        if (binding.CnpgDatabase is not null) return binding.CnpgDatabase.Name;
        if (binding.MongoDatabase is not null) return binding.MongoDatabase.Name;
        if (binding.RegisteredPostgresDatabase is not null) return binding.RegisteredPostgresDatabase.Name;
        return "—";
    }
}
