import {Session} from './service/Session.service.js'

export const ResourceActions = Object.freeze({
    create: 'create',
    read: 'read',
    readOne: 'readOne',
    update: 'update',
    delete: 'delete',
})

export class UnsupportedActionError extends Error {
    constructor(key, action) {
        super(`Resource '${key}' does not support action '${action}'.`)
    }
}

export class Resource {
    static async get(key) {
        if ( !this.instances ) {
            this.instances = []
        }

        if ( !this.instances[name] ) {
            this.instances[key] = new Resource(key)
            await this.instances[key].configure()
        }

        return this.instances[key]
    }

    constructor(key) {
        this.key = key
        this.configuration = {
            supportedActions: [],
        }
    }

    singular() {
        return this.configuration.display.singular
    }

    plural() {
        return this.configuration.display.plural
    }

    async configure() {
        this.configuration = await this.json('configure').then(x => x.data)
    }

    getSupportedActions() {
        return this.configuration.supportedActions
    }

    supports(action) {
        return this.getSupportedActions().includes(action)
    }

    checkSupports(action) {
        if ( !this.supports(action) ) {
            throw new UnsupportedActionError(this.key, action)
        }
    }

    async create(record) {
        return this.json('/', record, 'put').then(x => x.data)
    }

    async read() {
        this.checkSupports(ResourceActions.read)
        return this.json('/').then(x => x.data.records)
    }

    async readOne(id) {
        this.checkSupports(ResourceActions.readOne)
        return this.json(`/${id}`).then(x => x.data)
    }

    async update(id, row) {
        await this.json(`${id}`, row, 'PATCH')
    }

    async delete(id) {
        await this.json(`${id}`, {}, 'DELETE')
    }

    async json(endpoint, body = {}, method = 'get') {
        const response = await fetch(
            this.getEndpoint(endpoint),
            {
                method,
                ...(method !== 'get' ? {
                    headers: {
                        Accept: 'application/json',
                        'Content-Type': 'application/json',
                    },
                    body: JSON.stringify(body),
                } : {})
            }
        )

        if ( !response.ok ) {
            console.error(response)
            throw new Error('Request to endpoint failed: ' + endpoint)
        }

        const json = await response.json()
        if ( !json.success ) {
            console.error(json)
            throw new Error('Unsuccessful response.')
        }

        return json
    }

    getEndpoint(url = '/') {
        if ( !url.startsWith('/') ) {
            url = `/${url}`
        }

        return Session.get().url(`dash/cobalt/resource/${this.key}${url}`)
    }
}
