import {Injectable, Model, Field, FieldType} from '@extollo/lib'
import {IpAddress, Subnet} from '../types'
import {Host, SSHHost} from '../support/hosts'
import * as ssh2 from 'ssh2'
import * as sshpk from 'sshpk'
import {Setting} from './Setting.model'
import {PCTHost} from '../support/hosts/PCTHost'

/**
 * Node Model
 * -----------------------------------
 * Represents a single LXC container running a K8s worker node.
 */
@Injectable()
export class Node extends Model<Node> {
    protected static table = 'p5x_nodes'
    protected static key = 'node_id'

    @Field(FieldType.serial)
    public id?: number

    @Field(FieldType.varchar, 'pve_id')
    public pveId!: number

    @Field(FieldType.varchar)
    public hostname!: string

    @Field(FieldType.varchar, 'assigned_ip')
    public assignedIp!: IpAddress

    @Field(FieldType.int, 'assigned_subnet')
    public assignedSubnet!: Subnet

    @Field(FieldType.bool, 'is_permanent')
    public isPermanent: boolean = false

    @Field(FieldType.bool, 'is_master')
    public isMaster: boolean = false

    public async getHost(): Promise<Host> {
        // Try to make a direct SSH connection to the container
        const privKey = await Setting.loadOneRequired('sshPrivateKey')
        const formattedPrivKey = sshpk.parsePrivateKey(privKey, 'pem', {passphrase: ''}).toString('ssh')
        const directHost = this.container().makeNew<Host>(SSHHost, {
            host: this.assignedIp,
            username: 'root',
            privateKey: formattedPrivKey,
        } as ssh2.ConnectConfig)

        if ( await directHost.isAlive() ) {
            return directHost
        }

        // Otherwise, fall back to the PCTHost proxy
        return this.container().makeNew<Host>(PCTHost, {
            host: await Setting.loadOneRequired('pveApiHost'),
            username: 'root',
            password: await Setting.loadOneRequired('pveRootPassword'),
        }, this.pveId)
    }
}
