<template>
	<div class="relative h-full w-full overflow-y-auto">
		<div v-if="data" class="flex h-full w-full flex-col">
			<div class="gap-2">
				<div class="card flex flex-col gap-4">
					<label for="server-name-field" class="flex flex-col gap-2">
						<span class="text-lg font-bold text-contrast">Server name</span>
						<span> This name is only visible on Modrinth.</span>
					</label>
					<div class="flex flex-col gap-2">
						<input
							id="server-name-field"
							v-model="serverName"
							class="w-full md:w-[50%]"
							maxlength="48"
							minlength="1"
							@keyup.enter="!serverName && saveGeneral"
						/>
						<span v-if="!serverName" class="text-sm text-rose-400">
							Server name must be at least 1 character long.
						</span>
						<span v-if="!isValidServerName" class="text-sm text-rose-400">
							Server name can contain any character.
						</span>
					</div>
				</div>
				<!-- WIP - disable for now
        <div class="card flex flex-col gap-4">
          <label for="server-motd-field" class="flex flex-col gap-2">
            <span class="text-lg font-bold text-contrast">Server MOTD</span>
            <span>
              The message of the day is the message that players see when they log in to the server.
            </span>
          </label>
          <UiServersMOTDEditor :server="props.server" />
        </div>
        -->

				<div class="card flex flex-col gap-4">
					<label for="server-subdomain" class="flex flex-col gap-2">
						<span class="text-lg font-bold text-contrast">Custom URL</span>
						<span> Your friends can connect to your server using this URL. </span>
					</label>
					<div class="flex w-full items-center gap-2 md:w-[60%]">
						<input
							id="server-subdomain"
							v-model="serverSubdomain"
							class="h-[50%] w-[63%]"
							maxlength="32"
							@keyup.enter="saveGeneral"
						/>
						.modrinth.gg
					</div>
					<div v-if="!isValidSubdomain" class="flex flex-col text-sm text-rose-400">
						<span v-if="!isValidLengthSubdomain">
							Subdomain must be at least 5 characters long.
						</span>
						<span v-if="!isValidCharsSubdomain">
							Subdomain can only contain alphanumeric characters and dashes.
						</span>
					</div>
				</div>

				<div v-if="!data.is_medal" class="card flex flex-col gap-4">
					<label for="server-icon-field" class="flex flex-col gap-2">
						<span class="text-lg font-bold text-contrast">Server icon</span>
						<span> This icon will be visible on the Minecraft server list and on Modrinth. </span>
					</label>
					<div class="flex gap-4">
						<div
							v-tooltip="'Upload a custom Icon'"
							class="group relative flex w-fit cursor-pointer items-center gap-2 rounded-xl bg-table-alternateRow"
							@dragover.prevent="onDragOver"
							@dragleave.prevent="onDragLeave"
							@drop.prevent="onDrop"
							@click="triggerFileInput"
						>
							<input
								v-if="icon"
								id="server-icon-field"
								type="file"
								accept="image/png,image/jpeg,image/gif,image/webp"
								hidden
								@change="uploadFile"
							/>
							<div
								class="absolute top-0 hidden size-24 flex-col items-center justify-center rounded-xl bg-button-bg p-2 opacity-80 group-hover:flex"
							>
								<EditIcon class="h-8 w-8 text-contrast" />
							</div>
							<ServerIcon class="size-24" :image="icon" />
						</div>
						<ButtonStyled>
							<button
								v-tooltip="'Synchronize icon with installed modpack'"
								class="my-auto"
								@click="resetIcon"
							>
								<TransferIcon /> Sync icon
							</button>
						</ButtonStyled>
					</div>
				</div>
			</div>
		</div>
		<div v-else />
		<SaveBanner
			:is-visible="!!hasUnsavedChanges && !!isValidServerName"
			:server="props.server"
			:is-updating="isUpdating"
			:save="saveGeneral"
			:reset="resetGeneral"
		/>
	</div>
</template>

<script setup lang="ts">
import { EditIcon, TransferIcon } from '@modrinth/assets'
import { injectModrinthClient, injectNotificationManager, ServerIcon } from '@modrinth/ui'
import ButtonStyled from '@modrinth/ui/src/components/base/ButtonStyled.vue'

import SaveBanner from '~/components/ui/servers/SaveBanner.vue'
import type { ModrinthServer } from '~/composables/servers/modrinth-servers.ts'

const { addNotification } = injectNotificationManager()
const client = injectModrinthClient()

const props = defineProps<{
	server: ModrinthServer
}>()

const data = computed(() => props.server.general)
const serverName = ref(data.value?.name)
const serverSubdomain = ref(data.value?.net?.domain ?? '')
const isValidLengthSubdomain = computed(() => serverSubdomain.value.length >= 5)
const isValidCharsSubdomain = computed(() => /^[a-zA-Z0-9-]+$/.test(serverSubdomain.value))
const isValidSubdomain = computed(() => isValidLengthSubdomain.value && isValidCharsSubdomain.value)
const icon = computed(() => data.value?.image)

const isUpdating = ref(false)
const hasUnsavedChanges = computed(
	() =>
		(serverName.value && serverName.value !== data.value?.name) ||
		serverSubdomain.value !== data.value?.net?.domain,
)
const isValidServerName = computed(() => (serverName.value?.length ?? 0) > 0)

watch(serverName, (oldValue) => {
	if (!isValidServerName.value) {
		serverName.value = oldValue
	}
})

const saveGeneral = async () => {
	if (!isValidServerName.value || !isValidSubdomain.value) return

	try {
		isUpdating.value = true
		if (serverName.value !== data.value?.name) {
			await data.value?.updateName(serverName.value ?? '')
		}
		if (serverSubdomain.value !== data.value?.net?.domain) {
			try {
				// type shit backend makes me do
				const available = await props.server.network?.checkSubdomainAvailability(
					serverSubdomain.value,
				)

				if (!available) {
					addNotification({
						type: 'error',
						title: 'Subdomain not available',
						text: 'The subdomain you entered is already in use.',
					})
					return
				}

				await props.server.network?.changeSubdomain(serverSubdomain.value)
			} catch (error) {
				console.error('Error checking subdomain availability:', error)
				addNotification({
					type: 'error',
					title: 'Error checking availability',
					text: 'Failed to verify if the subdomain is available.',
				})
				return
			}
		}
		await new Promise((resolve) => setTimeout(resolve, 500))
		await props.server.refresh()
		addNotification({
			type: 'success',
			title: 'Server settings updated',
			text: 'Your server settings were successfully changed.',
		})
	} catch (error) {
		console.error(error)
		addNotification({
			type: 'error',
			title: 'Failed to update server settings',
			text: 'An error occurred while attempting to update your server settings.',
		})
	} finally {
		isUpdating.value = false
	}
}

const resetGeneral = () => {
	serverName.value = data.value?.name || ''
	serverSubdomain.value = data.value?.net?.domain ?? ''
}

const uploadFile = async (e: Event) => {
	const file = (e.target as HTMLInputElement).files?.[0]
	if (!file) {
		addNotification({
			type: 'error',
			title: 'No file selected',
			text: 'Please select a file to upload.',
		})
		return
	}

	const scaledFile = await new Promise<File>((resolve, reject) => {
		const canvas = document.createElement('canvas')
		const ctx = canvas.getContext('2d')
		const img = new Image()
		img.onload = () => {
			canvas.width = 64
			canvas.height = 64
			ctx?.drawImage(img, 0, 0, 64, 64)
			canvas.toBlob((blob) => {
				if (blob) {
					resolve(new File([blob], 'server-icon.png', { type: 'image/png' }))
				} else {
					reject(new Error('Canvas toBlob failed'))
				}
			}, 'image/png')
			URL.revokeObjectURL(img.src)
		}
		img.onerror = reject
		img.src = URL.createObjectURL(file)
	})

	try {
		if (data.value?.image) {
			await client.kyros.files_v0.deleteFileOrFolder('/server-icon.png', false)
			await client.kyros.files_v0.deleteFileOrFolder('/server-icon-original.png', false)
		}

		await client.kyros.files_v0.uploadFile('/server-icon.png', scaledFile).promise
		await client.kyros.files_v0.uploadFile('/server-icon-original.png', file).promise

		const canvas = document.createElement('canvas')
		const ctx = canvas.getContext('2d')
		const img = new Image()
		await new Promise<void>((resolve) => {
			img.onload = () => {
				canvas.width = 512
				canvas.height = 512
				ctx?.drawImage(img, 0, 0, 512, 512)
				const dataURL = canvas.toDataURL('image/png')
				useState(`server-icon-${props.server.serverId}`).value = dataURL
				if (data.value) data.value.image = dataURL
				resolve()
				URL.revokeObjectURL(img.src)
			}
			img.src = URL.createObjectURL(file)
		})

		addNotification({
			type: 'success',
			title: 'Server icon updated',
			text: 'Your server icon was successfully changed.',
		})
	} catch (error) {
		console.error('Error uploading icon:', error)
		addNotification({
			type: 'error',
			title: 'Upload failed',
			text: 'Failed to upload server icon.',
		})
	}
}

const resetIcon = async () => {
	if (data.value?.image) {
		try {
			await client.kyros.files_v0.deleteFileOrFolder('/server-icon.png', false)
			await client.kyros.files_v0.deleteFileOrFolder('/server-icon-original.png', false)

			useState(`server-icon-${props.server.serverId}`).value = undefined
			if (data.value) data.value.image = undefined

			await props.server.refresh(['general'])

			addNotification({
				type: 'success',
				title: 'Server icon reset',
				text: 'Your server icon was successfully reset.',
			})
		} catch (error) {
			console.error('Error resetting icon:', error)
			addNotification({
				type: 'error',
				title: 'Reset failed',
				text: 'Failed to reset server icon.',
			})
		}
	}
}

const onDragOver = (e: DragEvent) => {
	e.preventDefault()
}

const onDragLeave = (e: DragEvent) => {
	e.preventDefault()
}

const onDrop = (e: DragEvent) => {
	e.preventDefault()
	uploadFile(e)
}

const triggerFileInput = () => {
	const input = document.createElement('input')
	input.type = 'file'
	input.id = 'server-icon-field'
	input.accept = 'image/png,image/jpeg,image/gif,image/webp'
	input.onchange = uploadFile
	input.click()
}
</script>
