import { KvEntry } from 'nats';
import NatsClient from './NatsClient';

const BUCKET = 'station_state';

/**
 * Cached station data stored in NATS KV.
 * Keyed by station prefix — the same prefix embedded in the station token.
 * Carries all fields needed for auth and scan validation so no DB read
 * is required on the hot path after the first request from a station.
 */
export interface StationKVEntry {
    id: number;
    enabled: boolean;
    /** HMAC-SHA256 of the full station token, for re-verification on cache hit. */
    tokenHash: string;
    trackId: number;
    /** Track distance in metres. */
    trackDistance: number;
    /** Minimum lap time in seconds. 0 means no minimum (DB null mapped to 0). */
    minimumLapTime: number;
}

async function getBucket() {
    return NatsClient.getKV(BUCKET);
}

function prefixKey(prefix: string): string {
    return `station.prefix.${prefix}`;
}

function idKey(id: number): string {
    return `station.id.${id}`;
}

async function getEntry(key: string): Promise<StationKVEntry | null> {
    const bucket = await getBucket();
    let raw: KvEntry | null = null;
    try {
        raw = await bucket.get(key);
    } catch {
        return null;
    }
    if (!raw || raw.operation === 'DEL' || raw.operation === 'PURGE') {
        return null;
    }
    return JSON.parse(raw.string()) as StationKVEntry;
}

/**
 * Returns the cached StationKVEntry for the given token prefix, or null on a cache miss.
 */
export async function getStationEntry(prefix: string): Promise<StationKVEntry | null> {
    return getEntry(prefixKey(prefix));
}

/**
 * Returns the cached StationKVEntry for the given station DB id, or null on a cache miss.
 * Used by the intake flow where only stationId is available after ScanAuth.
 */
export async function getStationEntryById(id: number): Promise<StationKVEntry | null> {
    return getEntry(idKey(id));
}

/**
 * Writes a StationKVEntry under both the prefix key and the id key.
 * No TTL — entries are permanent until explicitly deleted.
 */
export async function setStationEntry(prefix: string, entry: StationKVEntry): Promise<void> {
    const bucket = await getBucket();
    const serialised = JSON.stringify(entry);
    await bucket.put(prefixKey(prefix), serialised);
    await bucket.put(idKey(entry.id), serialised);
}

/**
 * Removes the cached entries for the given prefix (and its id mirror).
 * Call this on station update or delete so the next request re-fetches from DB.
 */
export async function deleteStationEntry(prefix: string): Promise<void> {
    const bucket = await getBucket();
    // Fetch the entry first so we can also delete the id-keyed mirror
    const entry = await getEntry(prefixKey(prefix));
    try { await bucket.delete(prefixKey(prefix)); } catch { /* not cached yet */ }
    if (entry) {
        try { await bucket.delete(idKey(entry.id)); } catch { /* not cached yet */ }
    }
}
