"use server";
import { redis } from "@/lib/redis";
import { functionRetrieveUserSelection } from "@/apifetchers/utils";
import { ClientOnline } from "@/types/mutual/context/validations";
import { getCompleteFromRedis, setCompleteToRedis } from "@/apifetchers/mutual/context/complete/fetch";
import { AuthError } from "@/types/mutual/context/validations";

// Redis operation timeout (5 seconds)
const REDIS_TIMEOUT = 5000;

/**
 * Gets the online state from Redis
 * @returns The online state object
 */
const getOnlineFromRedis = async (): Promise<ClientOnline> => {
    try {
        let result;
        let decrpytUserSelection;
        try { decrpytUserSelection = await functionRetrieveUserSelection() } catch (error) { throw new AuthError('Failed to retrieve user selection') }
        const redisKey = decrpytUserSelection?.redisKey;
        if (!redisKey) { throw new AuthError('No redis key found') }
        if (redisKey === "default") { throw new AuthError('Invalid redis key') }
        try {
            const timeoutPromise = new Promise((_, reject) => { setTimeout(() => reject(new Error('Redis operation timed out')), REDIS_TIMEOUT) });
            result = await Promise.race([redis.get(`${redisKey}`), timeoutPromise]) as string | null;
        } catch (redisError) { throw new AuthError('Failed to access Redis data') }

        if (!result) { throw new AuthError('No data found in redis') }

        try {
            const parsedResult = JSON.parse(result);
            if (!parsedResult.online) { throw new AuthError('No online data found in redis') }
            return parsedResult.online;
        } catch (parseError) { throw new AuthError('Invalid data format in redis') }
    } catch (error) { if (error instanceof AuthError) { throw error } else { throw new AuthError(error instanceof Error ? error.message : 'Unknown error') } }
}

/**
 * Sets the online state in Redis
 * @param onlineObject The online state to set
 * @returns True if successful, false otherwise
 */
const setOnlineToRedis = async (onlineObject: ClientOnline): Promise<boolean> => {
    try {
        if (!onlineObject) { throw new AuthError('No online object provided') }

        let decrpytUserSelection;
        let oldData;

        try { decrpytUserSelection = await functionRetrieveUserSelection() } catch (error) { throw new AuthError('Failed to retrieve user selection') }
        if (!decrpytUserSelection) { throw new AuthError('No user selection found') }
        const redisKey = decrpytUserSelection?.redisKey;
        if (!redisKey) { throw new AuthError('No redis key found') }
        try { oldData = await getCompleteFromRedis() } catch (error) { throw new AuthError('Failed to retrieve existing data from Redis') }
        if (!oldData) { throw new AuthError('No old data found in redis') }
        try {
            const timeoutPromise = new Promise((_, reject) => { setTimeout(() => reject(new Error('Redis operation timed out')), REDIS_TIMEOUT) });
            await Promise.race([setCompleteToRedis({ ...oldData, online: onlineObject }), timeoutPromise]);
            return true;
        } catch (redisError) { throw new AuthError('Failed to update Redis data') }
    } catch (error) { if (error instanceof AuthError) throw error; throw new AuthError(error instanceof Error ? error.message : 'Unknown error') }
}

export { getOnlineFromRedis, setOnlineToRedis };
