import { Logger } from '@refloat/logger'
import { hostname } from 'os'

import { AgentPlatform } from './generated/schema'
import { error } from './utils/error'

export interface Configuration {
	debug: boolean
	api: URL
	name: string
	token: string
	platform: AgentPlatform
}

export namespace Configuration {
	let configuration: Readonly<Configuration> | null = null

	export function set(options: Partial<Configuration>) {
		const configured = configuration !== null

		configuration = {
			token: options.token ?? configuration?.token ?? required('TOKEN'),
			debug: options.debug ?? configuration?.debug ?? optional.boolean('DEBUG'),
			platform: options.platform ?? configuration?.platform ?? getPlatform(),
			api: new URL(
				(
					options.api?.href ??
					configuration?.api.href ??
					required('API')
				).replace(/\/+$/, ''),
			),
			name:
				options.name ??
				configuration?.name ??
				optional('AGENT_NAME') ??
				hostname(),
		}

		if (!configured || typeof options.debug === 'boolean') {
			Logger.configure({ debug: configuration.debug })
		}

		return configuration
	}

	export function get() {
		return configuration ?? set({})
	}

	export function required(name: string, defaultValue?: string) {
		const key = prefix(name)

		return (
			process.env[key] ?? defaultValue ?? error(`Please configure "${key}"`)
		)
	}

	export function optional(name: string, defaultValue?: string) {
		const key = prefix(name)

		return process.env[key] ?? defaultValue ?? null
	}

	export namespace optional {
		export function boolean(name: string, defaultValue?: boolean) {
			const value = optional(name, String(defaultValue))

			return value === 'true' || value === '1'
		}
	}
}

function prefix(name: string) {
	return `REFLOAT_${name}`
}

function getPlatform() {
	switch (process.platform) {
		case 'darwin':
			return AgentPlatform.macOS
		case 'linux':
			return AgentPlatform.Linux
		case 'win32':
			return AgentPlatform.Windows
		default:
			throw new Error(`Unsupported platform: "${process.platform}"`)
	}
}
