import { defineMessages, useVIntl } from '@modrinth/ui'

export const scopeMessages = defineMessages({
	userReadEmailLabel: {
		id: 'scopes.userReadEmail.label',
		defaultMessage: 'Read user email',
	},
	userReadEmailDescription: {
		id: 'scopes.userReadEmail.description',
		defaultMessage: 'Read your email',
	},
	userReadLabel: {
		id: 'scopes.userRead.label',
		defaultMessage: 'Read user data',
	},
	userReadDescription: {
		id: 'scopes.userRead.description',
		defaultMessage: 'Access your public profile information',
	},
	userWriteLabel: {
		id: 'scopes.userWrite.label',
		defaultMessage: 'Write user data',
	},
	userWriteDescription: {
		id: 'scopes.userWrite.description',
		defaultMessage: 'Write to your profile',
	},
	userDeleteLabel: {
		id: 'scopes.userDelete.label',
		defaultMessage: 'Delete your account',
	},
	userDeleteDescription: {
		id: 'scopes.userDelete.description',
		defaultMessage: 'Delete your account',
	},
	userAuthWriteLabel: {
		id: 'scopes.userAuthWrite.label',
		defaultMessage: 'Write auth data',
	},
	userAuthWriteDescription: {
		id: 'scopes.userAuthWrite.description',
		defaultMessage: 'Modify your authentication data',
	},
	notificationReadLabel: {
		id: 'scopes.notificationRead.label',
		defaultMessage: 'Read notifications',
	},
	notificationReadDescription: {
		id: 'scopes.notificationRead.description',
		defaultMessage: 'Read your notifications',
	},
	notificationWriteLabel: {
		id: 'scopes.notificationWrite.label',
		defaultMessage: 'Write notifications',
	},
	notificationWriteDescription: {
		id: 'scopes.notificationWrite.description',
		defaultMessage: 'Delete/View your notifications',
	},
	payoutsReadLabel: {
		id: 'scopes.payoutsRead.label',
		defaultMessage: 'Read payouts',
	},
	payoutsReadDescription: {
		id: 'scopes.payoutsRead.description',
		defaultMessage: 'Read your payouts data',
	},
	payoutsWriteLabel: {
		id: 'scopes.payoutsWrite.label',
		defaultMessage: 'Write payouts',
	},
	payoutsWriteDescription: {
		id: 'scopes.payoutsWrite.description',
		defaultMessage: 'Withdraw money',
	},
	analyticsLabel: {
		id: 'scopes.analytics.label',
		defaultMessage: 'Read analytics',
	},
	analyticsDescription: {
		id: 'scopes.analytics.description',
		defaultMessage: 'Access your analytics data',
	},
	projectCreateLabel: {
		id: 'scopes.projectCreate.label',
		defaultMessage: 'Create projects',
	},
	projectCreateDescription: {
		id: 'scopes.projectCreate.description',
		defaultMessage: 'Create new projects',
	},
	projectReadLabel: {
		id: 'scopes.projectRead.label',
		defaultMessage: 'Read projects',
	},
	projectReadDescription: {
		id: 'scopes.projectRead.description',
		defaultMessage: 'Read all your projects',
	},
	projectWriteLabel: {
		id: 'scopes.projectWrite.label',
		defaultMessage: 'Write projects',
	},
	projectWriteDescription: {
		id: 'scopes.projectWrite.description',
		defaultMessage: 'Write to project data',
	},
	projectDeleteLabel: {
		id: 'scopes.projectDelete.label',
		defaultMessage: 'Delete projects',
	},
	projectDeleteDescription: {
		id: 'scopes.projectDelete.description',
		defaultMessage: 'Delete your projects',
	},
	versionCreateLabel: {
		id: 'scopes.versionCreate.label',
		defaultMessage: 'Create versions',
	},
	versionCreateDescription: {
		id: 'scopes.versionCreate.description',
		defaultMessage: 'Create new versions',
	},
	versionReadLabel: {
		id: 'scopes.versionRead.label',
		defaultMessage: 'Read versions',
	},
	versionReadDescription: {
		id: 'scopes.versionRead.description',
		defaultMessage: 'Read all versions',
	},
	versionWriteLabel: {
		id: 'scopes.versionWrite.label',
		defaultMessage: 'Write versions',
	},
	versionWriteDescription: {
		id: 'scopes.versionWrite.description',
		defaultMessage: 'Write to version data',
	},
	versionDeleteLabel: {
		id: 'scopes.versionDelete.label',
		defaultMessage: 'Delete versions',
	},
	versionDeleteDescription: {
		id: 'scopes.versionDelete.description',
		defaultMessage: 'Delete a version',
	},
	reportCreateLabel: {
		id: 'scopes.reportCreate.label',
		defaultMessage: 'Create reports',
	},
	reportCreateDescription: {
		id: 'scopes.reportCreate.description',
		defaultMessage: 'Create reports',
	},
	reportReadLabel: {
		id: 'scopes.reportRead.label',
		defaultMessage: 'Read reports',
	},
	reportReadDescription: {
		id: 'scopes.reportRead.description',
		defaultMessage: 'Read reports',
	},
	reportWriteLabel: {
		id: 'scopes.reportWrite.label',
		defaultMessage: 'Write reports',
	},
	reportWriteDescription: {
		id: 'scopes.reportWrite.description',
		defaultMessage: 'Edit reports',
	},
	reportDeleteLabel: {
		id: 'scopes.reportDelete.label',
		defaultMessage: 'Delete reports',
	},
	reportDeleteDescription: {
		id: 'scopes.reportDelete.description',
		defaultMessage: 'Delete reports',
	},
	threadReadLabel: {
		id: 'scopes.threadRead.label',
		defaultMessage: 'Read threads',
	},
	threadReadDescription: {
		id: 'scopes.threadRead.description',
		defaultMessage: 'Read threads',
	},
	threadWriteLabel: {
		id: 'scopes.threadWrite.label',
		defaultMessage: 'Write threads',
	},
	threadWriteDescription: {
		id: 'scopes.threadWrite.description',
		defaultMessage: 'Write to threads',
	},
	patCreateLabel: {
		id: 'scopes.patCreate.label',
		defaultMessage: 'Create PATs',
	},
	patCreateDescription: {
		id: 'scopes.patCreate.description',
		defaultMessage: 'Create personal API tokens',
	},
	patReadLabel: {
		id: 'scopes.patRead.label',
		defaultMessage: 'Read PATs',
	},
	patReadDescription: {
		id: 'scopes.patRead.description',
		defaultMessage: 'View created API tokens',
	},
	patWriteLabel: {
		id: 'scopes.patWrite.label',
		defaultMessage: 'Write PATs',
	},
	patWriteDescription: {
		id: 'scopes.patWrite.description',
		defaultMessage: 'Edit personal API tokens',
	},
	patDeleteLabel: {
		id: 'scopes.patDelete.label',
		defaultMessage: 'Delete PATs',
	},
	patDeleteDescription: {
		id: 'scopes.patDelete.description',
		defaultMessage: 'Delete your personal API tokens',
	},
	sessionReadLabel: {
		id: 'scopes.sessionRead.label',
		defaultMessage: 'Read sessions',
	},
	sessionReadDescription: {
		id: 'scopes.sessionRead.description',
		defaultMessage: 'Read active sessions',
	},
	sessionDeleteLabel: {
		id: 'scopes.sessionDelete.label',
		defaultMessage: 'Delete sessions',
	},
	sessionDeleteDescription: {
		id: 'scopes.sessionDelete.description',
		defaultMessage: 'Delete sessions',
	},
	performAnalyticsLabel: {
		id: 'scopes.performAnalytics.label',
		defaultMessage: 'Perform analytics',
	},
	performAnalyticsDescription: {
		id: 'scopes.performAnalytics.description',
		defaultMessage: 'Perform analytics actions',
	},
	collectionCreateLabel: {
		id: 'scopes.collectionCreate.label',
		defaultMessage: 'Create collections',
	},
	collectionCreateDescription: {
		id: 'scopes.collectionCreate.description',
		defaultMessage: 'Create collections',
	},
	collectionReadLabel: {
		id: 'scopes.collectionRead.label',
		defaultMessage: 'Read collections',
	},
	collectionReadDescription: {
		id: 'scopes.collectionRead.description',
		defaultMessage: 'Read collections',
	},
	collectionWriteLabel: {
		id: 'scopes.collectionWrite.label',
		defaultMessage: 'Write collections',
	},
	collectionWriteDescription: {
		id: 'scopes.collectionWrite.description',
		defaultMessage: 'Write to collections',
	},
	collectionDeleteLabel: {
		id: 'scopes.collectionDelete.label',
		defaultMessage: 'Delete collections',
	},
	collectionDeleteDescription: {
		id: 'scopes.collectionDelete.description',
		defaultMessage: 'Delete collections',
	},
	organizationCreateLabel: {
		id: 'scopes.organizationCreate.label',
		defaultMessage: 'Create organizations',
	},
	organizationCreateDescription: {
		id: 'scopes.organizationCreate.description',
		defaultMessage: 'Create organizations',
	},
	organizationReadLabel: {
		id: 'scopes.organizationRead.label',
		defaultMessage: 'Read organizations',
	},
	organizationReadDescription: {
		id: 'scopes.organizationRead.description',
		defaultMessage: 'Read organizations',
	},
	organizationWriteLabel: {
		id: 'scopes.organizationWrite.label',
		defaultMessage: 'Write organizations',
	},
	organizationWriteDescription: {
		id: 'scopes.organizationWrite.description',
		defaultMessage: 'Write to organizations',
	},
	organizationDeleteLabel: {
		id: 'scopes.organizationDelete.label',
		defaultMessage: 'Delete organizations',
	},
	organizationDeleteDescription: {
		id: 'scopes.organizationDelete.description',
		defaultMessage: 'Delete organizations',
	},
	sessionAccessLabel: {
		id: 'scopes.sessionAccess.label',
		defaultMessage: 'Access sessions',
	},
	sessionAccessDescription: {
		id: 'scopes.sessionAccess.description',
		defaultMessage: 'Access modrinth-issued sessions',
	},
})

const scopeDefinitions = [
	{
		id: 'USER_READ_EMAIL',
		value: BigInt(1) << BigInt(0),
		label: scopeMessages.userReadEmailLabel,
		desc: scopeMessages.userReadEmailDescription,
	},
	{
		id: 'USER_READ',
		value: BigInt(1) << BigInt(1),
		label: scopeMessages.userReadLabel,
		desc: scopeMessages.userReadDescription,
	},
	{
		id: 'USER_WRITE',
		value: BigInt(1) << BigInt(2),
		label: scopeMessages.userWriteLabel,
		desc: scopeMessages.userWriteDescription,
	},
	{
		id: 'USER_DELETE',
		value: BigInt(1) << BigInt(3),
		label: scopeMessages.userDeleteLabel,
		desc: scopeMessages.userDeleteDescription,
	},
	{
		id: 'USER_AUTH_WRITE',
		value: BigInt(1) << BigInt(4),
		label: scopeMessages.userAuthWriteLabel,
		desc: scopeMessages.userAuthWriteDescription,
	},
	{
		id: 'NOTIFICATION_READ',
		value: BigInt(1) << BigInt(5),
		label: scopeMessages.notificationReadLabel,
		desc: scopeMessages.notificationReadDescription,
	},
	{
		id: 'NOTIFICATION_WRITE',
		value: BigInt(1) << BigInt(6),
		label: scopeMessages.notificationWriteLabel,
		desc: scopeMessages.notificationWriteDescription,
	},
	{
		id: 'PAYOUTS_READ',
		value: BigInt(1) << BigInt(7),
		label: scopeMessages.payoutsReadLabel,
		desc: scopeMessages.payoutsReadDescription,
	},
	{
		id: 'PAYOUTS_WRITE',
		value: BigInt(1) << BigInt(8),
		label: scopeMessages.payoutsWriteLabel,
		desc: scopeMessages.payoutsWriteDescription,
	},
	{
		id: 'ANALYTICS',
		value: BigInt(1) << BigInt(9),
		label: scopeMessages.analyticsLabel,
		desc: scopeMessages.analyticsDescription,
	},
	{
		id: 'PROJECT_CREATE',
		value: BigInt(1) << BigInt(10),
		label: scopeMessages.projectCreateLabel,
		desc: scopeMessages.projectCreateDescription,
	},
	{
		id: 'PROJECT_READ',
		value: BigInt(1) << BigInt(11),
		label: scopeMessages.projectReadLabel,
		desc: scopeMessages.projectReadDescription,
	},
	{
		id: 'PROJECT_WRITE',
		value: BigInt(1) << BigInt(12),
		label: scopeMessages.projectWriteLabel,
		desc: scopeMessages.projectWriteDescription,
	},
	{
		id: 'PROJECT_DELETE',
		value: BigInt(1) << BigInt(13),
		label: scopeMessages.projectDeleteLabel,
		desc: scopeMessages.projectDeleteDescription,
	},
	{
		id: 'VERSION_CREATE',
		value: BigInt(1) << BigInt(14),
		label: scopeMessages.versionCreateLabel,
		desc: scopeMessages.versionCreateDescription,
	},
	{
		id: 'VERSION_READ',
		value: BigInt(1) << BigInt(15),
		label: scopeMessages.versionReadLabel,
		desc: scopeMessages.versionReadDescription,
	},
	{
		id: 'VERSION_WRITE',
		value: BigInt(1) << BigInt(16),
		label: scopeMessages.versionWriteLabel,
		desc: scopeMessages.versionWriteDescription,
	},
	{
		id: 'VERSION_DELETE',
		value: BigInt(1) << BigInt(17),
		label: scopeMessages.versionDeleteLabel,
		desc: scopeMessages.versionDeleteDescription,
	},
	{
		id: 'REPORT_CREATE',
		value: BigInt(1) << BigInt(18),
		label: scopeMessages.reportCreateLabel,
		desc: scopeMessages.reportCreateDescription,
	},
	{
		id: 'REPORT_READ',
		value: BigInt(1) << BigInt(19),
		label: scopeMessages.reportReadLabel,
		desc: scopeMessages.reportReadDescription,
	},
	{
		id: 'REPORT_WRITE',
		value: BigInt(1) << BigInt(20),
		label: scopeMessages.reportWriteLabel,
		desc: scopeMessages.reportWriteDescription,
	},
	{
		id: 'REPORT_DELETE',
		value: BigInt(1) << BigInt(21),
		label: scopeMessages.reportDeleteLabel,
		desc: scopeMessages.reportDeleteDescription,
	},
	{
		id: 'THREAD_READ',
		value: BigInt(1) << BigInt(22),
		label: scopeMessages.threadReadLabel,
		desc: scopeMessages.threadReadDescription,
	},
	{
		id: 'THREAD_WRITE',
		value: BigInt(1) << BigInt(23),
		label: scopeMessages.threadWriteLabel,
		desc: scopeMessages.threadWriteDescription,
	},
	{
		id: 'PAT_CREATE',
		value: BigInt(1) << BigInt(24),
		label: scopeMessages.patCreateLabel,
		desc: scopeMessages.patCreateDescription,
	},
	{
		id: 'PAT_READ',
		value: BigInt(1) << BigInt(25),
		label: scopeMessages.patReadLabel,
		desc: scopeMessages.patReadDescription,
	},
	{
		id: 'PAT_WRITE',
		value: BigInt(1) << BigInt(26),
		label: scopeMessages.patWriteLabel,
		desc: scopeMessages.patWriteDescription,
	},
	{
		id: 'PAT_DELETE',
		value: BigInt(1) << BigInt(27),
		label: scopeMessages.patDeleteLabel,
		desc: scopeMessages.patDeleteDescription,
	},
	{
		id: 'SESSION_READ',
		value: BigInt(1) << BigInt(28),
		label: scopeMessages.sessionReadLabel,
		desc: scopeMessages.sessionReadDescription,
	},
	{
		id: 'SESSION_DELETE',
		value: BigInt(1) << BigInt(29),
		label: scopeMessages.sessionDeleteLabel,
		desc: scopeMessages.sessionDeleteDescription,
	},
	{
		id: 'PERFORM_ANALYTICS',
		value: BigInt(1) << BigInt(30),
		label: scopeMessages.performAnalyticsLabel,
		desc: scopeMessages.performAnalyticsDescription,
	},
	{
		id: 'COLLECTION_CREATE',
		value: BigInt(1) << BigInt(31),
		label: scopeMessages.collectionCreateLabel,
		desc: scopeMessages.collectionCreateDescription,
	},
	{
		id: 'COLLECTION_READ',
		value: BigInt(1) << BigInt(32),
		label: scopeMessages.collectionReadLabel,
		desc: scopeMessages.collectionReadDescription,
	},
	{
		id: 'COLLECTION_WRITE',
		value: BigInt(1) << BigInt(33),
		label: scopeMessages.collectionWriteLabel,
		desc: scopeMessages.collectionWriteDescription,
	},
	{
		id: 'COLLECTION_DELETE',
		value: BigInt(1) << BigInt(34),
		label: scopeMessages.collectionDeleteLabel,
		desc: scopeMessages.collectionDeleteDescription,
	},
	{
		id: 'ORGANIZATION_CREATE',
		value: BigInt(1) << BigInt(35),
		label: scopeMessages.organizationCreateLabel,
		desc: scopeMessages.organizationCreateDescription,
	},
	{
		id: 'ORGANIZATION_READ',
		value: BigInt(1) << BigInt(36),
		label: scopeMessages.organizationReadLabel,
		desc: scopeMessages.organizationReadDescription,
	},
	{
		id: 'ORGANIZATION_WRITE',
		value: BigInt(1) << BigInt(37),
		label: scopeMessages.organizationWriteLabel,
		desc: scopeMessages.organizationWriteDescription,
	},
	{
		id: 'ORGANIZATION_DELETE',
		value: BigInt(1) << BigInt(38),
		label: scopeMessages.organizationDeleteLabel,
		desc: scopeMessages.organizationDeleteDescription,
	},
	{
		id: 'SESSION_ACCESS',
		value: BigInt(1) << BigInt(39),
		label: scopeMessages.sessionAccessLabel,
		desc: scopeMessages.sessionAccessDescription,
	},
]

const Scopes = scopeDefinitions.reduce(
	(acc, scope) => {
		acc[scope.id] = scope.value
		return acc
	},
	{} as Record<string, bigint>,
)

export const restrictedScopes = [
	Scopes.PAT_READ,
	Scopes.PAT_CREATE,
	Scopes.PAT_WRITE,
	Scopes.PAT_DELETE,
	Scopes.SESSION_READ,
	Scopes.SESSION_DELETE,
	Scopes.SESSION_ACCESS,
	Scopes.USER_AUTH_WRITE,
	Scopes.USER_DELETE,
	Scopes.PERFORM_ANALYTICS,
]

export const scopeList = Object.entries(Scopes)
	.filter(([_, value]) => !restrictedScopes.includes(value))
	.map(([key, _]) => key)

export const getScopeValue = (scope: string) => {
	return Scopes[scope]
}

export const encodeScopes = (scopes: string[]) => {
	let scopeFlag = BigInt(0)

	// We iterate over the provided scopes
	for (const scope of scopes) {
		// We iterate over the entries of the Scopes object
		for (const [scopeName, scopeFlagValue] of Object.entries(Scopes)) {
			// If the scope name is the same as the provided scope, add the scope flag to the scopeFlag variable
			if (scopeName === scope) {
				scopeFlag = scopeFlag | scopeFlagValue
			}
		}
	}

	return scopeFlag
}

export const decodeScopes = (scopes: bigint | number) => {
	if (typeof scopes === 'number') {
		scopes = BigInt(scopes)
	}

	const authorizedScopes = []

	// We iterate over the entries of the Scopes object
	for (const [scopeName, scopeFlag] of Object.entries(Scopes)) {
		// If the scope flag is present in the provided number, add the scope name to the list
		if ((scopes & scopeFlag) === scopeFlag) {
			authorizedScopes.push(scopeName)
		}
	}

	return authorizedScopes
}

export const hasScope = (scopes: bigint, scope: string) => {
	const authorizedScopes = decodeScopes(scopes)
	return authorizedScopes.includes(scope)
}

export const toggleScope = (scopes: bigint, scope: string) => {
	const authorizedScopes = decodeScopes(scopes)
	if (authorizedScopes.includes(scope)) {
		return encodeScopes(authorizedScopes.filter((authorizedScope) => authorizedScope !== scope))
	} else {
		return encodeScopes([...authorizedScopes, scope])
	}
}

export const useScopes = () => {
	const { formatMessage } = useVIntl()

	const scopesToDefinitions = (scopes: bigint) => {
		const authorizedScopes = decodeScopes(scopes)
		return authorizedScopes.map((scope) => {
			const scopeDefinition = scopeDefinitions.find(
				(scopeDefinition) => scopeDefinition.id === scope,
			)
			if (!scopeDefinition) {
				throw new Error(`Scope ${scope} not found`)
			}
			return formatMessage(scopeDefinition.desc)
		})
	}

	const scopesToLabels = (scopes: bigint) => {
		const authorizedScopes = decodeScopes(scopes)
		return authorizedScopes.map((scope) => {
			const scopeDefinition = scopeDefinitions.find(
				(scopeDefinition) => scopeDefinition.id === scope,
			)
			if (!scopeDefinition) {
				throw new Error(`Scope ${scope} not found`)
			}
			return formatMessage(scopeDefinition.label)
		})
	}

	return {
		scopesToDefinitions,
		scopesToLabels,
	}
}
