import { dirname, join, normalize } from 'path'

export function resolve(source: string, dependency: string) {
	if (dependency === '@refloat/context') {
		return dependency
	}

	const relative = dependency.startsWith('./') || dependency.startsWith('../')
	let path = dependency

	if (!path.endsWith('.js')) {
		path += '.js'
	}

	if (relative) {
		return path
	}

	let scheme: Source.Scheme | null = null

	if (path[0] === '.') {
		path = normalize(join(dirname(source), path))
	} else {
		const parsed = parseScheme(path)

		scheme = parsed.scheme
		path = normalize(parsed.path)
	}

	if (path.endsWith('/') || (!relative && path.split('/').length <= 3)) {
		path = normalize(join(path, 'index.js'))
	}

	return relative ? path : `${scheme}://${path}`
}

export interface Source {
	scheme: Source.Scheme
	host: string
	owner: string
	repo: string
	path: string
	ref: string | null
}

export namespace Source {
	export type Scheme = 'git+https' | 'git+ssh'
}

export function parse(source: string): Source {
	const { scheme, path: schemePath } = parseScheme(source)
	const [host, owner, repoPath, ...paths] = normalize(schemePath).split('/')
	const path = paths.join('/')

	if (
		typeof host === 'string' &&
		typeof owner === 'string' &&
		typeof repoPath === 'string'
	) {
		const [repo, ref = null] = repoPath.split('#')

		if (typeof repo === 'string') {
			return { scheme, host, owner, repo, path, ref }
		}
	}

	throw new Error(`Invalid config module source: "${source}"`)
}

function parseScheme(source: string): Pick<Source, 'scheme' | 'path'> {
	if (re.git.https.test(source)) {
		return {
			scheme: 'git+https',
			path: source.replace(re.git.https, ''),
		}
	}

	return {
		scheme: 'git+ssh',
		path: source.replace(re.git.ssh, ''),
	}
}

const re = {
	git: {
		ssh: /^git\+ssh:\/\//,
		https: /^git\+https:\/\//,
	},
}
