<template>
	<JavaDetectionModal ref="detectJavaModal" @submit="(val) => emit('update:modelValue', val)" />
	<div :id="props.id" class="toggle-setting" :class="{ compact }">
		<div class="input-with-status">
			<StyledInput
				autocomplete="off"
				:disabled="props.disabled"
				:model-value="props.modelValue ? props.modelValue.path : ''"
				:placeholder="placeholder ?? formatMessage(messages.pathPlaceholder)"
				wrapper-class="installation-input"
				@update:model-value="
					(val) => {
						emit('update:modelValue', {
							...props.modelValue,
							path: val,
						})
					}
				"
			/>
			<ButtonStyled
				:color="
					!hoveringTest && !testingJava
						? testingJavaSuccess === true
							? 'green'
							: 'red'
						: 'standard'
				"
				color-fill="text"
			>
				<button
					:aria-label="formatMessage(messages.testJavaInstallation)"
					class="!shadow-none"
					:disabled="testingJava || props.disabled"
					@click="runTest(props.modelValue?.path)"
					@mouseenter="!props.disabled && (hoveringTest = true)"
					@mouseleave="hoveringTest = false"
				>
					<SpinnerIcon v-if="testingJava" class="animate-spin h-4 w-4" />
					<CheckCircleIcon
						v-else-if="testingJavaSuccess === true && !hoveringTest"
						class="h-4 w-4"
					/>
					<XCircleIcon v-else-if="testingJavaSuccess !== true && !hoveringTest" class="h-4 w-4" />
					<RefreshCwIcon v-else-if="!props.disabled" class="h-4 w-4" />
				</button>
			</ButtonStyled>
		</div>
		<span class="installation-buttons">
			<ButtonStyled v-if="props.version">
				<button
					v-tooltip="
						testingJavaSuccess === true ? formatMessage(messages.alreadyInstalled) : undefined
					"
					class="!shadow-none"
					:disabled="props.disabled || installingJava || testingJavaSuccess === true"
					@click="reinstallJava"
				>
					<DownloadIcon />
					{{
						installingJava
							? formatMessage(messages.installing)
							: formatMessage(messages.installRecommended)
					}}
				</button>
			</ButtonStyled>
			<ButtonStyled>
				<button class="!shadow-none" :disabled="props.disabled" @click="autoDetect">
					<SearchIcon />
					{{ formatMessage(messages.detect) }}
				</button>
			</ButtonStyled>
			<ButtonStyled>
				<button class="!shadow-none" :disabled="props.disabled" @click="handleJavaFileInput()">
					<FolderSearchIcon />
					{{ formatMessage(messages.browse) }}
				</button>
			</ButtonStyled>
		</span>
	</div>
</template>

<script setup>
import {
	CheckCircleIcon,
	DownloadIcon,
	FolderSearchIcon,
	RefreshCwIcon,
	SearchIcon,
	SpinnerIcon,
	XCircleIcon,
} from '@modrinth/assets'
import {
	ButtonStyled,
	defineMessages,
	injectNotificationManager,
	StyledInput,
	useVIntl,
} from '@modrinth/ui'
import { open } from '@tauri-apps/plugin-dialog'
import { ref, watch } from 'vue'

import JavaDetectionModal from '@/components/ui/JavaDetectionModal.vue'
import useJavaTest from '@/composables/useJavaTest'
import { trackEvent } from '@/helpers/analytics'
import { auto_install_java, find_filtered_jres, get_jre } from '@/helpers/jre.js'

const { handleError } = injectNotificationManager()
const { formatMessage } = useVIntl()

const messages = defineMessages({
	pathPlaceholder: {
		id: 'app.java-selector.path.placeholder',
		defaultMessage: '/path/to/java',
	},
	testJavaInstallation: {
		id: 'app.java-selector.test-installation',
		defaultMessage: 'Test Java installation',
	},
	alreadyInstalled: {
		id: 'app.java-selector.already-installed',
		defaultMessage: 'Already installed',
	},
	installing: {
		id: 'app.java-selector.installing',
		defaultMessage: 'Installing...',
	},
	installRecommended: {
		id: 'app.java-selector.install-recommended',
		defaultMessage: 'Install recommended',
	},
	detect: {
		id: 'app.java-selector.detect',
		defaultMessage: 'Detect',
	},
	browse: {
		id: 'app.java-selector.browse',
		defaultMessage: 'Browse',
	},
})

const props = defineProps({
	id: {
		type: String,
		required: false,
		default: null,
	},
	version: {
		type: Number,
		required: false,
		default: null,
	},
	modelValue: {
		type: Object,
		default: () => ({
			path: '',
			version: '',
		}),
	},
	disabled: {
		type: Boolean,
		required: false,
		default: false,
	},
	placeholder: {
		type: String,
		required: false,
		default: null,
	},
	compact: {
		type: Boolean,
		default: false,
	},
})

const emit = defineEmits(['update:modelValue'])

const {
	testingJava,
	javaTestResult: testingJavaSuccess,
	testJavaInstallationDebounced,
	testJavaInstallation,
} = useJavaTest()

const installingJava = ref(false)
const hoveringTest = ref(false)
let hasInitialized = false

async function runTest(path) {
	await testJavaInstallation(path, props.version, true)
}

watch(
	() => props.modelValue?.path,
	(newPath) => {
		if (newPath) {
			if (!hasInitialized) {
				testJavaInstallation(newPath, props.version, false)
				hasInitialized = true
			} else {
				testJavaInstallationDebounced(newPath, props.version)
			}
		}
	},
	{ immediate: true },
)

async function handleJavaFileInput() {
	const filePath = await open()

	if (filePath) {
		let result = await get_jre(filePath.path ?? filePath).catch(handleError)
		if (!result) {
			result = {
				path: filePath.path ?? filePath,
				version: props.version.toString(),
				parsed_version: props.version,
				architecture: 'x86',
			}
		}

		trackEvent('JavaManualSelect', {
			version: props.version,
		})

		emit('update:modelValue', result)
	}
}

const detectJavaModal = ref(null)
async function autoDetect() {
	if (!props.compact) {
		detectJavaModal.value.show(props.version, props.modelValue)
	} else {
		const versions = await find_filtered_jres(props.version).catch(handleError)
		if (versions.length > 0) {
			emit('update:modelValue', versions[0])
		}
	}
}

async function reinstallJava() {
	installingJava.value = true
	const path = await auto_install_java(props.version).catch(handleError)
	let result = await get_jre(path)

	if (!result) {
		result = {
			path: path,
			version: props.version.toString(),
			parsed_version: props.version,
			architecture: 'x86',
		}
	}

	trackEvent('JavaReInstall', {
		path: path,
		version: props.version,
	})

	emit('update:modelValue', result)
	installingJava.value = false
	runTest(result.path)
}
</script>

<style lang="scss" scoped>
.input-with-status {
	display: flex;
	flex-direction: row;
	align-items: center;
	gap: 0.5rem;
	width: 100%;
	min-width: 0;
}

.installation-input {
	flex: 1 1 0;
	min-width: 0;
}

.toggle-setting {
	display: flex;
	flex-wrap: wrap;
	flex-direction: row;
	justify-content: space-between;
	align-items: center;
	gap: 0.5rem;

	&.compact {
		flex-wrap: wrap;
	}
}

.installation-buttons {
	display: flex;
	flex-direction: row;
	align-items: center;
	gap: 0.5rem;
	margin: 0;
}
</style>
