const SAVE_THROTTLE_MS = 2000;
const TOKEN_KEY = '__storage_token__';
const BASE_URL = '/storage/api';

const pendingSaves = new Map<string, ReturnType<typeof setTimeout>>();

// ─── Auth ────────────────────────────────────────────────────

let token: string | null = localStorage.getItem(TOKEN_KEY);

export const isLoggedIn = () => token !== null;

export const login = async (username: string, password: string): Promise<void> => {
    const res = await fetch(`${BASE_URL}/login`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ username, password }),
    });
    const json = await res.json();
    if (!res.ok) throw new Error(json.error ?? 'Login failed');
    token = json.token;
    localStorage.setItem(TOKEN_KEY, json.token);
};

export const logout = () => {
    token = null;
    localStorage.removeItem(TOKEN_KEY);
};

// ─── Storage ─────────────────────────────────────────────────

export const loadObject = async <T>(key: string, defaultObject: T): Promise<T> => {
    let localObject: Partial<T> = {};
    try {
        const json = localStorage.getItem(key);
        if (json) localObject = JSON.parse(json);
    } catch { }

    let remoteObject: Partial<T> = {};
    if (token) {
        try {
            const res = await fetch(`${BASE_URL}/storage/${key}`, {
                headers: { 'Authorization': `Bearer ${token}` },
            });
            if (res.ok) remoteObject = await res.json();
        } catch { }
    }

    return { ...defaultObject, ...localObject, ...remoteObject };
}

export const saveObject = <T>(key: string, obj: T) => {
    const saveData = JSON.stringify(obj);

    try {
        localStorage.setItem(key, saveData);
    } catch { }

    if (token) {
        const existing = pendingSaves.get(key);
        if (existing) clearTimeout(existing);
        pendingSaves.set(key, setTimeout(() => {
            pendingSaves.delete(key);
            saveRemote(key, saveData);
        }, SAVE_THROTTLE_MS));
    }
};

const saveRemote = async (key: string, saveData: string) => {
    try {
        await fetch(`${BASE_URL}/storage/${key}`, {
            method: 'POST',
            headers: {
                'Authorization': `Bearer ${token}`,
                'Content-Type': 'application/json',
            },
            body: saveData,
        });
    } catch { }
};

// ─── Compression utils ───────────────────────────────────────

export const compressBlob = async (blob: Blob | string): Promise<Blob> => {
    if (typeof blob === 'string') blob = new Blob([blob]);
    const cs = new CompressionStream("gzip");
    return await new Response(blob.stream().pipeThrough(cs)).blob();
}

export const decompressBlob = async (blob: Blob): Promise<Blob> => {
    const ds = new DecompressionStream("gzip");
    return await new Response(blob.stream().pipeThrough(ds)).blob();
}
