/**
 * Fleet shared-state sync as a `PeriodicService` (PHNX-3392 usage-sync,
 * PHNX-3792 session mirror).
 *
 * This is the one tick that owns the bounded Git exchange over the fleet-synced
 * user repo, so every non-secret daemon-state field rides it rather than opening
 * a second committer. Each tick: (1) publishes this box's own fields into its
 * conflict-free `devices/<device>/daemon-state.json` — a headed box's Claude
 * usage snapshot, and EVERY box's lightweight session digests (PHNX-3792);
 * (2) runs one serialized, timeout-bounded commit/rebase/push; (3) consumes the
 * peer fields the exchange delivered — a worker merges usage newest-wins, and
 * every non-worker box folds peers' session digests into its local index so the
 * picker renders remote-host previews inline. No tick opens a device-to-device
 * SSH mesh.
 */
import { BasePeriodicService } from './service.js';
const USAGE_SYNC_TICK_MS = 15 * 60_000;
const USAGE_SYNC_DEADLINE_MS = 2 * 60_000;
const USAGE_SYNC_KICKOFF_MS = 90_000;
export class UsageSyncService extends BasePeriodicService {
    id = 'usage-sync';
    intervalMs = USAGE_SYNC_TICK_MS;
    deadlineMs = USAGE_SYNC_DEADLINE_MS;
    startupDelayMs = USAGE_SYNC_KICKOFF_MS;
    async onStart(_ctx) {
        // No connections to open — each tick re-reads the local cache + registry.
    }
    async onStop() {
        // Nothing to release — the supervisor's timer teardown is the only cleanup.
    }
    async onTick(ctx) {
        const { consumeUsageSnapshotsFromSharedStore, publishUsageSnapshotToSharedStore } = await import('../accounting/usage-sync.js');
        const { consumeSessionMirrorFromSharedStore, publishSessionMirrorToSharedStore } = await import('../session/mirror.js');
        // Publish every owned field BEFORE the single git exchange so they ride one commit.
        const published = await publishUsageSnapshotToSharedStore();
        if (published.changed)
            ctx.log('INFO', `usage-sync: published usage snapshot to ${published.path}`);
        if (published.error)
            ctx.log('WARN', `usage-sync: publish: ${published.error}`);
        const mirrored = await publishSessionMirrorToSharedStore();
        if (mirrored.changed)
            ctx.log('INFO', `session-mirror: published ${mirrored.count} session digest(s)`);
        if (mirrored.error)
            ctx.log('WARN', `session-mirror: publish: ${mirrored.error}`);
        const { syncFleetSharedStateRepo } = await import('../fleet-shared-repo-sync.js');
        const transport = await syncFleetSharedStateRepo();
        if (transport.skipped)
            ctx.log('WARN', `usage-sync: ${transport.skipped}`);
        if (transport.error)
            ctx.log('WARN', `usage-sync: shared-store transport: ${transport.error}`);
        if (transport.untrackedBackedUp?.length) {
            ctx.log('WARN', `usage-sync: backed up ${transport.untrackedBackedUp.length} untracked shared-store collision(s) to ${transport.untrackedBackupDir}: ${transport.untrackedBackedUp.join(', ')}`);
        }
        if (!transport.success)
            return;
        const consumed = consumeUsageSnapshotsFromSharedStore();
        if (consumed.merged > 0) {
            ctx.log('INFO', `usage-sync: merged ${consumed.merged} row(s) from ${consumed.sources.join(', ')}`);
        }
        for (const err of consumed.errors)
            ctx.log('WARN', `usage-sync: ${err.device}: ${err.message}`);
        const foldedIn = consumeSessionMirrorFromSharedStore();
        if (foldedIn.merged > 0) {
            ctx.log('INFO', `session-mirror: folded ${foldedIn.merged} session(s) from ${foldedIn.sources.join(', ')}`);
        }
        if (foldedIn.pruned > 0)
            ctx.log('INFO', `session-mirror: pruned ${foldedIn.pruned} stale mirror row(s)`);
        for (const err of foldedIn.errors)
            ctx.log('WARN', `session-mirror: ${err.device}: ${err.message}`);
    }
}
