const modulename = 'UpdateChecker';
import { txEnv } from '@core/globalData';
import consoleFactory from '@lib/console';
import { UpdateDataType } from '@shared/otherTypes';
import { UpdateAvailableEventType } from '@shared/socketioTypes';
import { queryChangelogApi } from './queryChangelogApi';
import { getUpdateRolloutDelay } from './updateRollout';
const console = consoleFactory(modulename);


type CachedDelayType = {
    ts: number,
    diceRoll: number,
}

/**
 * Creates a cache string.
 */
const createCacheString = (delayData: CachedDelayType) => {
    return `${delayData.ts},${delayData.diceRoll}`;
}


/**
 * Parses the cached string.
 * Format: "ts,diceRoll"
 */
const parseCacheString = (raw: any) => {
    if (typeof raw !== 'string' || !raw) return;
    const [ts, diceRoll] = raw.split(',');
    const obj = {
        ts: parseInt(ts),
        diceRoll: parseInt(diceRoll),
    } satisfies CachedDelayType;
    if (isNaN(obj.ts) || isNaN(obj.diceRoll)) return;
    return obj;
}


/**
 * Rolls dice, gets integer between 0 and 100
 */
const rollDice = () => {
    return Math.floor(Math.random() * 101);
}

const DELAY_CACHE_KEY = 'updateDelay';


/**
 * Module to check for updates and notify the user according to a rollout strategy randomly picked.
 */
export default class UpdateChecker {
    txaUpdateData?: UpdateDataType;
    fxsUpdateData?: UpdateDataType;

    constructor() {
        //Check for updates ASAP
        setImmediate(() => {
            this.checkChangelog();
        });

        //Check again every 15 mins
        setInterval(() => {
            this.checkChangelog();
        }, 15 * 60_000);
    }


    /**
     * Check for txAdmin and FXServer updates
     */
    async checkChangelog() {
        const updates = await queryChangelogApi();
        if (!updates) return;

        //If fxserver, don't print anything, just update the data
        if (updates.fxs) {
            this.fxsUpdateData = {
                version: updates.fxs.version,
                isImportant: updates.fxs.isImportant,
            }
        }

        //If txAdmin update, check for delay before printing
        if (updates.txa) {
            //Setup delay data
            const currTs = Date.now();
            let delayData: CachedDelayType;
            const rawCache = txCore.cacheStore.get(DELAY_CACHE_KEY);
            const cachedData = parseCacheString(rawCache);
            if (cachedData) {
                delayData = cachedData;
            } else {
                delayData = {
                    diceRoll: rollDice(),
                    ts: currTs,
                }
                txCore.cacheStore.set(DELAY_CACHE_KEY, createCacheString(delayData));
            }

            //Get the delay
            const notifDelayDays = getUpdateRolloutDelay(
                updates.txa.semverDiff,
                txEnv.txaVersion.includes('-'),
                delayData.diceRoll
            );
            const notifDelayMs = notifDelayDays * 24 * 60 * 60 * 1000;
            console.verbose.debug(`Update available, notification delayed by: ${notifDelayDays} day(s).`);
            if (currTs - delayData.ts >= notifDelayMs) {
                txCore.cacheStore.delete(DELAY_CACHE_KEY);
                this.txaUpdateData = {
                    version: updates.txa.version,
                    isImportant: updates.txa.isImportant,
                }
                if (updates.txa.isImportant) {
                    console.error('This version of txAdmin is outdated.');
                    console.error('Please update as soon as possible.');
                    console.error('For more information: https://discord.gg/uAmsGa2');
                } else {
                    console.warn('This version of txAdmin is outdated.');
                    console.warn('A patch (bug fix) update is available for txAdmin.');
                    console.warn('If you are experiencing any kind of issue, please update now.');
                    console.warn('For more information: https://discord.gg/uAmsGa2');
                }
            }
        }

        //Sending event to the UI
        if (this.txaUpdateData || this.fxsUpdateData) {
            txCore.webServer.webSocket.pushEvent<UpdateAvailableEventType>('updateAvailable', {
                fxserver: this.fxsUpdateData,
                txadmin: this.txaUpdateData,
            });
        }
    }
};

/*
    TODO:
    Create an page with the changelog, that queries for the following endpoint and caches it for 15 minutes:
        https://changelogs-live.fivem.net/api/changelog/versions/2385/2375?tag=server
    Maybe even grab the data from commits:
        https://changelogs-live.fivem.net/api/changelog/versions/5562
    Other relevant apis:
        https://changelogs-live.fivem.net/api/changelog/versions/win32/server? (the one being used below)
        https://changelogs-live.fivem.net/api/changelog/versions
        https://api.github.com/repos/tabarra/txAdmin/releases (changelog in [].body)

    NOTE: old logic
    if == recommended, you're fine
    if > recommended && < optional, pls update to optional
    if == optional, you're fine
    if > optional && < latest, pls update to latest
    if == latest, duh
    if < critical, BIG WARNING
*/
