<template>
	<div v-if="data">
		<Teleport to="#sidebar-teleport-target">
			<ProjectSidebarCompatibility
				v-if="!isServerProject"
				:project="data"
				:tags="{ loaders: allLoaders, gameVersions: allGameVersions }"
				:project-v3="projectV3"
				class="project-sidebar-section"
			/>
			<ProjectSidebarServerInfo
				v-if="isServerProject"
				:project-v3="projectV3"
				:tags="{ loaders: allLoaders, gameVersions: allGameVersions }"
				:required-content="serverRequiredContent"
				:recommended-version="serverRecommendedVersion"
				:supported-versions="serverSupportedVersions"
				:loaders="serverModpackLoaders"
				:ping="serverPing"
				:status-online="serverStatusOnline"
				class="project-sidebar-section"
			/>
			<ProjectSidebarLinks
				link-target="_blank"
				:project="data"
				:project-v3="projectV3"
				class="project-sidebar-section"
			/>
			<ProjectSidebarTags :project="data" class="project-sidebar-section" />
			<ProjectSidebarCreators
				:organization="organization"
				:members="members"
				:org-link="(slug) => `https://modrinth.com/organization/${slug}`"
				:user-link="(username) => `https://modrinth.com/user/${username}`"
				link-target="_blank"
				class="project-sidebar-section"
			/>
			<ProjectSidebarDetails
				:project="data"
				:has-versions="versions.length > 0"
				:link-target="`_blank`"
				:hide-license="isServerProject"
				:show-followers="isServerProject"
				class="project-sidebar-section"
			/>
		</Teleport>
		<div class="flex flex-col gap-4 p-6">
			<div
				v-if="projectInstallContext"
				class="sticky top-0 z-20 -mx-6 -mt-6 rounded-tl-[--radius-xl] border-0 border-b border-solid bg-surface-1 p-3 border-surface-5"
			>
				<BrowseInstallHeader :install-context="projectInstallContext" />
			</div>
			<InstanceIndicator v-if="instance && !projectInstallContext" :instance="instance" />
			<template v-if="data">
				<Teleport
					v-if="themeStore.featureFlags.project_background"
					to="#background-teleport-target"
				>
					<ProjectBackgroundGradient :project="data" />
				</Teleport>
				<ProjectPageHeader
					v-else
					:project="data"
					:project-v3="projectV3"
					:show-status-badge="data.status !== 'approved'"
					@contextmenu.prevent.stop="handleRightClick"
					@category="(category) => router.push(`${projectSearchUrl}?f=categories:${category}`)"
				>
					<template #actions>
						<template v-if="isServerProject">
							<ButtonStyled v-if="serverPlaying" color="red" size="large">
								<button type="button" @click="handleStopServer">
									<StopCircleIcon />
									{{ formatMessage(commonMessages.stopButton) }}
								</button>
							</ButtonStyled>
							<ButtonStyled v-else color="brand" size="large">
								<button type="button" :disabled="serverInstallLoading" @click="handleClickPlay">
									<PlayIcon />
									{{
										serverInstallLoading
											? formatMessage(commonMessages.installingLabel)
											: formatMessage(commonMessages.playButton)
									}}
								</button>
							</ButtonStyled>
							<ButtonStyled circular size="large">
								<button
									v-tooltip="formatMessage(commonMessages.addServerToInstanceButton)"
									type="button"
									:aria-label="formatMessage(commonMessages.addServerToInstanceButton)"
									@click="handleAddServerToInstance"
								>
									<PlusIcon />
								</button>
							</ButtonStyled>
							<ButtonStyled circular size="large" type="transparent">
								<TeleportOverflowMenu
									:options="serverProjectHeaderMoreActions"
									tooltip="More options"
									aria-label="More options"
								>
									<MoreVerticalIcon />
								</TeleportOverflowMenu>
							</ButtonStyled>
						</template>
						<template v-else>
							<ButtonStyled v-if="showSwitchVersion && onVersionsPage" size="large">
								<button v-tooltip="formatMessage(messages.alreadyInstalled)" type="button" disabled>
									<CheckIcon />
									{{ formatMessage(commonMessages.installedLabel) }}
								</button>
							</ButtonStyled>
							<ButtonStyled v-else-if="showSwitchVersion" size="large">
								<button type="button" @click="goToVersions">
									<SwapIcon />
									{{ formatMessage(messages.switchVersion) }}
								</button>
							</ButtonStyled>
							<ButtonStyled v-else color="brand" size="large">
								<button
									v-tooltip="
										installButtonInstalled ? formatMessage(messages.alreadyInstalled) : undefined
									"
									type="button"
									:disabled="installButtonDisabled"
									@click="install(null)"
								>
									<component :is="installButtonIcon" :class="installButtonIconClass" />
									{{
										installButtonInstalled
											? formatMessage(commonMessages.installedLabel)
											: installButtonValidating
												? formatMessage(commonMessages.validatingLabel)
												: installButtonLoading
													? formatMessage(commonMessages.installingLabel)
													: serverProjectSelected
														? formatMessage(commonMessages.selectedLabel)
														: formatMessage(commonMessages.installButton)
									}}
								</button>
							</ButtonStyled>
							<ButtonStyled circular size="large" type="transparent">
								<TeleportOverflowMenu
									:options="projectHeaderMoreActions"
									tooltip="More options"
									aria-label="More options"
								>
									<MoreVerticalIcon />
								</TeleportOverflowMenu>
							</ButtonStyled>
						</template>
					</template>
				</ProjectPageHeader>
				<NavTabs
					:links="[
						{
							label: 'Description',
							href: projectDescriptionHref,
						},
						{
							label: 'Versions',
							href: versionsHref,
							subpages: ['version'],
							shown: projectV3?.minecraft_server == null,
						},
						{
							label: 'Gallery',
							href: projectGalleryHref,
							shown: data.gallery.length > 0,
						},
					]"
				/>
				<RouterView
					v-if="route.path.startsWith('/project')"
					:project="data"
					:versions="versions"
					:members="members"
					:instance="instance"
					:install="install"
					:installed="installed"
					:installing="installing"
					:installed-version="installedVersion"
				/>
			</template>
			<template v-else> Project data couldn't not be loaded. </template>
		</div>
		<SelectedProjectsFloatingBar
			v-if="projectInstallContext"
			:install-context="projectInstallContext"
		/>
		<ContextMenu ref="options" @option-clicked="handleOptionsClick">
			<template #install>
				<DownloadIcon /> {{ formatMessage(commonMessages.installButton) }}
			</template>
			<template #open_link>
				<GlobeIcon /> {{ formatMessage(commonMessages.openInModrinthButton) }} <ExternalIcon />
			</template>
			<template #copy_link>
				<ClipboardCopyIcon /> {{ formatMessage(commonMessages.copyLinkButton) }}
			</template>
		</ContextMenu>
		<CreationFlowModal
			v-if="serverInstallContent.isServerContext.value && data?.project_type === 'modpack'"
			ref="serverSetupModalRef"
			:type="
				serverInstallContent.serverFlowFrom.value === 'reset-server'
					? 'reset-server'
					: 'server-onboarding'
			"
			:available-loaders="['vanilla', 'fabric', 'neoforge', 'forge', 'quilt', 'paper', 'purpur']"
			:show-snapshot-toggle="true"
			:on-back="serverInstallContent.onServerFlowBack"
			:search-modpacks="serverInstallContent.searchServerModpacks"
			:get-project-versions="serverInstallContent.getServerProjectVersions"
			:get-loader-manifest="getLoaderManifest"
			@hide="() => {}"
			@browse-modpacks="() => {}"
			@create="serverInstallContent.handleServerModpackFlowCreate"
		/>
	</div>
</template>

<script setup>
import {
	BookmarkIcon,
	CheckIcon,
	ClipboardCopyIcon,
	DownloadIcon,
	ExternalIcon,
	GlobeIcon,
	HeartIcon,
	MoreVerticalIcon,
	PlayIcon,
	PlusIcon,
	ReportIcon,
	SpinnerIcon,
	StopCircleIcon,
} from '@modrinth/assets'
import {
	BrowseInstallHeader,
	ButtonStyled,
	commonMessages,
	CreationFlowModal,
	defineMessages,
	getTargetInstallPreferences,
	injectNotificationManager,
	NavTabs,
	ProjectBackgroundGradient,
	ProjectPageHeader,
	ProjectSidebarCompatibility,
	ProjectSidebarCreators,
	ProjectSidebarDetails,
	ProjectSidebarLinks,
	ProjectSidebarServerInfo,
	ProjectSidebarTags,
	requestInstall,
	SelectedProjectsFloatingBar,
	TeleportOverflowMenu,
	useVIntl,
} from '@modrinth/ui'
import { useQueryClient } from '@tanstack/vue-query'
import { convertFileSrc } from '@tauri-apps/api/core'
import { openUrl } from '@tauri-apps/plugin-opener'
import dayjs from 'dayjs'
import relativeTime from 'dayjs/plugin/relativeTime'
import { computed, onUnmounted, ref, shallowRef, watch } from 'vue'
import { useRoute, useRouter } from 'vue-router'

import { SwapIcon } from '@/assets/icons/index.js'
import ContextMenu from '@/components/ui/ContextMenu.vue'
import InstanceIndicator from '@/components/ui/InstanceIndicator.vue'
import {
	fetchCachedServerStatus,
	getFreshCachedServerStatus,
} from '@/composables/instances/use-server-status-query'
import {
	get_organization,
	get_project,
	get_project_v3,
	get_team,
	get_version,
	get_version_many,
} from '@/helpers/cache.js'
import { process_listener } from '@/helpers/events'
import {
	get as getInstance,
	get_projects as getInstanceProjects,
	kill,
	list as listInstances,
} from '@/helpers/instance'
import { get_loader_versions as getLoaderManifest } from '@/helpers/metadata'
import { get_by_instance_id } from '@/helpers/process'
import { get_categories, get_game_versions, get_loaders } from '@/helpers/tags'
import { getServerAddress } from '@/helpers/worlds'
import { injectContentInstall } from '@/providers/content-install'
import { injectServerInstall } from '@/providers/server-install'
import { createServerInstallContent } from '@/providers/setup/server-install-content'
import { useBreadcrumbs } from '@/store/breadcrumbs'
import { useTheming } from '@/store/state.js'

dayjs.extend(relativeTime)

const { handleError } = injectNotificationManager()
const { install: installVersion } = injectContentInstall()
const route = useRoute()
const router = useRouter()
const queryClient = useQueryClient()
const breadcrumbs = useBreadcrumbs()
const themeStore = useTheming()
const { formatMessage } = useVIntl()

const messages = defineMessages({
	backToBrowse: {
		id: 'app.project.install-context.back-to-browse',
		defaultMessage: 'Back to discover',
	},
	alreadyInstalled: {
		id: 'app.project.install-button.already-installed',
		defaultMessage: 'This project is already installed',
	},
	switchVersion: {
		id: 'app.project.install-button.switch-version',
		defaultMessage: 'Switch version',
	},
})

const { installingServerProjects, playServerProject, showAddServerToInstanceModal } =
	injectServerInstall()
const installing = ref(false)
const data = shallowRef(null)
const versions = shallowRef([])
const members = shallowRef([])
const categories = shallowRef([])
const organization = shallowRef(null)
const instance = ref(null)
const instanceProjects = ref(null)

const installed = ref(false)
const installedVersion = ref(null)
const isServerProject = ref(false)
const projectV3 = shallowRef(null)
const serverRequiredContent = shallowRef(null)
const serverRecommendedVersion = shallowRef(null)
const serverSupportedVersions = shallowRef([])
const serverModpackLoaders = shallowRef([])
const serverPing = ref(undefined)
const serverStatusOnline = ref(false)
const serverInstancePath = ref(null)
const serverPlaying = ref(false)
const serverSetupModalRef = ref(null)
const serverInstallContent = createServerInstallContent({ serverSetupModalRef })

serverInstallContent.watchServerContextChanges()
await serverInstallContent.initServerContext()

const instanceFilters = computed(() => {
	if (!instance.value) {
		return {}
	}

	const loaders = []
	if (data.value.project_type === 'mod') {
		if (instance.value.loader !== 'vanilla') {
			loaders.push(instance.value.loader)
		}
		if (instance.value.loader === 'vanilla' || data.value.loaders.includes('datapack')) {
			loaders.push('datapack')
		}
	}

	return { l: loaders, g: instance.value.game_version }
})

function buildProjectHref(path, extraQuery = {}) {
	const params = new URLSearchParams()
	for (const [key, val] of Object.entries({ ...route.query, ...extraQuery })) {
		if (Array.isArray(val)) {
			for (const v of val) params.append(key, v)
		} else if (val) {
			params.append(key, String(val))
		}
	}
	const qs = params.toString()
	return qs ? `${path}?${qs}` : path
}

function buildBrowseHref(path) {
	const params = new URLSearchParams()
	for (const [key, val] of Object.entries(route.query)) {
		if (key === 'b') continue
		if (Array.isArray(val)) {
			for (const v of val) params.append(key, v)
		} else if (val) {
			params.append(key, String(val))
		}
	}
	const qs = params.toString()
	return qs ? `${path}?${qs}` : path
}

const projectDescriptionHref = computed(() => buildProjectHref(`/project/${route.params.id}`))
const versionsHref = computed(() =>
	buildProjectHref(`/project/${route.params.id}/versions`, instanceFilters.value),
)
const projectGalleryHref = computed(() => buildProjectHref(`/project/${route.params.id}/gallery`))

const projectBrowseBackUrl = computed(() => {
	const browsePath = route.query.b
	if (typeof browsePath === 'string' && browsePath.startsWith('/browse/')) return browsePath
	const type = data.value?.project_type ? `${data.value.project_type}` : 'mod'
	return buildBrowseHref(`/browse/${type}`)
})

const projectInstallContext = computed(() => {
	const serverData = serverInstallContent.serverContextServerData.value
	if (serverData) {
		return {
			name: serverData.name,
			loader: serverData.loader ?? '',
			gameVersion: serverData.mc_version ?? '',
			serverId: serverInstallContent.serverIdQuery.value,
			upstream: serverData.upstream,
			iconSrc: null,
			isMedal: serverData.is_medal,
			backUrl: projectBrowseBackUrl.value,
			backLabel: formatMessage(messages.backToBrowse),
			heading: serverInstallContent.serverBrowseHeading.value,
			queuedCount: serverInstallContent.queuedServerInstallCount.value,
			selectedProjects: serverInstallContent.selectedServerInstallProjects.value,
			isInstallingSelected: serverInstallContent.isInstallingQueuedServerInstalls.value,
			installProgress: serverInstallContent.queuedInstallProgress.value,
			clearQueued: serverInstallContent.clearQueuedServerInstalls,
			clearSelected: serverInstallContent.clearQueuedServerInstalls,
			discardSelectedAndBack: serverInstallContent.discardQueuedServerInstallsAndBack,
			installSelected: serverInstallContent.installQueuedServerInstallsAndBack,
		}
	}

	if (instance.value) {
		return {
			name: instance.value.name,
			loader: instance.value.loader,
			gameVersion: instance.value.game_version,
			iconSrc: instance.value.icon_path ? convertFileSrc(instance.value.icon_path) : null,
			backUrl: projectBrowseBackUrl.value,
			backLabel: formatMessage(messages.backToBrowse),
			heading: formatMessage(commonMessages.installingContentLabel),
		}
	}

	return null
})

const serverProjectInstallContext = computed(
	() =>
		!!serverInstallContent.serverContextServerData.value &&
		['modpack', 'mod', 'plugin', 'datapack'].includes(data.value?.project_type),
)
const serverProjectSelected = computed(
	() => !!data.value && serverInstallContent.queuedServerInstallProjectIds.value.has(data.value.id),
)
const serverProjectInstalled = computed(
	() =>
		!!data.value &&
		(serverInstallContent.serverContentProjectIds.value.has(data.value.id) ||
			serverInstallContent.serverContextServerData.value?.upstream?.project_id === data.value.id),
)
const installButtonLoading = computed(
	() => installing.value || serverInstallContent.isInstallingQueuedServerInstalls.value,
)
const installButtonValidating = computed(
	() =>
		serverProjectInstallContext.value &&
		installing.value &&
		data.value?.project_type !== 'modpack' &&
		!serverInstallContent.isInstallingQueuedServerInstalls.value,
)
const installButtonInstalled = computed(() =>
	serverProjectInstallContext.value ? serverProjectInstalled.value : installed.value,
)
const installButtonDisabled = computed(
	() => installButtonInstalled.value || installButtonLoading.value,
)
const serverInstallLoading = computed(
	() => !!data.value && installingServerProjects.value.includes(data.value.id),
)
const installButtonIcon = computed(() => {
	if (installButtonLoading.value && !installButtonInstalled.value) return SpinnerIcon
	if (!installButtonInstalled.value && !serverProjectSelected.value) return DownloadIcon
	return CheckIcon
})
const installButtonIconClass = computed(() =>
	installButtonLoading.value && !installButtonInstalled.value ? 'animate-spin' : undefined,
)
const serverProjectHeaderMoreActions = computed(() => [
	{
		id: 'open-in-browser',
		label: formatMessage(commonMessages.openInModrinthButton),
		icon: ExternalIcon,
		action: openProjectInBrowser,
	},
	{
		divider: true,
	},
	{
		id: 'report',
		label: formatMessage(commonMessages.reportButton),
		icon: ReportIcon,
		color: 'red',
		action: reportProject,
	},
])
const projectHeaderMoreActions = computed(() => [
	{
		id: 'follow',
		label: formatMessage(commonMessages.followButton),
		icon: HeartIcon,
		disabled: true,
		tooltip: 'Coming soon',
		action: () => {},
	},
	{
		id: 'save',
		label: formatMessage(commonMessages.saveButton),
		icon: BookmarkIcon,
		disabled: true,
		tooltip: 'Coming soon',
		action: () => {},
	},
	{
		id: 'open-in-browser',
		label: formatMessage(commonMessages.openInModrinthButton),
		icon: ExternalIcon,
		action: openProjectInBrowser,
	},
	{
		divider: true,
	},
	{
		id: 'report',
		label: formatMessage(commonMessages.reportButton),
		icon: ReportIcon,
		color: 'red',
		action: reportProject,
	},
])
const projectSearchUrl = computed(
	() => `/browse/${isServerProject.value ? 'server' : data.value?.project_type}`,
)

const showSwitchVersion = computed(() => !!instance.value && installed.value)
const onVersionsPage = computed(() => route.name === 'Versions')

function goToVersions() {
	router.push(versionsHref.value)
}

const [allLoaders, allGameVersions] = await Promise.all([
	get_loaders().catch(handleError).then(ref),
	get_game_versions().catch(handleError).then(ref),
])

async function handleClickPlay() {
	if (!isServerProject.value) return
	await playServerProject(data.value.id).catch(handleError)
	await updateServerPlayState()
}

async function updateServerPlayState() {
	if (!isServerProject.value || !data.value) return
	const packs = await listInstances()
	const inst = packs.find((p) => p.link?.project_id === data.value.id)
	if (inst) {
		serverInstancePath.value = inst.id
		const processes = await get_by_instance_id(inst.id).catch(() => [])
		serverPlaying.value = Array.isArray(processes) && processes.length > 0
	} else {
		serverInstancePath.value = null
		serverPlaying.value = false
	}
}

async function handleStopServer() {
	if (!serverInstancePath.value) return
	await kill(serverInstancePath.value).catch(() => {})
	serverPlaying.value = false
}

function handleAddServerToInstance() {
	const address = getServerAddress(projectV3.value?.minecraft_java_server)
	if (!address || !data.value) return
	showAddServerToInstanceModal(data.value.title, address)
}

function openProjectInBrowser() {
	if (!data.value) return
	const type = isServerProject.value ? 'project' : data.value.project_type
	void openUrl(`https://modrinth.com/${type}/${data.value.slug}`)
}

function reportProject() {
	if (!data.value) return
	void openUrl(`https://modrinth.com/report?item=project&itemID=${data.value.id}`)
}

async function fetchProjectData() {
	const [project, projectV3Result] = await Promise.all([
		get_project(route.params.id, 'must_revalidate').catch(handleError),
		get_project_v3(route.params.id, 'must_revalidate').catch(handleError),
	])
	projectV3.value = projectV3Result

	if (!project) {
		handleError('Error loading project')
		return
	}

	data.value = project
	;[versions.value, members.value, categories.value, instance.value, instanceProjects.value] =
		await Promise.all([
			get_version_many(project.versions, 'must_revalidate').catch(handleError),
			get_team(project.team).catch(handleError),
			get_categories().catch(handleError),
			route.query.i ? getInstance(route.query.i).catch(handleError) : Promise.resolve(),
			route.query.i ? getInstanceProjects(route.query.i).catch(handleError) : Promise.resolve(),
		])

	versions.value = versions.value.sort((a, b) => dayjs(b.date_published) - dayjs(a.date_published))

	if (instanceProjects.value) {
		const installedFile = Object.values(instanceProjects.value).find(
			(x) => x.metadata && x.metadata.project_id === data.value.id,
		)
		if (installedFile) {
			installed.value = true
			installedVersion.value = installedFile.metadata.version_id
		}
	}

	if (project.organization) {
		organization.value = await get_organization(project.organization).catch(handleError)
	}

	isServerProject.value = projectV3.value?.minecraft_server != null
	serverStatusOnline.value = !!projectV3.value?.minecraft_java_server?.ping?.data

	breadcrumbs.setName('Project', data.value.title)

	fetchDeferredServerData(project)
}

function fetchDeferredServerData(project) {
	const serverAddress = projectV3.value?.minecraft_java_server?.address
	if (serverAddress) {
		const cachedStatus = getFreshCachedServerStatus(queryClient, serverAddress)
		if (cachedStatus) {
			serverPing.value = cachedStatus.ping
			serverStatusOnline.value = true
		} else {
			serverPing.value = undefined
		}

		fetchCachedServerStatus(queryClient, serverAddress)
			.then((status) => {
				if (projectV3.value?.minecraft_java_server?.address !== serverAddress) return
				serverPing.value = status.ping
				serverStatusOnline.value = true
			})
			.catch((error) => {
				console.error(`Failed to ping server ${serverAddress}:`, error)
			})
	}

	const content = projectV3.value?.minecraft_java_server?.content
	if (content?.kind === 'modpack' && content.version_id) {
		get_version(content.version_id, 'bypass')
			.catch(handleError)
			.then(async (modpackVersion) => {
				if (!modpackVersion) return
				serverRecommendedVersion.value = modpackVersion.game_versions?.[0] ?? null
				serverModpackLoaders.value = modpackVersion.mrpack_loaders ?? []
				if (modpackVersion.project_id) {
					const modpackProject = await get_project_v3(
						modpackVersion.project_id,
						'must_revalidate',
					).catch(handleError)
					if (modpackProject) {
						const primaryFile =
							modpackVersion.files?.find((f) => f.primary) ?? modpackVersion.files?.[0]

						serverRequiredContent.value = {
							name: modpackProject.name,
							versionNumber: modpackVersion.version_number ?? '',
							icon: modpackProject.icon_url,
							onclickName:
								modpackProject.id !== project.id
									? () => router.push(`/project/${modpackProject.id}`)
									: undefined,
							onclickVersion:
								modpackProject.id !== project.id
									? () => router.push(`/project/${modpackProject.id}/version/${modpackVersion.id}`)
									: undefined,
							onclickDownload: primaryFile?.url ? () => openUrl(primaryFile.url) : undefined,
							showCustomModpackTooltip: modpackProject.id === project.id,
						}
					}
				}
			})
	} else if (content?.kind === 'vanilla') {
		serverRecommendedVersion.value = content.recommended_game_version ?? null
		const supported = content.supported_game_versions ?? []
		serverSupportedVersions.value = supported.filter((v) => !!v)
	}

	updateServerPlayState()
}

await fetchProjectData()

let unlistenProcesses
process_listener((e) => {
	if (
		e.event === 'finished' &&
		serverInstancePath.value &&
		e.instance_id === serverInstancePath.value
	) {
		serverPlaying.value = false
	}
}).then((unlisten) => {
	unlistenProcesses = unlisten
})

onUnmounted(() => {
	unlistenProcesses?.()
})

watch(
	() => route.params.id,
	async () => {
		if (route.params.id && route.path.startsWith('/project')) {
			await fetchProjectData()
		}
	},
)

async function install(version) {
	if (serverProjectInstallContext.value && data.value) {
		if (serverProjectSelected.value) {
			serverInstallContent.removeQueuedServerInstall(data.value.id)
			return
		}
		if (installButtonDisabled.value) return

		installing.value = true
		try {
			const contentType = data.value.project_type
			await requestInstall({
				project: {
					...data.value,
					project_id: data.value.id,
					icon_url: data.value.icon_url,
				},
				contentType,
				mode: contentType === 'modpack' ? 'immediate' : 'queue',
				selectedFilters: [],
				providedFilters: [],
				overriddenProvidedFilterTypes: [],
				targetPreferences: getTargetInstallPreferences(
					{
						gameVersion: serverInstallContent.serverContextServerData.value?.mc_version,
						loader: serverInstallContent.serverContextServerData.value?.loader,
					},
					contentType,
				),
				getProjectVersions: async () => versions.value,
				queue: {
					get: serverInstallContent.getQueuedServerInstallPlans,
					set: serverInstallContent.setQueuedServerInstallPlans,
				},
				install: (plan) =>
					serverInstallContent.openServerModpackInstallFlow({
						projectId: plan.projectId,
						versionId: plan.versionId,
						name: plan.project.title ?? plan.project.name ?? data.value.title,
						iconUrl: plan.project.icon_url ?? undefined,
					}),
			})
		} catch (err) {
			handleError(err)
		} finally {
			installing.value = false
		}
		return
	}

	installing.value = true
	await installVersion(
		data.value.id,
		version,
		instance.value ? instance.value.id : null,
		'ProjectPage',
		(version, installedProjectIds) => {
			installing.value = false

			const installedIds = installedProjectIds ?? [data.value.id]
			if (instance.value && version && installedIds.includes(data.value.id)) {
				installed.value = true
				installedVersion.value = version
			}
		},
		(profile) => {
			router.push(`/instance/${profile}`)
		},
	).catch(handleError)
}

const options = ref(null)
const handleRightClick = (event) => {
	options.value.showMenu(event, data.value, [
		{
			name: 'install',
		},
		{
			type: 'divider',
		},
		{
			name: 'open_link',
		},
		{
			name: 'copy_link',
		},
	])
}
const handleOptionsClick = (args) => {
	switch (args.option) {
		case 'install':
			install(null)
			break
		case 'open_link':
			openUrl(`https://modrinth.com/${args.item.project_type}/${args.item.slug}`)
			break
		case 'copy_link':
			navigator.clipboard.writeText(
				`https://modrinth.com/${args.item.project_type}/${args.item.slug}`,
			)
			break
	}
}
</script>

<style scoped lang="scss">
.root-container {
	display: flex;
	flex-direction: row;
	min-height: 100%;
}

.project-sidebar {
	position: fixed;
	width: calc(300px + 1.5rem);
	min-height: calc(100vh - 3.25rem);
	height: fit-content;
	max-height: calc(100vh - 3.25rem);
	padding: 1rem 0.5rem 1rem 1rem;
	overflow-y: auto;
	-ms-overflow-style: none;
	scrollbar-width: none;

	&::-webkit-scrollbar {
		width: 0;
		background: transparent;
	}
}

.sidebar-card {
	display: flex;
	flex-direction: column;
	gap: 1rem;
}

.content-container {
	display: flex;
	flex-direction: column;
	width: 100%;
	padding: 1rem;
	margin-left: calc(300px + 1rem);
}

.button-group {
	display: flex;
	flex-wrap: wrap;
	flex-direction: row;
	gap: 0.5rem;
}

.stats {
	display: flex;
	flex-direction: column;
	flex-wrap: wrap;
	gap: var(--gap-md);

	.stat {
		display: flex;
		flex-direction: row;
		align-items: center;
		width: fit-content;
		gap: var(--gap-xs);
		--stat-strong-size: 1.25rem;

		strong {
			font-size: var(--stat-strong-size);
		}

		p {
			margin: 0;
		}

		svg {
			min-height: var(--stat-strong-size);
			min-width: var(--stat-strong-size);
		}
	}

	.date {
		margin-top: auto;
	}
}

.tabs {
	display: flex;
	flex-direction: row;
	gap: 1rem;
	margin-bottom: var(--gap-md);
	justify-content: space-between;

	.tab {
		display: flex;
		flex-direction: row;
		align-items: center;
		border-radius: var(--border-radius);
		cursor: pointer;
		transition: background-color 0.2s ease-in-out;

		&:hover {
			background-color: var(--color-raised-bg);
		}

		&.router-view-active {
			background-color: var(--color-raised-bg);
		}
	}
}

.links {
	a {
		display: inline-flex;
		align-items: center;
		border-radius: 1rem;
		color: var(--color-text);

		svg,
		img {
			height: 1rem;
			width: 1rem;
		}

		span {
			margin-left: 0.25rem;
			text-decoration: underline;
			line-height: 2rem;
		}

		&:focus-visible,
		&:hover {
			svg,
			img,
			span {
				color: var(--color-heading);
			}
		}

		&:active {
			svg,
			img,
			span {
				color: var(--color-text-dark);
			}
		}

		&:not(:last-child)::after {
			content: '•';
			margin: 0 0.25rem;
		}
	}
}

.install-loading {
	scale: 0.2;
	height: 1rem;
	width: 1rem;
	margin-right: -1rem;

	:deep(svg) {
		color: var(--color-contrast);
	}
}

.project-sidebar-section {
	@apply p-4 flex flex-col gap-2 border-0 border-b-[1px] border-[--brand-gradient-border] border-solid;
}
</style>
