const Model = require('flitter-orm/src/model/Model');
const uuid = require('uuid/v4');

class VersionedModel extends Model {
    static get schema() {
        return {
            version_archive: [Object],
            version_num: { type: Number, default: 1 },
            version_create_date: { type: Date, default: () => new Date },
            version_user_id: String,
        }
    }

    __is_version_instantation = false
    __version_base = undefined
    __version_data = undefined

    is_a_version() {
        return this.__is_version_instantation
    }

    version_base() {
        return this.__version_base
    }

    raw_version_data() {
        return this.__version_data
    }

    __initialize_version(base, data = {}) {
        this.__is_version_instantation = true
        this.__version_base = base
        this.__version_data = data
    }

    async version_save(message = undefined, user_id = undefined) {
        await this.new_version(message, user_id)
        return this.save()
    }

    async new_version(message = undefined, user_id = undefined) {
        if ( !this.version_num ) this.version_num = 1
        if ( !this.version_archive ) this.version_archive = []

        this.version_num += 1
        this.version_create_date = new Date()
        this.version_user_id = user_id

        const version_data = await this.cast_to_version_data()
        version_data.version_UUID = uuid()
        version_data.version_message = message

        this.version_archive.push(version_data)
    }

    async cast_to_version_data() {
        const schema = this.constructor.__schema
        const shallow_object = {}
        for ( const prop in schema.schema ) {
            if ( prop in this ) {
                shallow_object[prop] = this[prop]
            }
        }

        const data = await this.__scope_limit_save(schema.cast_to_schema(shallow_object))
        delete data.version_archive
        return data
    }

    async get_version_data(version_num = undefined) {
        if ( typeof version_num === 'undefined' ) {
            return await this.cast_to_version_data()
        } else {
            return this.version_archive.find(data => Number(data.version_num) === Number(version_num))
        }
    }

    has_version(version_num = undefined) {
        return !!this.version_archive.find(data => {
            return Number(data.version_num) === Number(version_num)
        })
    }

    toJSON() {
        const data = {...this}
        delete data.__version_data
        delete data.__version_base
        delete data.__is_version_instantation
        delete data.version_archive

        if ( this.is_a_version() ) {
            data.version_message = this.__version_data.version_message
            data.version_user_id = this.__version_data.version_user_id
        }

        return data
    }

    async as_version(version_num = undefined) {
        const data = await this.get_version_data(version_num)
        console.log('as version data', data, version_num)
        const inst = new this.constructor(data)
        inst.__initialize_version(this, data)
        return inst
    }
}

module.exports = exports = VersionedModel
