import { Schema } from 'jsonschema'
import {
    TestUsersSchema,
    isJsonValidAndLogError,
    PeersInfoSchema,
    ModulesSchema,
    SelfInfoSchema,
} from '../types/typeSchemas'
import logger from './logger'
import utils from './utils'

// FIXME: remove all file exists checks from everywhere for files that are created / checked here

type FileDescriptor = {
    path: string
    schema?: Schema
    defaultValue?: string
    shouldBe?: string
    description?: string
}

export const validateFiles = (): boolean => {
    let everythingValid = true
    Object.entries(files).forEach(([key, file]: [string, FileDescriptor]) => {
        let fileExists = utils.FileExists(file.path)
        if (file.defaultValue != null && !fileExists) {
            // FIXME: create path too
            utils.WriteFile(file.defaultValue, file.path)
            fileExists = true
        }

        if (file.shouldBe && !fileExists) {
            const errMsg = [`File "${file.path}" does not exist! (${key})`]
            if (file.shouldBe) {
                errMsg.push(`Should be: ${file.shouldBe}`)
            }
            logger.Log(errMsg.join(' '), 'redbg')
            everythingValid = false
            return
        }

        if (file.schema && fileExists) {
            const val = utils.ReadJSON(file.path)
            if (!isJsonValidAndLogError(val, file.schema, file.path)) {
                everythingValid = false
                return
            }
        }
    })

    return everythingValid
}

export const files = {
    // --------------------------------------------------------------------------------
    // server / modules files
    // --------------------------------------------------------------------------------
    serverPath: {
        path: 'dist/server.js',
        shouldBe:
            'server main entry file, created after running "npm run build"',
    },
    qminingPageDir: {
        path: 'submodules/qmining-page',
        shouldBe:
            'qmining page submodule directory, created by pulling submodules / setup script',
    },
    qminingIndexPath: {
        path: 'nextStatic/qminingPagePublic/index.html',
        shouldBe:
            'qmining page-s build index.html, created by "npm run build" in qmining page submodule dir',
    },
    dataEditorPageDir: {
        path: 'submodules/qmining-data-editor',
        shouldBe:
            'qmining data editor page submodule directory, created by pulling submodules / setup script',
    },
    dataEditorIndexPath: {
        path: 'nextStatic/dataEditorPublic/index.html',
        shouldBe:
            'qmining data editor-s build index.html, created by "npm run build" in qmining data editor submodule dir',
    },
    moodleTestUserscriptDir: {
        path: 'submodules/moodle-test-userscript',
        shouldBe:
            'moodle test userscript submodule directory, created by pulling submodules / setup script',
    },
    moodleTestUserscriptPath: {
        path: 'submodules/moodle-test-userscript/stable.user.js',
        shouldBe:
            'moodle test userscript file, created by pulling submodules / setup script',
    },

    domainFile: {
        path: 'data/domain',
        shouldBe:
            'server domain for cookies and stuff, for ex.: "frylabs.net", no "http://" and things like that, just the domain',
    },
    // --------------------------------------------------------------------------------
    // stats files
    // --------------------------------------------------------------------------------
    registeredScriptsFile: {
        path: 'stats/registeredScripts.json',
        defaultValue: JSON.stringify([]),
    },
    askedQuestionFile: {
        path: 'stats/askedQuestions',
        description: 'text file of recieved data on /ask',
    },
    recievedQuestionFile: {
        path: 'stats/recievedQuestions',
        description: 'text file of recieved data on /isAdding',
    },
    dailyDataCountFile: {
        path: 'stats/dailyDataCount',
        description: 'text file of daily data count',
    },
    dataEditsLog: {
        path: 'stats/dataEdits',
        description: 'text file of data edit logs',
    },

    // --------------------------------------------------------------------------------
    // https files
    // --------------------------------------------------------------------------------
    privkeyFile: {
        path: '/etc/letsencrypt/live/frylabs.net/privkey.pem',
        description: 'private key file for https',
    },
    fullchainFile: {
        path: '/etc/letsencrypt/live/frylabs.net/fullchain.pem',
        description: 'full chain key file for https',
    },
    chainFile: {
        path: '/etc/letsencrypt/live/frylabs.net/chain.pem',
        description: 'chain key file for https',
    },

    // --------------------------------------------------------------------------------
    // api files
    // --------------------------------------------------------------------------------
    rootRedirectToFile: {
        path: 'data/apiRootRedirectTo',
        description: 'url to redirect users trying to acces root api path',
    },
    modulesFile: {
        path: './src/modules.json',
        shouldBe: 'module files for server',
        schema: ModulesSchema,
    },
    extraModulesFile: {
        path: './src/extraModules/extraModules.json',
        description: 'extra private modules for server, not tracked by git',
        schema: ModulesSchema,
    },
    statExcludeFile: {
        path: './data/statExclude.json',
        shouldBe:
            'array of strings which if included in requests url-s then the request itself is not counted in stats',
        defaultValue: JSON.stringify([]),
        schema: { type: 'array', items: { type: 'string' } },
    },
    usersDBPath: {
        path: './data/dbs/users.db',
        shouldBe: 'users sqlite db file',
    },

    // --------------------------------------------------------------------------------
    // qmining api
    // --------------------------------------------------------------------------------
    testUsersFile: {
        path: 'data/testUsers.json',
        defaultValue: JSON.stringify({ userIds: [] }),
        schema: TestUsersSchema,
        description:
            'test users, recieved data from them wont get added to question dbs',
    },

    // --------------------------------------------------------------------------------
    // log files
    // --------------------------------------------------------------------------------
    vlogDir: {
        path: 'stats/vlogs/',
        description: 'verbose logs directory',
    },
    logDir: {
        path: 'stats/logs/',
        description: 'basic logs directory',
    },
    statFile: {
        path: 'stats/stats',
        defaultValue: JSON.stringify({}),
        description: 'json of visited paths all time',
    },
    vStatFile: {
        path: 'stats/vstats',
        defaultValue: JSON.stringify({}),
        description: 'json of visited paths by day',
    },
    uStatsFile: {
        path: 'stats/ustats',
        defaultValue: JSON.stringify({}),
        description: 'json of visits per user',
    },
    uvStatsFile: {
        path: 'stats/uvstats',
        defaultValue: JSON.stringify({}),
        description: 'json of visits per user by day',
    },
    nologFile: {
        path: './data/nolog',
        defaultValue: '',
        description:
            'text file of users seperated by new lines to ignore in logging / stats',
    },

    // --------------------------------------------------------------------------------
    // peer files
    // --------------------------------------------------------------------------------
    peersPath: {
        path: 'data/p2p/',
        description: 'p2p files directory',
    },
    peersFile: {
        path: 'data/p2p/peers.json',
        description: 'json of list of peers',
        defaultValue: JSON.stringify([]),
        schema: PeersInfoSchema,
    },
    selfInfoFile: {
        path: 'data/p2p/selfInfo.json',
        description: 'json of info of this servers peer functionality',
        defaultValue: JSON.stringify({}),
        schema: SelfInfoSchema,
    },
    thirdPartyPeersFile: {
        path: 'data/p2p/thirdPartyPeers.json',
        description: 'json of third party peers reported by other peers',
    },
    keyFile: {
        path: 'data/p2p/key',
    },
} as const satisfies Record<string, FileDescriptor>

export const paths = Object.entries(files).reduce(
    (acc, [key, value]) => ({ ...acc, [key]: value.path }),
    {}
) as Record<keyof typeof files, string>
