{% extends "base.html" %}

{% block title %}Sites - S3 Compatible Storage{% endblock %}

{% block content %}
<div class="page-header d-flex justify-content-between align-items-center mb-4">
  <div>
    <p class="text-uppercase text-muted small mb-1">Geo-Distribution</p>
    <h1 class="h3 mb-1 d-flex align-items-center gap-2">
      <svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" fill="currentColor" class="text-primary" viewBox="0 0 16 16">
        <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8zm7.5-6.923c-.67.204-1.335.82-1.887 1.855A7.97 7.97 0 0 0 5.145 4H7.5V1.077zM4.09 4a9.267 9.267 0 0 1 .64-1.539 6.7 6.7 0 0 1 .597-.933A7.025 7.025 0 0 0 2.255 4H4.09zm-.582 3.5c.03-.877.138-1.718.312-2.5H1.674a6.958 6.958 0 0 0-.656 2.5h2.49zM4.847 5a12.5 12.5 0 0 0-.338 2.5H7.5V5H4.847zM8.5 5v2.5h2.99a12.495 12.495 0 0 0-.337-2.5H8.5zM4.51 8.5a12.5 12.5 0 0 0 .337 2.5H7.5V8.5H4.51zm3.99 0V11h2.653c.187-.765.306-1.608.338-2.5H8.5zM5.145 12c.138.386.295.744.468 1.068.552 1.035 1.218 1.65 1.887 1.855V12H5.145zm.182 2.472a6.696 6.696 0 0 1-.597-.933A9.268 9.268 0 0 1 4.09 12H2.255a7.024 7.024 0 0 0 3.072 2.472zM3.82 11a13.652 13.652 0 0 1-.312-2.5h-2.49c.062.89.291 1.733.656 2.5H3.82zm6.853 3.472A7.024 7.024 0 0 0 13.745 12H11.91a9.27 9.27 0 0 1-.64 1.539 6.688 6.688 0 0 1-.597.933zM8.5 12v2.923c.67-.204 1.335-.82 1.887-1.855.173-.324.33-.682.468-1.068H8.5zm3.68-1h2.146c.365-.767.594-1.61.656-2.5h-2.49a13.65 13.65 0 0 1-.312 2.5zm2.802-3.5a6.959 6.959 0 0 0-.656-2.5H12.18c.174.782.282 1.623.312 2.5h2.49zM11.27 2.461c.247.464.462.98.64 1.539h1.835a7.024 7.024 0 0 0-3.072-2.472c.218.284.418.598.597.933zM10.855 4a7.966 7.966 0 0 0-.468-1.068C9.835 1.897 9.17 1.282 8.5 1.077V4h2.355z"/>
      </svg>
      Site Registry
    </h1>
    <p class="text-muted mb-0 mt-1">Configure this site's identity and manage peer sites for geo-distribution.</p>
  </div>
  <div class="d-none d-md-flex align-items-center gap-2">
    {% if local_site and local_site.site_id %}
    <span class="badge bg-secondary bg-opacity-10 text-secondary fs-6 px-3 py-2">
      {{ local_site.site_id }}
    </span>
    <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="text-muted" viewBox="0 0 16 16">
      <path fill-rule="evenodd" d="M1 8a.5.5 0 0 1 .5-.5h11.793l-3.147-3.146a.5.5 0 0 1 .708-.708l4 4a.5.5 0 0 1 0 .708l-4 4a.5.5 0 0 1-.708-.708L13.293 8.5H1.5A.5.5 0 0 1 1 8z"/>
    </svg>
    {% endif %}
    <span class="badge bg-primary bg-opacity-10 text-primary fs-6 px-3 py-2">
      {{ peers|length }} peer{% if peers|length != 1 %}s{% else %}{% endif %}
    </span>
  </div>
</div>

<div class="row g-4">
    <div class="col-lg-4 col-md-5">
        <div class="card shadow-sm border-0 mb-4" style="border-radius: 1rem;">
            <div class="card-header bg-transparent border-0 pt-4 pb-0 px-4">
                <h5 class="fw-semibold d-flex align-items-center gap-2 mb-1">
                    <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="text-primary" viewBox="0 0 16 16">
                        <path d="M8 16s6-5.686 6-10A6 6 0 0 0 2 6c0 4.314 6 10 6 10zm0-7a3 3 0 1 1 0-6 3 3 0 0 1 0 6z"/>
                    </svg>
                    Local Site Identity
                </h5>
                <p class="text-muted small mb-0">This site's configuration</p>
            </div>
            <div class="card-body px-4 pb-4">
                <form method="POST" action="{{ url_for(endpoint="ui.update_local_site") }}" id="localSiteForm">
                    <input type="hidden" name="csrf_token" value="{{ csrf_token_value }}"/>
                    <div class="mb-3">
                        <label for="site_id" class="form-label fw-medium">Site ID</label>
                        <input type="text" class="form-control" id="site_id" name="site_id" required
                            value="{% if local_site %}{{ local_site.site_id }}{% else %}{{ config_site_id | default(value="") }}{% endif %}"
                            placeholder="us-west-1">
                        <div class="form-text">Unique identifier for this site</div>
                    </div>
                    <div class="mb-3">
                        <label for="endpoint" class="form-label fw-medium">Endpoint URL</label>
                        <input type="url" class="form-control" id="endpoint" name="endpoint"
                            value="{% if local_site %}{{ local_site.endpoint }}{% else %}{{ config_site_endpoint | default(value="") }}{% endif %}"
                            placeholder="https://s3.us-west-1.example.com">
                        <div class="form-text">Public URL for this site</div>
                    </div>
                    <div class="mb-3">
                        <label for="region" class="form-label fw-medium">Region</label>
                        <input type="text" class="form-control" id="region" name="region"
                            value="{% if local_site %}{{ local_site.region }}{% else %}{{ config_site_region }}{% endif %}">
                    </div>
                    <div class="row mb-3">
                        <div class="col-6">
                            <label for="priority" class="form-label fw-medium">Priority</label>
                            <input type="number" class="form-control" id="priority" name="priority"
                                value="{% if local_site %}{{ local_site.priority }}{% else %}{{ 100 }}{% endif %}" min="0">
                            <div class="form-text">Lower = preferred</div>
                        </div>
                        <div class="col-6">
                            <label for="display_name" class="form-label fw-medium">Display Name</label>
                            <input type="text" class="form-control" id="display_name" name="display_name"
                                value="{% if local_site %}{{ local_site.display_name }}{% else %}{{ "" }}{% endif %}"
                                placeholder="US West Primary">
                        </div>
                    </div>
                    <div class="d-grid">
                        <button type="submit" class="btn btn-primary">
                            <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" class="me-1" viewBox="0 0 16 16">
                                <path d="M10.97 4.97a.75.75 0 0 1 1.07 1.05l-3.99 4.99a.75.75 0 0 1-1.08.02L4.324 8.384a.75.75 0 1 1 1.06-1.06l2.094 2.093 3.473-4.425a.267.267 0 0 1 .02-.022z"/>
                            </svg>
                            Save Local Site
                        </button>
                    </div>
                </form>
            </div>
        </div>

        <div class="card shadow-sm border-0" style="border-radius: 1rem;">
            <div class="card-header bg-transparent border-0 pt-3 pb-0 px-4">
                <button class="btn btn-link text-decoration-none p-0 w-100 d-flex align-items-center justify-content-between"
                    type="button" data-bs-toggle="collapse" data-bs-target="#addPeerCollapse"
                    aria-expanded="false" aria-controls="addPeerCollapse">
                    <span class="d-flex align-items-center gap-2">
                        <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="text-primary" viewBox="0 0 16 16">
                            <path fill-rule="evenodd" d="M8 2a.5.5 0 0 1 .5.5v5h5a.5.5 0 0 1 0 1h-5v5a.5.5 0 0 1-1 0v-5h-5a.5.5 0 0 1 0-1h5v-5A.5.5 0 0 1 8 2Z"/>
                        </svg>
                        <span class="fw-semibold h5 mb-0">Add Peer Site</span>
                    </span>
                    <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="text-muted add-peer-chevron" viewBox="0 0 16 16">
                        <path fill-rule="evenodd" d="M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z"/>
                    </svg>
                </button>
                <p class="text-muted small mb-0 mt-1">Register a remote site</p>
            </div>
            <div class="collapse" id="addPeerCollapse">
                <div class="card-body px-4 pb-4">
                    <form method="POST" action="{{ url_for(endpoint="ui.add_peer_site") }}" id="addPeerForm">
                        <input type="hidden" name="csrf_token" value="{{ csrf_token_value }}"/>
                        <div class="mb-3">
                            <label for="peer_site_id" class="form-label fw-medium">Site ID</label>
                            <input type="text" class="form-control" id="peer_site_id" name="site_id" required placeholder="us-east-1">
                        </div>
                        <div class="mb-3">
                            <label for="peer_endpoint" class="form-label fw-medium">Endpoint URL</label>
                            <input type="url" class="form-control" id="peer_endpoint" name="endpoint" required placeholder="https://s3.us-east-1.example.com">
                        </div>
                        <div class="mb-3">
                            <label for="peer_region" class="form-label fw-medium">Region</label>
                            <input type="text" class="form-control" id="peer_region" name="region" value="us-east-1">
                        </div>
                        <div class="row mb-3">
                            <div class="col-6">
                                <label for="peer_priority" class="form-label fw-medium">Priority</label>
                                <input type="number" class="form-control" id="peer_priority" name="priority" value="100" min="0">
                            </div>
                            <div class="col-6">
                                <label for="peer_display_name" class="form-label fw-medium">Display Name</label>
                                <input type="text" class="form-control" id="peer_display_name" name="display_name" placeholder="US East DR">
                            </div>
                        </div>
                        <div class="mb-3">
                            <label for="peer_connection_id" class="form-label fw-medium">Connection</label>
                            <select class="form-select" id="peer_connection_id" name="connection_id">
                                <option value="">No connection</option>
                                {% for conn in connections %}
                                <option value="{{ conn.id }}">{{ conn.name }} ({{ conn.endpoint_url }})</option>
                                {% endfor %}
                            </select>
                            <div class="form-text">Link to a remote connection for health checks</div>
                        </div>
                        <div class="mb-3">
                            <label for="peer_inbound_access_key" class="form-label fw-medium">Peer Inbound Access Key</label>
                            <input type="text" class="form-control" id="peer_inbound_access_key" name="peer_inbound_access_key" placeholder="AKIA... (optional)" autocomplete="off" spellcheck="false">
                            <div class="form-text">Access key the peer presents when calling this site (e.g. /admin/cluster/overview). Leave blank to require admin credentials.</div>
                        </div>
                        <div class="d-grid">
                            <button type="submit" class="btn btn-primary">
                                <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" class="me-1" viewBox="0 0 16 16">
                                    <path fill-rule="evenodd" d="M8 2a.5.5 0 0 1 .5.5v5h5a.5.5 0 0 1 0 1h-5v5a.5.5 0 0 1-1 0v-5h-5a.5.5 0 0 1 0-1h5v-5A.5.5 0 0 1 8 2Z"/>
                                </svg>
                                Add Peer Site
                            </button>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>

    <div class="col-lg-8 col-md-7">
        <div class="card shadow-sm border-0" style="border-radius: 1rem;">
            <div class="card-header bg-transparent border-0 pt-4 pb-0 px-4 d-flex justify-content-between align-items-start">
                <div>
                    <h5 class="fw-semibold d-flex align-items-center gap-2 mb-1">
                        <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="text-muted" viewBox="0 0 16 16">
                            <path fill-rule="evenodd" d="M6 3.5A1.5 1.5 0 0 1 7.5 2h1A1.5 1.5 0 0 1 10 3.5v1A1.5 1.5 0 0 1 8.5 6v1H14a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-1 0V8h-5v.5a.5.5 0 0 1-1 0V8h-5v.5a.5.5 0 0 1-1 0v-1A.5.5 0 0 1 2 7h5.5V6A1.5 1.5 0 0 1 6 4.5v-1zM8.5 5a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5h-1a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h1zM0 11.5A1.5 1.5 0 0 1 1.5 10h1A1.5 1.5 0 0 1 4 11.5v1A1.5 1.5 0 0 1 2.5 14h-1A1.5 1.5 0 0 1 0 12.5v-1zm1.5-.5a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h1a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5h-1zm4.5.5A1.5 1.5 0 0 1 7.5 10h1a1.5 1.5 0 0 1 1.5 1.5v1A1.5 1.5 0 0 1 8.5 14h-1A1.5 1.5 0 0 1 6 12.5v-1zm1.5-.5a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h1a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5h-1zm4.5.5a1.5 1.5 0 0 1 1.5-1.5h1a1.5 1.5 0 0 1 1.5 1.5v1a1.5 1.5 0 0 1-1.5 1.5h-1a1.5 1.5 0 0 1-1.5-1.5v-1zm1.5-.5a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h1a.5.5 0 0 0 .5-.5v-1a.5.5 0 0 0-.5-.5h-1z"/>
                        </svg>
                        Peer Sites
                    </h5>
                    <p class="text-muted small mb-0">Known remote sites in the cluster</p>
                </div>
                {% if peers %}
                <button type="button" class="btn btn-outline-secondary btn-sm" id="btnCheckAllHealth" title="Check health of all peers">
                    <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" class="me-1" viewBox="0 0 16 16">
                        <path d="M11.251.068a.5.5 0 0 1 .227.58L9.677 6.5H13a.5.5 0 0 1 .364.843l-8 8.5a.5.5 0 0 1-.842-.49L6.323 9.5H3a.5.5 0 0 1-.364-.843l8-8.5a.5.5 0 0 1 .615-.09z"/>
                    </svg>
                    Check All
                </button>
                {% endif %}
            </div>
            <div class="card-body px-4 pb-4">
                {% if peers %}
                <div class="table-responsive">
                    <table class="table table-hover align-middle mb-0">
                        <thead class="table-light">
                            <tr>
                                <th scope="col" style="width: 50px;">Health</th>
                                <th scope="col">Site ID</th>
                                <th scope="col">Endpoint</th>
                                <th scope="col">Region</th>
                                <th scope="col">Priority</th>
                                <th scope="col">Sync Status</th>
                                <th scope="col" class="text-end">Actions</th>
                            </tr>
                        </thead>
                        <tbody>
                            {% for item in peers_with_stats %}
                            {% set peer = item.peer %}
                            <tr data-site-id="{{ peer.site_id }}">
                                <td class="text-center">
                                    <span class="peer-health-status" data-site-id="{{ peer.site_id }}"
                                        data-last-checked="{{ peer.last_health_check | default(value="") }}"
                                        title="{% if peer.is_healthy == true %}Healthy{% elif peer.is_healthy == false %}Unhealthy{% else %}Not checked{% endif %}{% if peer.last_health_check %} (checked {{ peer.last_health_check }}){% endif %}"
                                        style="cursor: help;">
                                        {% if peer.is_healthy == true %}
                                        <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="text-success" viewBox="0 0 16 16">
                                            <path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zm-3.97-3.03a.75.75 0 0 0-1.08.022L7.477 9.417 5.384 7.323a.75.75 0 0 0-1.06 1.06L6.97 11.03a.75.75 0 0 0 1.079-.02l3.992-4.99a.75.75 0 0 0-.01-1.05z"/>
                                        </svg>
                                        {% elif peer.is_healthy == false %}
                                        <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="text-danger" viewBox="0 0 16 16">
                                            <path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zM5.354 4.646a.5.5 0 1 0-.708.708L7.293 8l-2.647 2.646a.5.5 0 0 0 .708.708L8 8.707l2.646 2.647a.5.5 0 0 0 .708-.708L8.707 8l2.647-2.646a.5.5 0 0 0-.708-.708L8 7.293 5.354 4.646z"/>
                                        </svg>
                                        {% else %}
                                        <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="text-muted" viewBox="0 0 16 16">
                                            <path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"/>
                                            <path d="M5.255 5.786a.237.237 0 0 0 .241.247h.825c.138 0 .248-.113.266-.25.09-.656.54-1.134 1.342-1.134.686 0 1.314.343 1.314 1.168 0 .635-.374.927-.965 1.371-.673.489-1.206 1.06-1.168 1.987l.003.217a.25.25 0 0 0 .25.246h.811a.25.25 0 0 0 .25-.25v-.105c0-.718.273-.927 1.01-1.486.609-.463 1.244-.977 1.244-2.056 0-1.511-1.276-2.241-2.673-2.241-1.267 0-2.655.59-2.75 2.286zm1.557 5.763c0 .533.425.927 1.01.927.609 0 1.028-.394 1.028-.927 0-.552-.42-.94-1.029-.94-.584 0-1.009.388-1.009.94z"/>
                                        </svg>
                                        {% endif %}
                                    </span>
                                </td>
                                <td>
                                    <div class="d-flex align-items-center gap-2">
                                        <div class="peer-icon">
                                            <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
                                                <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8zm7.5-6.923c-.67.204-1.335.82-1.887 1.855A7.97 7.97 0 0 0 5.145 4H7.5V1.077zM4.09 4a9.267 9.267 0 0 1 .64-1.539 6.7 6.7 0 0 1 .597-.933A7.025 7.025 0 0 0 2.255 4H4.09zm-.582 3.5c.03-.877.138-1.718.312-2.5H1.674a6.958 6.958 0 0 0-.656 2.5h2.49zM4.847 5a12.5 12.5 0 0 0-.338 2.5H7.5V5H4.847zM8.5 5v2.5h2.99a12.495 12.495 0 0 0-.337-2.5H8.5zM4.51 8.5a12.5 12.5 0 0 0 .337 2.5H7.5V8.5H4.51zm3.99 0V11h2.653c.187-.765.306-1.608.338-2.5H8.5z"/>
                                            </svg>
                                        </div>
                                        <div>
                                            <span class="fw-medium">{% if peer.display_name %}{{ peer.display_name }}{% else %}{{ peer.site_id }}{% endif %}</span>
                                            {% if peer.display_name and peer.display_name != peer.site_id %}
                                            <br><small class="text-muted">{{ peer.site_id }}</small>
                                            {% endif %}
                                        </div>
                                    </div>
                                </td>
                                <td>
                                    <span class="endpoint-display text-muted small" data-full-url="{{ peer.endpoint }}" title="{{ peer.endpoint }}" style="cursor: pointer;">
                                        {% set parsed = peer.endpoint | split(pat="//") %}
                                        {% if parsed|length > 1 %}{% set host_parts = parsed[1] | split(pat="/") %}{{ host_parts[0] }}{% else %}{{ peer.endpoint }}{% endif %}
                                    </span>
                                    <button type="button" class="btn btn-link btn-sm p-0 ms-1 btn-copy-endpoint" data-url="{{ peer.endpoint }}" title="Copy full URL">
                                        <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" fill="currentColor" class="text-muted" viewBox="0 0 16 16">
                                            <path d="M4 1.5H3a2 2 0 0 0-2 2V14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3.5a2 2 0 0 0-2-2h-1v1h1a1 1 0 0 1 1 1V14a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V3.5a1 1 0 0 1 1-1h1v-1z"/>
                                            <path d="M9.5 1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5v-1a.5.5 0 0 1 .5-.5h3zm-3-1A1.5 1.5 0 0 0 5 1.5v1A1.5 1.5 0 0 0 6.5 4h3A1.5 1.5 0 0 0 11 2.5v-1A1.5 1.5 0 0 0 9.5 0h-3z"/>
                                        </svg>
                                    </button>
                                </td>
                                <td><span class="text-muted small">{{ peer.region }}</span></td>
                                <td><span class="text-muted small">{{ peer.priority }}</span></td>
                                <td class="sync-stats-cell" data-site-id="{{ peer.site_id }}">
                                    {% if item.has_connection %}
                                    <div class="d-flex align-items-center gap-2">
                                        <span class="badge bg-primary bg-opacity-10 text-primary">{{ item.buckets_syncing }} bucket{% if item.buckets_syncing != 1 %}s{% else %}{% endif %}</span>
                                        {% if item.has_bidirectional %}
                                        <span class="bidir-status-icon" data-site-id="{{ peer.site_id }}" title="Bidirectional sync - click to verify">
                                            <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" class="text-info" viewBox="0 0 16 16" style="cursor: pointer;">
                                                <path fill-rule="evenodd" d="M1 11.5a.5.5 0 0 0 .5.5h11.793l-3.147 3.146a.5.5 0 0 0 .708.708l4-4a.5.5 0 0 0 0-.708l-4-4a.5.5 0 0 0-.708.708L13.293 11H1.5a.5.5 0 0 0-.5.5zm14-7a.5.5 0 0 1-.5.5H2.707l3.147 3.146a.5.5 0 1 1-.708.708l-4-4a.5.5 0 0 1 0-.708l4-4a.5.5 0 1 1 .708.708L2.707 4H14.5a.5.5 0 0 1 .5.5z"/>
                                            </svg>
                                        </span>
                                        {% endif %}
                                        {% if item.errors and item.errors > 0 %}
                                        <span class="badge bg-danger bg-opacity-10 text-danger" title="Sync errors across bidirectional buckets">{{ item.errors }} err</span>
                                        {% endif %}
                                    </div>
                                    {% if item.last_sync_at %}
                                    <div class="text-muted small mt-1" data-last-sync-at="{{ item.last_sync_at }}">
                                        last sync: <span class="last-sync-rel">just now</span>
                                        {% if item.objects_pulled %} · {{ item.objects_pulled }} pulled{% endif %}
                                    </div>
                                    {% endif %}
                                    <div class="sync-stats-detail d-none mt-2 small" id="stats-{{ peer.site_id }}">
                                        <span class="spinner-border spinner-border-sm text-muted" style="width: 12px; height: 12px;"></span>
                                    </div>
                                    {% else %}
                                    <a href="#" class="text-muted small link-no-connection"
                                        data-site-id="{{ peer.site_id }}"
                                        title="Click to link a connection">Link a connection</a>
                                    {% endif %}
                                </td>
                                <td class="text-end">
                                    <div class="d-flex align-items-center justify-content-end gap-1">
                                        <button type="button" class="btn btn-outline-secondary btn-sm"
                                            data-bs-toggle="modal"
                                            data-bs-target="#editPeerModal"
                                            data-site-id="{{ peer.site_id }}"
                                            data-endpoint="{{ peer.endpoint }}"
                                            data-region="{{ peer.region }}"
                                            data-priority="{{ peer.priority }}"
                                            data-display-name="{{ peer.display_name }}"
                                            data-connection-id="{{ peer.connection_id | default(value="") }}"
                                            data-peer-inbound-access-key="{{ peer.peer_inbound_access_key | default(value="") }}"
                                            title="Edit peer">
                                            <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" viewBox="0 0 16 16">
                                                <path d="M12.146.146a.5.5 0 0 1 .708 0l3 3a.5.5 0 0 1 0 .708l-10 10a.5.5 0 0 1-.168.11l-5 2a.5.5 0 0 1-.65-.65l2-5a.5.5 0 0 1 .11-.168l10-10zM11.207 2.5 13.5 4.793 14.793 3.5 12.5 1.207 11.207 2.5zm1.586 3L10.5 3.207 4 9.707V10h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.293l6.5-6.5z"/>
                                            </svg>
                                        </button>
                                        <div class="dropdown peer-actions-dropdown">
                                            <button class="btn btn-outline-secondary btn-sm" type="button" data-bs-toggle="dropdown" aria-expanded="false" title="More actions">
                                                <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" viewBox="0 0 16 16">
                                                    <path d="M3 9.5a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3zm5 0a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3zm5 0a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3z"/>
                                                </svg>
                                            </button>
                                            <ul class="dropdown-menu dropdown-menu-end">
                                                <li>
                                                    <button type="button" class="dropdown-item btn-check-health" data-site-id="{{ peer.site_id }}">
                                                        <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" class="me-2 text-warning" viewBox="0 0 16 16">
                                                            <path d="M11.251.068a.5.5 0 0 1 .227.58L9.677 6.5H13a.5.5 0 0 1 .364.843l-8 8.5a.5.5 0 0 1-.842-.49L6.323 9.5H3a.5.5 0 0 1-.364-.843l8-8.5a.5.5 0 0 1 .615-.09z"/>
                                                        </svg>
                                                        Check Health
                                                    </button>
                                                </li>
                                                <li>
                                                    <button type="button" class="dropdown-item btn-check-bidir {% if not item.has_connection %}disabled{% endif %}"
                                                        data-site-id="{{ peer.site_id }}"
                                                        data-display-name="{% if peer.display_name %}{{ peer.display_name }}{% else %}{{ peer.site_id }}{% endif %}">
                                                        <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" class="me-2 text-info" viewBox="0 0 16 16">
                                                            <path fill-rule="evenodd" d="M1 11.5a.5.5 0 0 0 .5.5h11.793l-3.147 3.146a.5.5 0 0 0 .708.708l4-4a.5.5 0 0 0 0-.708l-4-4a.5.5 0 0 0-.708.708L13.293 11H1.5a.5.5 0 0 0-.5.5zm14-7a.5.5 0 0 1-.5.5H2.707l3.147 3.146a.5.5 0 1 1-.708.708l-4-4a.5.5 0 0 1 0-.708l4-4a.5.5 0 1 1 .708.708L2.707 4H14.5a.5.5 0 0 1 .5.5z"/>
                                                        </svg>
                                                        Bidirectional Status
                                                    </button>
                                                </li>
                                                {% if item.has_connection and item.buckets_syncing > 0 %}
                                                <li>
                                                    <button type="button" class="dropdown-item btn-load-stats" data-site-id="{{ peer.site_id }}">
                                                        <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" class="me-2 text-primary" viewBox="0 0 16 16">
                                                            <path fill-rule="evenodd" d="M8 3a5 5 0 1 0 4.546 2.914.5.5 0 0 1 .908-.417A6 6 0 1 1 8 2v1z"/>
                                                            <path d="M8 4.466V.534a.25.25 0 0 1 .41-.192l2.36 1.966c.12.1.12.284 0 .384L8.41 4.658A.25.25 0 0 1 8 4.466z"/>
                                                        </svg>
                                                        Load Sync Stats
                                                    </button>
                                                </li>
                                                {% endif %}
                                                <li>
                                                    <a href="{{ url_for(endpoint="ui.replication_wizard", site_id=peer.site_id) }}"
                                                        class="dropdown-item {% if not item.has_connection %}disabled{% endif %}">
                                                        <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" class="me-2 text-primary" viewBox="0 0 16 16">
                                                            <path d="M11.534 7h3.932a.25.25 0 0 1 .192.41l-1.966 2.36a.25.25 0 0 1-.384 0l-1.966-2.36a.25.25 0 0 1 .192-.41zm-11 2h3.932a.25.25 0 0 0 .192-.41L2.692 6.23a.25.25 0 0 0-.384 0L.342 8.59A.25.25 0 0 0 .534 9z"/>
                                                            <path fill-rule="evenodd" d="M8 3c-1.552 0-2.94.707-3.857 1.818a.5.5 0 1 1-.771-.636A6.002 6.002 0 0 1 13.917 7H12.9A5.002 5.002 0 0 0 8 3zM3.1 9a5.002 5.002 0 0 0 8.757 2.182.5.5 0 1 1 .771.636A6.002 6.002 0 0 1 2.083 9H3.1z"/>
                                                        </svg>
                                                        Replication Wizard
                                                    </a>
                                                </li>
                                                <li><hr class="dropdown-divider"></li>
                                                <li>
                                                    <button type="button" class="dropdown-item text-danger"
                                                        data-bs-toggle="modal"
                                                        data-bs-target="#deletePeerModal"
                                                        data-site-id="{{ peer.site_id }}"
                                                        data-display-name="{% if peer.display_name %}{{ peer.display_name }}{% else %}{{ peer.site_id }}{% endif %}">
                                                        <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" class="me-2" viewBox="0 0 16 16">
                                                            <path d="M5.5 5.5A.5.5 0 0 1 6 6v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm2.5 0a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm3 .5a.5.5 0 0 0-1 0v6a.5.5 0 0 0 1 0V6z"/>
                                                            <path fill-rule="evenodd" d="M14.5 3a1 1 0 0 1-1 1H13v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V4h-.5a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1H6a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1h3.5a1 1 0 0 1 1 1v1zM4.118 4 4 4.059V13a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V4.059L11.882 4H4.118zM2.5 3V2h11v1h-11z"/>
                                                        </svg>
                                                        Delete Peer
                                                    </button>
                                                </li>
                                            </ul>
                                        </div>
                                    </div>
                                </td>
                            </tr>
                            {% endfor %}
                        </tbody>
                    </table>
                </div>
                {% else %}
                <div class="empty-state text-center py-5">
                    <div class="empty-state-icon mx-auto mb-3">
                        <svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" fill="currentColor" viewBox="0 0 16 16">
                            <path d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8zm7.5-6.923c-.67.204-1.335.82-1.887 1.855A7.97 7.97 0 0 0 5.145 4H7.5V1.077zM4.09 4a9.267 9.267 0 0 1 .64-1.539 6.7 6.7 0 0 1 .597-.933A7.025 7.025 0 0 0 2.255 4H4.09zm-.582 3.5c.03-.877.138-1.718.312-2.5H1.674a6.958 6.958 0 0 0-.656 2.5h2.49zM4.847 5a12.5 12.5 0 0 0-.338 2.5H7.5V5H4.847zM8.5 5v2.5h2.99a12.495 12.495 0 0 0-.337-2.5H8.5zM4.51 8.5a12.5 12.5 0 0 0 .337 2.5H7.5V8.5H4.51zm3.99 0V11h2.653c.187-.765.306-1.608.338-2.5H8.5zM5.145 12c.138.386.295.744.468 1.068.552 1.035 1.218 1.65 1.887 1.855V12H5.145zm.182 2.472a6.696 6.696 0 0 1-.597-.933A9.268 9.268 0 0 1 4.09 12H2.255a7.024 7.024 0 0 0 3.072 2.472z"/>
                        </svg>
                    </div>
                    <h5 class="fw-semibold mb-2">No peer sites yet</h5>
                    <p class="text-muted mb-0">Add peer sites to enable geo-distribution and site-to-site replication.</p>
                </div>
                {% endif %}
            </div>
        </div>
    </div>
</div>

<div class="modal fade" id="editPeerModal" tabindex="-1" aria-hidden="true">
    <div class="modal-dialog modal-dialog-centered">
        <div class="modal-content">
            <div class="modal-header border-0 pb-0">
                <h5 class="modal-title fw-semibold">
                    <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="text-primary" viewBox="0 0 16 16">
                        <path d="M12.146.146a.5.5 0 0 1 .708 0l3 3a.5.5 0 0 1 0 .708l-10 10a.5.5 0 0 1-.168.11l-5 2a.5.5 0 0 1-.65-.65l2-5a.5.5 0 0 1 .11-.168l10-10zM11.207 2.5 13.5 4.793 14.793 3.5 12.5 1.207 11.207 2.5zm1.586 3L10.5 3.207 4 9.707V10h.5a.5.5 0 0 1 .5.5v.5h.5a.5.5 0 0 1 .5.5v.5h.293l6.5-6.5zm-9.761 5.175-.106.106-1.528 3.821 3.821-1.528.106-.106A.5.5 0 0 1 5 12.5V12h-.5a.5.5 0 0 1-.5-.5V11h-.5a.5.5 0 0 1-.468-.325z"/>
                    </svg>
                    Edit Peer Site
                </h5>
                <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
            </div>
            <form method="POST" id="editPeerForm">
                <input type="hidden" name="csrf_token" value="{{ csrf_token_value }}"/>
                <div class="modal-body">
                    <div class="mb-3">
                        <label class="form-label fw-medium">Site ID</label>
                        <input type="text" class="form-control" id="edit_site_id" name="site_id" readonly>
                    </div>
                    <div class="mb-3">
                        <label for="edit_endpoint" class="form-label fw-medium">Endpoint URL</label>
                        <input type="url" class="form-control" id="edit_endpoint" name="endpoint" required>
                    </div>
                    <div class="mb-3">
                        <label for="edit_region" class="form-label fw-medium">Region</label>
                        <input type="text" class="form-control" id="edit_region" name="region" required>
                    </div>
                    <div class="row mb-3">
                        <div class="col-6">
                            <label for="edit_priority" class="form-label fw-medium">Priority</label>
                            <input type="number" class="form-control" id="edit_priority" name="priority" min="0">
                        </div>
                        <div class="col-6">
                            <label for="edit_display_name" class="form-label fw-medium">Display Name</label>
                            <input type="text" class="form-control" id="edit_display_name" name="display_name">
                        </div>
                    </div>
                    <div class="mb-3">
                        <label for="edit_connection_id" class="form-label fw-medium">Connection</label>
                        <select class="form-select" id="edit_connection_id" name="connection_id">
                            <option value="">No connection</option>
                            {% for conn in connections %}
                            <option value="{{ conn.id }}">{{ conn.name }} ({{ conn.endpoint_url }})</option>
                            {% endfor %}
                        </select>
                    </div>
                    <div class="mb-3">
                        <label for="edit_peer_inbound_access_key" class="form-label fw-medium">Peer Inbound Access Key</label>
                        <input type="text" class="form-control" id="edit_peer_inbound_access_key" name="peer_inbound_access_key" placeholder="AKIA... (optional)" autocomplete="off" spellcheck="false">
                        <div class="form-text">Access key the peer presents when calling this site (e.g. /admin/cluster/overview). Leave blank to require admin credentials.</div>
                    </div>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Cancel</button>
                    <button type="submit" class="btn btn-primary">
                        <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" class="me-1" viewBox="0 0 16 16">
                            <path d="M10.97 4.97a.75.75 0 0 1 1.07 1.05l-3.99 4.99a.75.75 0 0 1-1.08.02L4.324 8.384a.75.75 0 1 1 1.06-1.06l2.094 2.093 3.473-4.425a.267.267 0 0 1 .02-.022z"/>
                        </svg>
                        Save
                    </button>
                </div>
            </form>
        </div>
    </div>
</div>

<div class="modal fade" id="deletePeerModal" tabindex="-1" aria-hidden="true">
    <div class="modal-dialog modal-dialog-centered">
        <div class="modal-content">
            <div class="modal-header border-0 pb-0">
                <h5 class="modal-title fw-semibold">
                    <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="text-danger" viewBox="0 0 16 16">
                        <path d="M5.5 5.5A.5.5 0 0 1 6 6v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm2.5 0a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm3 .5a.5.5 0 0 0-1 0v6a.5.5 0 0 0 1 0V6z"/>
                        <path fill-rule="evenodd" d="M14.5 3a1 1 0 0 1-1 1H13v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V4h-.5a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1H6a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1h3.5a1 1 0 0 1 1 1v1zM4.118 4 4 4.059V13a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V4.059L11.882 4H4.118zM2.5 3V2h11v1h-11z"/>
                    </svg>
                    Delete Peer Site
                </h5>
                <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
            </div>
            <div class="modal-body">
                <p>Are you sure you want to delete <strong id="deletePeerName"></strong>?</p>
                <div class="alert alert-warning d-flex align-items-start small" role="alert">
                    <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="flex-shrink-0 me-2 mt-0" viewBox="0 0 16 16">
                        <path d="M8 16A8 8 0 1 0 8 0a8 8 0 0 0 0 16zm.93-9.412-1 4.705c-.07.34.029.533.304.533.194 0 .487-.07.686-.246l-.088.416c-.287.346-.92.598-1.465.598-.703 0-1.002-.422-.808-1.319l.738-3.468c.064-.293.006-.399-.287-.47l-.451-.081.082-.381 2.29-.287zM8 5.5a1 1 0 1 1 0-2 1 1 0 0 1 0 2z"/>
                    </svg>
                    <div>This will remove the peer from the site registry. Any site sync configurations may be affected.</div>
                </div>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Cancel</button>
                <form method="POST" id="deletePeerForm">
                    <input type="hidden" name="csrf_token" value="{{ csrf_token_value }}"/>
                    <button type="submit" class="btn btn-danger">
                        <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" class="me-1" viewBox="0 0 16 16">
                            <path d="M5.5 5.5A.5.5 0 0 1 6 6v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm2.5 0a.5.5 0 0 1 .5.5v6a.5.5 0 0 1-1 0V6a.5.5 0 0 1 .5-.5zm3 .5a.5.5 0 0 0-1 0v6a.5.5 0 0 0 1 0V6z"/>
                            <path fill-rule="evenodd" d="M14.5 3a1 1 0 0 1-1 1H13v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V4h-.5a1 1 0 0 1-1-1V2a1 1 0 0 1 1-1H6a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1h3.5a1 1 0 0 1 1 1v1zM4.118 4 4 4.059V13a1 1 0 0 0 1 1h6a1 1 0 0 0 1-1V4.059L11.882 4H4.118zM2.5 3V2h11v1h-11z"/>
                        </svg>
                        Delete
                    </button>
                </form>
            </div>
        </div>
    </div>
</div>

<div class="modal fade" id="bidirStatusModal" tabindex="-1" aria-hidden="true">
    <div class="modal-dialog modal-dialog-centered modal-lg">
        <div class="modal-content">
            <div class="modal-header border-0 pb-0">
                <h5 class="modal-title fw-semibold">
                    <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="text-info me-2" viewBox="0 0 16 16">
                        <path fill-rule="evenodd" d="M1 11.5a.5.5 0 0 0 .5.5h11.793l-3.147 3.146a.5.5 0 0 0 .708.708l4-4a.5.5 0 0 0 0-.708l-4-4a.5.5 0 0 0-.708.708L13.293 11H1.5a.5.5 0 0 0-.5.5zm14-7a.5.5 0 0 1-.5.5H2.707l3.147 3.146a.5.5 0 1 1-.708.708l-4-4a.5.5 0 0 1 0-.708l4-4a.5.5 0 1 1 .708.708L2.707 4H14.5a.5.5 0 0 1 .5.5z"/>
                    </svg>
                    Bidirectional Sync Status
                </h5>
                <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
            </div>
            <div class="modal-body">
                <div id="bidirStatusContent">
                    <div class="text-center py-4">
                        <span class="spinner-border text-primary" role="status"></span>
                        <p class="text-muted mt-2 mb-0">Checking configuration...</p>
                    </div>
                </div>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Close</button>
                <a href="#" id="bidirWizardLink" class="btn btn-primary d-none">
                    <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" fill="currentColor" class="me-1" viewBox="0 0 16 16">
                        <path d="M9.828.722a.5.5 0 0 1 .354.146l4.95 4.95a.5.5 0 0 1 0 .707c-.48.48-1.072.588-1.503.588-.177 0-.335-.018-.46-.039l-3.134 3.134a5.927 5.927 0 0 1 .16 1.013c.046.702-.032 1.687-.72 2.375a.5.5 0 0 1-.707 0l-2.829-2.828-3.182 3.182c-.195.195-1.219.902-1.414.707-.195-.195.512-1.22.707-1.414l3.182-3.182-2.828-2.829a.5.5 0 0 1 0-.707c.688-.688 1.673-.767 2.375-.72a5.922 5.922 0 0 1 1.013.16l3.134-3.133a2.772 2.772 0 0 1-.04-.461c0-.43.108-1.022.589-1.503a.5.5 0 0 1 .353-.146z"/>
                    </svg>
                    Run Setup Wizard
                </a>
            </div>
        </div>
    </div>
</div>

<script>
(function() {
    var escapeHtml = window.UICore ? window.UICore.escapeHtml : function(s) { return s; };

    var editPeerModal = document.getElementById('editPeerModal');
    if (editPeerModal) {
        editPeerModal.addEventListener('show.bs.modal', function (event) {
            var button = event.relatedTarget;
            var siteId = button.getAttribute('data-site-id');
            document.getElementById('edit_site_id').value = siteId;
            document.getElementById('edit_endpoint').value = button.getAttribute('data-endpoint');
            document.getElementById('edit_region').value = button.getAttribute('data-region');
            document.getElementById('edit_priority').value = button.getAttribute('data-priority');
            document.getElementById('edit_display_name').value = button.getAttribute('data-display-name');
            document.getElementById('edit_connection_id').value = button.getAttribute('data-connection-id');
            document.getElementById('edit_peer_inbound_access_key').value = button.getAttribute('data-peer-inbound-access-key') || '';
            document.getElementById('editPeerForm').action = '/ui/sites/peers/' + encodeURIComponent(siteId) + '/update';
        });
    }

    document.querySelectorAll('.link-no-connection').forEach(function(link) {
        link.addEventListener('click', function(e) {
            e.preventDefault();
            var siteId = this.getAttribute('data-site-id');
            var row = this.closest('tr[data-site-id]');
            if (row) {
                var btn = row.querySelector('.btn[data-bs-target="#editPeerModal"]');
                if (btn) btn.click();
            }
        });
    });

    var deletePeerModal = document.getElementById('deletePeerModal');
    if (deletePeerModal) {
        deletePeerModal.addEventListener('show.bs.modal', function (event) {
            var button = event.relatedTarget;
            var siteId = button.getAttribute('data-site-id');
            var displayName = button.getAttribute('data-display-name');
            document.getElementById('deletePeerName').textContent = displayName;
            document.getElementById('deletePeerForm').action = '/ui/sites/peers/' + encodeURIComponent(siteId) + '/delete';
        });
    }

    function formatTimeAgo(date) {
        var seconds = Math.floor((new Date() - date) / 1000);
        if (seconds < 60) return 'just now';
        var minutes = Math.floor(seconds / 60);
        if (minutes < 60) return minutes + 'm ago';
        var hours = Math.floor(minutes / 60);
        if (hours < 24) return hours + 'h ago';
        return Math.floor(hours / 24) + 'd ago';
    }

    function doHealthCheck(siteId) {
        var row = document.querySelector('tr[data-site-id="' + CSS.escape(siteId) + '"]');
        var statusSpan = row ? row.querySelector('.peer-health-status') : null;
        if (!statusSpan) return Promise.resolve();

        statusSpan.innerHTML = '<span class="spinner-border spinner-border-sm text-muted" role="status" style="width: 14px; height: 14px;"></span>';

        return fetch('/ui/sites/peers/' + encodeURIComponent(siteId) + '/health')
            .then(function(response) { return response.json(); })
            .then(function(data) {
                var now = new Date();
                statusSpan.setAttribute('data-last-checked', now.toISOString());
                if (data.is_healthy) {
                    statusSpan.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="text-success" viewBox="0 0 16 16"><path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zm-3.97-3.03a.75.75 0 0 0-1.08.022L7.477 9.417 5.384 7.323a.75.75 0 0 0-1.06 1.06L6.97 11.03a.75.75 0 0 0 1.079-.02l3.992-4.99a.75.75 0 0 0-.01-1.05z"/></svg>';
                    statusSpan.title = 'Healthy (checked ' + formatTimeAgo(now) + ')';
                    return { siteId: siteId, healthy: true };
                } else {
                    statusSpan.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="text-danger" viewBox="0 0 16 16"><path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zM5.354 4.646a.5.5 0 1 0-.708.708L7.293 8l-2.647 2.646a.5.5 0 0 0 .708.708L8 8.707l2.646 2.647a.5.5 0 0 0 .708-.708L8.707 8l2.647-2.646a.5.5 0 0 0-.708-.708L8 7.293 5.354 4.646z"/></svg>';
                    statusSpan.title = 'Unhealthy' + (data.error ? ': ' + data.error : '') + ' (checked ' + formatTimeAgo(now) + ')';
                    return { siteId: siteId, healthy: false, error: data.error };
                }
            })
            .catch(function(err) {
                statusSpan.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="text-muted" viewBox="0 0 16 16"><path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"/><path d="M5.255 5.786a.237.237 0 0 0 .241.247h.825c.138 0 .248-.113.266-.25.09-.656.54-1.134 1.342-1.134.686 0 1.314.343 1.314 1.168 0 .635-.374.927-.965 1.371-.673.489-1.206 1.06-1.168 1.987l.003.217a.25.25 0 0 0 .25.246h.811a.25.25 0 0 0 .25-.25v-.105c0-.718.273-.927 1.01-1.486.609-.463 1.244-.977 1.244-2.056 0-1.511-1.276-2.241-2.673-2.241-1.267 0-2.655.59-2.75 2.286zm1.557 5.763c0 .533.425.927 1.01.927.609 0 1.028-.394 1.028-.927 0-.552-.42-.94-1.029-.94-.584 0-1.009.388-1.009.94z"/></svg>';
                statusSpan.title = 'Check failed';
                return { siteId: siteId, healthy: null };
            });
    }

    document.querySelectorAll('.btn-check-health').forEach(function(btn) {
        btn.addEventListener('click', function() {
            var siteId = this.getAttribute('data-site-id');
            doHealthCheck(siteId).then(function(result) {
                if (!result) return;
                if (result.healthy === true) {
                    if (window.showToast) window.showToast('Peer site is healthy', 'Health Check', 'success');
                } else if (result.healthy === false) {
                    if (window.showToast) window.showToast(result.error || 'Peer site is unhealthy', 'Health Check', 'error');
                } else {
                    if (window.showToast) window.showToast('Failed to check health', 'Health Check', 'error');
                }
            });
        });
    });

    var checkAllBtn = document.getElementById('btnCheckAllHealth');
    if (checkAllBtn) {
        checkAllBtn.addEventListener('click', function() {
            var btn = this;
            var originalHtml = btn.innerHTML;
            btn.disabled = true;
            btn.innerHTML = '<span class="spinner-border spinner-border-sm me-1"></span>Checking...';

            var siteIds = [];
            document.querySelectorAll('.peer-health-status').forEach(function(el) {
                siteIds.push(el.getAttribute('data-site-id'));
            });

            var promises = siteIds.map(function(id) { return doHealthCheck(id); });
            Promise.all(promises).then(function(results) {
                var healthy = results.filter(function(r) { return r && r.healthy === true; }).length;
                var unhealthy = results.filter(function(r) { return r && r.healthy === false; }).length;
                var failed = results.filter(function(r) { return r && r.healthy === null; }).length;

                var msg = healthy + ' healthy';
                if (unhealthy > 0) msg += ', ' + unhealthy + ' unhealthy';
                if (failed > 0) msg += ', ' + failed + ' failed';
                if (window.showToast) window.showToast(msg, 'Health Check', unhealthy > 0 ? 'warning' : 'success');

                btn.disabled = false;
                btn.innerHTML = originalHtml;
            });
        });
    }

    document.querySelectorAll('.btn-load-stats').forEach(function(btn) {
        btn.addEventListener('click', function() {
            var siteId = this.getAttribute('data-site-id');
            var detailDiv = document.getElementById('stats-' + siteId);
            if (!detailDiv) return;

            detailDiv.classList.remove('d-none');
            detailDiv.innerHTML = '<span class="spinner-border spinner-border-sm text-muted" style="width: 12px; height: 12px;"></span> Loading...';

            fetch('/ui/sites/peers/' + encodeURIComponent(siteId) + '/sync-stats')
                .then(function(response) { return response.json(); })
                .then(function(data) {
                    if (data.error) {
                        detailDiv.innerHTML = '<span class="text-danger">' + escapeHtml(data.error) + '</span>';
                    } else {
                        var lastSync = data.last_sync_at
                            ? new Date(data.last_sync_at * 1000).toLocaleString()
                            : 'Never';
                        detailDiv.innerHTML =
                            '<div class="d-flex flex-wrap gap-2 mb-1">' +
                                '<span class="text-success"><strong>' + escapeHtml(String(data.objects_synced)) + '</strong> synced</span>' +
                                '<span class="text-warning"><strong>' + escapeHtml(String(data.objects_pending)) + '</strong> pending</span>' +
                                '<span class="text-danger"><strong>' + escapeHtml(String(data.objects_failed)) + '</strong> failed</span>' +
                            '</div>' +
                            '<div class="text-muted" style="font-size: 0.75rem;">Last sync: ' + escapeHtml(lastSync) + '</div>';
                    }
                })
                .catch(function() {
                    detailDiv.innerHTML = '<span class="text-danger">Failed to load stats</span>';
                });
        });
    });

    document.querySelectorAll('.bidir-status-icon').forEach(function(icon) {
        icon.addEventListener('click', function() {
            var siteId = this.getAttribute('data-site-id');
            var row = this.closest('tr[data-site-id]');
            var btn = row ? row.querySelector('.btn-check-bidir') : null;
            if (btn) btn.click();
        });
    });

    document.querySelectorAll('.btn-check-bidir').forEach(function(btn) {
        btn.addEventListener('click', function() {
            var siteId = this.getAttribute('data-site-id');
            var displayName = this.getAttribute('data-display-name');
            var modal = new bootstrap.Modal(document.getElementById('bidirStatusModal'));
            var contentDiv = document.getElementById('bidirStatusContent');
            var wizardLink = document.getElementById('bidirWizardLink');

            contentDiv.innerHTML =
                '<div class="text-center py-4">' +
                    '<span class="spinner-border text-primary" role="status"></span>' +
                    '<p class="text-muted mt-2 mb-0">Checking bidirectional configuration with ' + escapeHtml(displayName) + '...</p>' +
                '</div>';
            wizardLink.classList.add('d-none');
            modal.show();

            fetch('/ui/sites/peers/' + encodeURIComponent(siteId) + '/bidirectional-status')
                .then(function(response) { return response.json(); })
                .then(function(data) {
                    var html = '';

                    if (data.is_fully_configured) {
                        html += '<div class="alert alert-success d-flex align-items-center mb-4" role="alert">' +
                            '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="currentColor" class="flex-shrink-0 me-2" viewBox="0 0 16 16">' +
                                '<path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zm-3.97-3.03a.75.75 0 0 0-1.08.022L7.477 9.417 5.384 7.323a.75.75 0 0 0-1.06 1.06L6.97 11.03a.75.75 0 0 0 1.079-.02l3.992-4.99a.75.75 0 0 0-.01-1.05z"/>' +
                            '</svg>' +
                            '<div><strong>Bidirectional sync is fully configured!</strong><br><small>Both sites are set up to sync data in both directions.</small></div>' +
                        '</div>';
                    } else if (data.issues && data.issues.length > 0) {
                        var errors = data.issues.filter(function(i) { return i.severity === 'error'; });
                        var warnings = data.issues.filter(function(i) { return i.severity === 'warning'; });

                        if (errors.length > 0) {
                            html += '<div class="alert alert-danger mb-3" role="alert">' +
                                '<h6 class="alert-heading fw-bold mb-2">' +
                                    '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="me-1" viewBox="0 0 16 16"><path d="M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zM5.354 4.646a.5.5 0 1 0-.708.708L7.293 8l-2.647 2.646a.5.5 0 0 0 .708.708L8 8.707l2.646 2.647a.5.5 0 0 0 .708-.708L8.707 8l2.647-2.646a.5.5 0 0 0-.708-.708L8 7.293 5.354 4.646z"/></svg>' +
                                    ' Configuration Errors</h6><ul class="mb-0 ps-3">';
                            errors.forEach(function(issue) {
                                html += '<li><strong>' + escapeHtml(issue.code) + ':</strong> ' + escapeHtml(issue.message) + '</li>';
                            });
                            html += '</ul></div>';
                        }

                        if (warnings.length > 0) {
                            html += '<div class="alert alert-warning mb-3" role="alert">' +
                                '<h6 class="alert-heading fw-bold mb-2">' +
                                    '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="me-1" viewBox="0 0 16 16"><path d="M8.982 1.566a1.13 1.13 0 0 0-1.96 0L.165 13.233c-.457.778.091 1.767.98 1.767h13.713c.889 0 1.438-.99.98-1.767L8.982 1.566zM8 5c.535 0 .954.462.9.995l-.35 3.507a.552.552 0 0 1-1.1 0L7.1 5.995A.905.905 0 0 1 8 5zm.002 6a1 1 0 1 1 0 2 1 1 0 0 1 0-2z"/></svg>' +
                                    ' Warnings</h6><ul class="mb-0 ps-3">';
                            warnings.forEach(function(issue) {
                                html += '<li><strong>' + escapeHtml(issue.code) + ':</strong> ' + escapeHtml(issue.message) + '</li>';
                            });
                            html += '</ul></div>';
                        }
                    }

                    html += '<div class="row g-3">';
                    html += '<div class="col-md-6"><div class="card h-100"><div class="card-header bg-light py-2"><strong>This Site (Local)</strong></div>' +
                        '<div class="card-body small">' +
                            '<p class="mb-1"><strong>Site ID:</strong> ' + (data.local_site_id ? escapeHtml(data.local_site_id) : '<span class="text-danger">Not configured</span>') + '</p>' +
                            '<p class="mb-1"><strong>Endpoint:</strong> ' + (data.local_endpoint ? escapeHtml(data.local_endpoint) : '<span class="text-danger">Not configured</span>') + '</p>' +
                            '<p class="mb-1"><strong>Site Sync Worker:</strong> ' + (data.local_site_sync_enabled ? '<span class="text-success">Enabled</span>' : '<span class="text-warning">Disabled</span>') + '</p>' +
                            '<p class="mb-0"><strong>Bidirectional Rules:</strong> ' + (data.local_bidirectional_rules ? data.local_bidirectional_rules.length : 0) + '</p>' +
                        '</div></div></div>';

                    if (data.remote_status) {
                        var rs = data.remote_status;
                        html += '<div class="col-md-6"><div class="card h-100"><div class="card-header bg-light py-2"><strong>Remote Site (' + escapeHtml(displayName) + ')</strong></div>' +
                            '<div class="card-body small">';
                        if (rs.admin_access_denied) {
                            html += '<p class="text-warning mb-0">Admin access denied - cannot verify remote configuration</p>';
                        } else if (rs.reachable === false) {
                            html += '<p class="text-danger mb-0">Could not reach remote admin API</p>';
                        } else {
                            html += '<p class="mb-1"><strong>Has Peer Entry for Us:</strong> ' + (rs.has_peer_for_us ? '<span class="text-success">Yes</span>' : '<span class="text-danger">No</span>') + '</p>' +
                                '<p class="mb-1"><strong>Connection Configured:</strong> ' + (rs.peer_connection_configured ? '<span class="text-success">Yes</span>' : '<span class="text-danger">No</span>') + '</p>';
                        }
                        html += '</div></div></div>';
                    } else {
                        html += '<div class="col-md-6"><div class="card h-100"><div class="card-header bg-light py-2"><strong>Remote Site (' + escapeHtml(displayName) + ')</strong></div>' +
                            '<div class="card-body small"><p class="text-muted mb-0">Could not check remote status</p></div></div></div>';
                    }
                    html += '</div>';

                    if (data.local_bidirectional_rules && data.local_bidirectional_rules.length > 0) {
                        html += '<div class="mt-3"><h6 class="fw-semibold">Local Bidirectional Rules</h6>' +
                            '<table class="table table-sm table-bordered mb-0"><thead class="table-light"><tr><th>Source Bucket</th><th>Target Bucket</th><th>Status</th></tr></thead><tbody>';
                        data.local_bidirectional_rules.forEach(function(rule) {
                            html += '<tr><td>' + escapeHtml(rule.bucket_name) + '</td><td>' + escapeHtml(rule.target_bucket) + '</td>' +
                                '<td>' + (rule.enabled ? '<span class="badge bg-success">Enabled</span>' : '<span class="badge bg-secondary">Disabled</span>') + '</td></tr>';
                        });
                        html += '</tbody></table></div>';
                    }

                    if (!data.is_fully_configured) {
                        html += '<div class="alert alert-info mt-3 mb-0" role="alert">' +
                            '<h6 class="alert-heading fw-bold">How to Fix</h6>' +
                            '<ol class="mb-0 ps-3">' +
                                '<li>Ensure this site has a Site ID and Endpoint URL configured</li>' +
                                '<li>On the remote site, register this site as a peer with a connection</li>' +
                                '<li>Create bidirectional replication rules on both sites</li>' +
                                '<li>Enable SITE_SYNC_ENABLED=true on both sites</li>' +
                            '</ol></div>';
                        var blockingErrors = ['NO_CONNECTION', 'CONNECTION_NOT_FOUND', 'REMOTE_UNREACHABLE', 'ENDPOINT_NOT_ALLOWED'];
                        var hasBlockingError = data.issues && data.issues.some(function(i) { return blockingErrors.indexOf(i.code) !== -1; });
                        if (!hasBlockingError) {
                            wizardLink.href = '/ui/replication/new?site_id=' + encodeURIComponent(siteId);
                            wizardLink.classList.remove('d-none');
                        }
                    }

                    contentDiv.innerHTML = html;
                })
                .catch(function(err) {
                    contentDiv.innerHTML = '<div class="alert alert-danger" role="alert"><strong>Error:</strong> Failed to check bidirectional status. ' + escapeHtml(err.message || '') + '</div>';
                });
        });
    });

    document.querySelectorAll('.btn-copy-endpoint').forEach(function(btn) {
        btn.addEventListener('click', function(e) {
            e.stopPropagation();
            var url = this.getAttribute('data-url');
            if (window.UICore && window.UICore.copyToClipboard) {
                window.UICore.copyToClipboard(url).then(function(ok) {
                    if (ok && window.showToast) window.showToast('Endpoint URL copied', 'Copied', 'success');
                });
            }
        });
    });

    var localSiteForm = document.getElementById('localSiteForm');
    if (localSiteForm) {
        localSiteForm.addEventListener('submit', function(e) {
            e.preventDefault();
            window.UICore.submitFormAjax(this, {
                successMessage: 'Local site configuration updated',
                onSuccess: function() {
                    setTimeout(function() { location.reload(); }, 800);
                }
            });
        });
    }

    var addPeerForm = document.getElementById('addPeerForm');
    if (addPeerForm) {
        addPeerForm.addEventListener('submit', function(e) {
            e.preventDefault();
            window.UICore.submitFormAjax(this, {
                successMessage: 'Peer site added',
                onSuccess: function(data) {
                    if (data.redirect) {
                        setTimeout(function() { window.location.href = data.redirect; }, 800);
                    } else {
                        setTimeout(function() { location.reload(); }, 800);
                    }
                }
            });
        });
    }

    var editPeerForm = document.getElementById('editPeerForm');
    if (editPeerForm) {
        editPeerForm.addEventListener('submit', function(e) {
            e.preventDefault();
            var modal = bootstrap.Modal.getInstance(document.getElementById('editPeerModal'));
            window.UICore.submitFormAjax(this, {
                successMessage: 'Peer site updated',
                onSuccess: function() {
                    if (modal) modal.hide();
                    setTimeout(function() { location.reload(); }, 800);
                }
            });
        });
    }

    var deletePeerForm = document.getElementById('deletePeerForm');
    if (deletePeerForm) {
        deletePeerForm.addEventListener('submit', function(e) {
            e.preventDefault();
            var modal = bootstrap.Modal.getInstance(document.getElementById('deletePeerModal'));
            window.UICore.submitFormAjax(this, {
                successMessage: 'Peer site deleted',
                onSuccess: function() {
                    if (modal) modal.hide();
                    setTimeout(function() { location.reload(); }, 800);
                }
            });
        });
    }
    document.querySelectorAll('.peer-actions-dropdown').forEach(function(dd, idx) {
        var menu = dd.querySelector('.dropdown-menu');
        if (!menu) return;
        var pairId = 'peer-dd-' + idx;
        dd.dataset.peerDdPair = pairId;
        menu.dataset.peerDdPair = pairId;
        function reposition() {
            var toggle = dd.querySelector('[data-bs-toggle="dropdown"]');
            if (!toggle) return;
            var rect = toggle.getBoundingClientRect();
            var menuWidth = menu.offsetWidth;
            var menuHeight = menu.offsetHeight;
            var pad = 8;
            var left = rect.right - menuWidth;
            if (left + menuWidth > window.innerWidth - pad) left = window.innerWidth - pad - menuWidth;
            if (left < pad) left = pad;
            var top = rect.bottom;
            if (top + menuHeight > window.innerHeight - pad) {
                top = Math.max(pad, rect.top - menuHeight);
            }
            menu.style.position = 'fixed';
            menu.style.top = top + 'px';
            menu.style.left = left + 'px';
            menu.style.right = 'auto';
            menu.style.bottom = 'auto';
            menu.style.transform = 'none';
        }
        dd.addEventListener('show.bs.dropdown', function() {
            if (menu.parentNode !== document.body) document.body.appendChild(menu);
        });
        dd.addEventListener('shown.bs.dropdown', reposition);
        dd.addEventListener('hidden.bs.dropdown', function() {
            menu.style.cssText = '';
            if (menu.parentNode !== dd) dd.appendChild(menu);
        });
        window.addEventListener('resize', function() { if (menu.classList.contains('show')) reposition(); });
        window.addEventListener('scroll', function() { if (menu.classList.contains('show')) reposition(); }, true);
    });
})();

(function () {
    function fmtRel(ts) {
        var diff = Math.max(0, Math.floor(Date.now() / 1000 - ts));
        if (diff < 60) return diff + "s ago";
        if (diff < 3600) return Math.floor(diff / 60) + "m ago";
        if (diff < 86400) return Math.floor(diff / 3600) + "h ago";
        return Math.floor(diff / 86400) + "d ago";
    }
    function refresh() {
        document.querySelectorAll("[data-last-sync-at]").forEach(function (el) {
            var ts = parseFloat(el.getAttribute("data-last-sync-at"));
            var span = el.querySelector(".last-sync-rel");
            if (span && !isNaN(ts)) span.textContent = fmtRel(ts);
        });
    }
    refresh();
    setInterval(refresh, 30000);
})();
</script>

<style>
.add-peer-chevron {
    transition: transform 0.2s ease;
}
[aria-expanded="true"] .add-peer-chevron {
    transform: rotate(180deg);
}
.endpoint-display:hover {
    text-decoration: underline;
}
.peer-actions-dropdown .dropdown-menu {
    position: fixed !important;
    inset: auto !important;
    transform: none !important;
}
</style>
{% endblock %}
