/**
 * store/viewer.ts — Viewer singleton state (fstoken + roots)
 *
 * fstoken has a 1h TTL on the backend. We cache it in sessionStorage so
 * F5 and agent→viewer transitions are instant (stale-while-revalidate).
 *
 * acquire() is idempotent: no-op if token is fresh, re-acquires if within
 * REFRESH_BEFORE_EXPIRY of expiry. Safe to call from multiple places.
 */

import { defineStore } from 'pinia';
import { ref, computed } from 'vue';
import { getApiBase } from '../utils/apiBase';

const STORAGE_KEY = 'viewer_auth';
const REFRESH_BEFORE_EXPIRY_MS = 5 * 60 * 1000; // refresh if <5min left

interface ViewerAuth {
    fstoken: string;
    roots: string[];
    expiresAt: number; // ms epoch, client-side estimate (TTL - 1h)
}



function loadStored(): ViewerAuth | null {
    try {
        const raw = sessionStorage.getItem(STORAGE_KEY);
        if (!raw) return null;
        return JSON.parse(raw) as ViewerAuth;
    } catch {
        return null;
    }
}

function saveStored(auth: ViewerAuth) {
    try {
        sessionStorage.setItem(STORAGE_KEY, JSON.stringify(auth));
    } catch {}
}

function clearStored() {
    sessionStorage.removeItem(STORAGE_KEY);
}

export const useViewerStore = defineStore('viewer', () => {
    const stored = loadStored();

    const fstoken = ref<string>(stored?.fstoken ?? '');
    const roots = ref<string[]>(stored?.roots ?? []);
    const expiresAt = ref<number>(stored?.expiresAt ?? 0);

    // true once we have a valid (non-expired) token
    const ready = computed(() => !!fstoken.value && Date.now() < expiresAt.value);

    let acquiring: Promise<void> | null = null;

    async function acquire(force = false): Promise<void> {
        // Skip if token is fresh (more than REFRESH_BEFORE_EXPIRY_MS left)
        if (!force && fstoken.value && Date.now() < expiresAt.value - REFRESH_BEFORE_EXPIRY_MS) return;

        // Deduplicate concurrent calls
        if (acquiring) return acquiring;

        acquiring = _acquire().finally(() => { acquiring = null; });
        return acquiring;
    }

    async function _acquire(): Promise<void> {
        const sessionToken = localStorage.getItem('nyx_session') || localStorage.getItem('titan_token') || '';
        if (!sessionToken) return;

        try {
            const res = await fetch(`${getApiBase()}/api/viewer/token`, {
                method: 'POST',
                headers: { Authorization: `Bearer ${sessionToken}` },
            });
            if (!res.ok) {
                // token rejected — clear stale state
                fstoken.value = '';
                roots.value = [];
                expiresAt.value = 0;
                clearStored();
                return;
            }
            const data = await res.json();
            const newToken: string = data.fstoken;

            // Fetch roots while we have the token
            let newRoots: string[] = roots.value.length ? roots.value : ['shared', 'workspace-titan'];
            try {
                const tr = await fetch(`${getApiBase()}/api/viewer/tree?root=&token=${encodeURIComponent(newToken)}`);
                if (tr.ok) {
                    const td = await tr.json();
                    if (Array.isArray(td.dirs) && td.dirs.length) newRoots = td.dirs;
                }
            } catch {}

            // Client-side expiry estimate: backend TTL is 1h
            const newExpiresAt = Date.now() + 60 * 60 * 1000;

            fstoken.value = newToken;
            roots.value = newRoots;
            expiresAt.value = newExpiresAt;

            saveStored({ fstoken: newToken, roots: newRoots, expiresAt: newExpiresAt });
        } catch {}
    }

    function invalidate() {
        fstoken.value = '';
        roots.value = [];
        expiresAt.value = 0;
        clearStored();
    }

    return { fstoken, roots, ready, acquire, invalidate };
});
