import {AsyncPipe, Awaitable, Controller, Inject, Injectable, Maybe, QueryRow, Safe} from '@extollo/lib'
import {DataSourceController} from '../../../cobalt'
import {HostGroup} from '../../../models/HostGroup.model'
import {Provisioner} from '../../../services/Provisioner.service'

@Injectable()
export class HostGroups extends Controller implements DataSourceController {
    @Inject()
    protected readonly provisioner!: Provisioner

    read(): Awaitable<QueryRow[]> {
       return HostGroup.query<HostGroup>()
            .orderBy('name')
            .get()
            .collect()
            .then(x => x.mapCall('toCobalt').awaitAll())
            .then(x => x.all())
    }

    readOne(id: any): Awaitable<Maybe<QueryRow>> {
        return HostGroup.query<HostGroup>()
            .whereKey(id)
            .first()
            .then(x => x?.toCobalt())
    }

    insert(row: QueryRow): Awaitable<QueryRow> {
        const hosts = row.hosts
        if ( !Array.isArray(hosts) || !hosts.every(i => typeof i === 'string') ) {
            throw new Error('Invalid hosts: must be number[]')
        }

        return AsyncPipe.wrap(this.request.makeNew<HostGroup>(HostGroup))
            .peek(g => g.name = (new Safe(row.name)).string())
            .peek(g => g.save())
            .peek(g => g.setHosts(hosts))
            .tap(g => g.toCobalt())
            .resolve()
    }

    async update(id: any, row: QueryRow): Promise<QueryRow> {
        const hosts = row.hosts
        if ( !Array.isArray(hosts) || !hosts.every(i => typeof i === 'string') ) {
            throw new Error('Invalid hosts: must be number[]')
        }

        const hostGroup = await HostGroup.query<HostGroup>()
            .whereKey(id)
            .first()

        if ( !hostGroup ) {
            throw new Error('Invalid host group ID.')
        }

        hostGroup.name = (new Safe(row.name)).string()
        await hostGroup.save()
        await hostGroup.setHosts(hosts)
        return hostGroup.toCobalt()
    }

    async delete(id: any): Promise<void> {
        HostGroup.query<HostGroup>()
            .whereKey(id)
            .delete()
    }

    async getPVEHosts(): Promise<QueryRow[]> {
        return AsyncPipe.wrap(this.provisioner)
            .tap(p => p.getApi())
            .tap(api => api.nodes.$get())
            .tap(nodes =>
                nodes.map(node => ({
                    pveHost: node.id || node.node,
                    pveDisplay: `${node.node} (CPUs: ${node.maxcpu}, RAM: ${Math.floor((node.maxmem || 0) / 1000000000)})`
                }))
            )
            .resolve()
    }
}

