import { Schema, Validator } from 'jsonschema'
import logger from '../utils/logger'
// https://json-schema.org/learn/getting-started-step-by-step
const validator = new Validator()

export const validateJSON = (
    val: unknown,
    schema: Schema
): {
    isValid: boolean
    errorMsg: string[]
} => {
    const res = validator.validate(val, schema)
    const errorMsg = res.errors.map((e) => {
        return `${e.stack}`
    })
    return {
        isValid: res.valid,
        errorMsg: errorMsg,
    }
}

export const isJsonValidAndLogError = (
    object: unknown,
    schema: Schema,
    filePath: string
): boolean => {
    const { isValid: isSelfInfoValid, errorMsg: selfInfoErrorMsg } =
        validateJSON(object, schema)
    if (!isSelfInfoValid) {
        logger.Log(`File (${filePath}) has invalid contents!`, 'redbg')
        selfInfoErrorMsg.forEach((x) => logger.Log(x, 'red'))

        return false
    }
    return true
}

const PeerInfoSchemaBase = {
    type: 'object',
    properties: {
        name: { type: 'string' },
        host: { type: 'string' },
        port: { type: 'number' },
        publicKey: { type: 'string' },
        contact: { type: 'string' },
        lastSync: { type: 'number' },
        note: { type: 'string' },
        pw: { type: 'string' },
        http: { type: 'boolean' },
    },
    required: ['name', 'host', 'port', 'contact', 'pw'],
}

export const SelfInfoSchema: Schema = {
    ...PeerInfoSchemaBase,
    required: ['name', 'host', 'port', 'contact'],
}

export const PeerInfoSchema: Schema = {
    ...PeerInfoSchemaBase,
}

export const PeersInfoSchema: Schema = {
    type: 'array',
    items: PeerInfoSchema,
}

export const QuestionSchema: Schema = {
    type: 'object',
    properties: {
        Q: { type: 'string' },
        A: { type: 'string' },
        data: {
            type: 'object',
            properties: {
                type: { type: 'string' },
                date: { type: 'number' },
                source: { type: 'string' },
                base64: { type: 'array', items: { type: 'string' } },
                images: { type: 'array', items: { type: 'string' } },
                hashedImages: { type: 'array', items: { type: 'string' } },
                possibleAnswers: {
                    type: 'array',
                    items: {
                        type: 'object',
                        properties: {
                            type: { type: 'string' },
                            val: { type: 'string' },
                            selectedByUser: { type: 'boolean' },
                        },
                    },
                },
            },
            required: ['type'],
        },
    },
    required: ['Q', 'A', 'data'],
}

export const SubjectSchema: Schema = {
    type: 'object',
    properties: {
        Name: { type: 'string' },
        Questions: { type: 'array', items: QuestionSchema },
    },
    required: ['Name', 'Questions'],
}

export const QuestoinDbFileSchema: Schema = {
    type: 'array',
    items: SubjectSchema,
}

export const LinksSchema: Schema = {
    type: 'object',
    properties: {
        donate: { type: 'string' },
        patreon: { type: 'string' },
    },
    required: ['donate', 'patreon'],
}

export const TestUsersSchema: Schema = {
    type: 'object',
    properties: {
        userIds: { type: 'array', items: { type: 'number' } },
    },
    required: ['userIds'],
}

export const ModuleSchema: Schema = {
    type: 'object',
    properties: {
        path: { type: 'string' },
        publicdirs: {
            type: 'array',
            minItems: 1, // FIXME: make this a single string, no need for array
            items: { type: 'string' },
        },
        nextDir: { type: 'string' },
        name: { type: 'string' },
        route: { type: 'string' },
        isNextJs: { type: 'boolean' },
    },
    required: ['path', 'publicdirs', 'name', 'route'],
}

export const ModulesSchema: Schema = {
    type: 'object',
    patternProperties: {
        '.*': ModuleSchema,
    },
}
