<template>
	<div>
		<ConfirmModal
			ref="modal_confirm"
			title="Are you sure you want to delete this project?"
			description="If you proceed, all versions and any attached data will be removed from our servers. This may break other projects, so be careful."
			:has-to-type="true"
			:confirmation-text="project.title"
			proceed-label="Delete"
			@proceed="deleteProject"
		/>
		<section class="universal-card">
			<div class="label">
				<h3>
					<span class="label__title size-card-header">Project information</span>
				</h3>
			</div>
			<label for="project-icon">
				<span class="label__title">Icon</span>
			</label>
			<div class="input-group">
				<Avatar
					:src="deletedIcon ? null : previewImage ? previewImage : project.icon_url"
					:alt="project.title"
					size="md"
					class="project__icon"
				/>
				<div class="input-stack">
					<FileInput
						id="project-icon"
						:max-size="262144"
						:show-icon="true"
						accept="image/png,image/jpeg,image/gif,image/webp"
						class="choose-image iconified-button"
						prompt="Upload icon"
						aria-label="Upload icon"
						:disabled="!hasPermission"
						@change="showPreviewImage"
					>
						<UploadIcon aria-hidden="true" />
					</FileInput>
					<button
						v-if="!deletedIcon && (previewImage || project.icon_url)"
						class="iconified-button"
						:disabled="!hasPermission"
						@click="markIconForDeletion"
					>
						<TrashIcon aria-hidden="true" />
						Remove icon
					</button>
				</div>
			</div>

			<label for="project-name">
				<span class="label__title">Name</span>
			</label>
			<input
				id="project-name"
				v-model="name"
				maxlength="2048"
				type="text"
				:disabled="!hasPermission"
			/>

			<label for="project-slug">
				<span class="label__title">URL</span>
			</label>
			<div class="text-input-wrapper">
				<div class="text-input-wrapper__before">
					<span class="hidden sm:inline">https://modrinth.com</span>/{{
						$getProjectTypeForUrl(project.project_type, project.loaders)
					}}/
				</div>
				<input
					id="project-slug"
					v-model="slug"
					type="text"
					maxlength="64"
					autocomplete="off"
					:disabled="!hasPermission"
				/>
			</div>

			<label for="project-summary">
				<span class="label__title">Summary</span>
			</label>
			<div v-if="summaryWarning" class="my-2 flex items-center gap-1.5 text-orange">
				<TriangleAlertIcon class="my-auto" />
				{{ summaryWarning }}
			</div>
			<div class="textarea-wrapper summary-input">
				<textarea
					id="project-summary"
					v-model="summary"
					maxlength="256"
					:disabled="!hasPermission"
				/>
			</div>
			<template
				v-if="
					!flags.newProjectEnvironmentSettings &&
					project.versions?.length !== 0 &&
					project.project_type !== 'resourcepack' &&
					project.project_type !== 'plugin' &&
					project.project_type !== 'shader' &&
					project.project_type !== 'datapack'
				"
			>
				<div class="adjacent-input">
					<label for="project-env-client">
						<span class="label__title">Client-side</span>
						<span class="label__description">
							Select based on if the
							{{ formatProjectType(project.project_type).toLowerCase() }} has functionality on the
							client side. Just because a mod works in Singleplayer doesn't mean it has actual
							client-side functionality.
						</span>
					</label>
					<Multiselect
						id="project-env-client"
						v-model="clientSide"
						class="small-multiselect"
						placeholder="Select one"
						:options="sideTypes"
						:custom-label="(value) => value.charAt(0).toUpperCase() + value.slice(1)"
						:searchable="false"
						:close-on-select="true"
						:show-labels="false"
						:allow-empty="false"
						:disabled="!hasPermission"
					/>
				</div>
				<div class="adjacent-input">
					<label for="project-env-server">
						<span class="label__title">Server-side</span>
						<span class="label__description">
							Select based on if the
							{{ formatProjectType(project.project_type).toLowerCase() }} has functionality on the
							<strong>logical</strong> server. Remember that Singleplayer contains an integrated
							server.
						</span>
					</label>
					<Multiselect
						id="project-env-server"
						v-model="serverSide"
						class="small-multiselect"
						placeholder="Select one"
						:options="sideTypes"
						:custom-label="(value) => value.charAt(0).toUpperCase() + value.slice(1)"
						:searchable="false"
						:close-on-select="true"
						:show-labels="false"
						:allow-empty="false"
						:disabled="!hasPermission"
					/>
				</div>
			</template>
			<div class="adjacent-input">
				<label for="project-visibility">
					<span class="label__title">Visibility</span>
					<div class="label__description">
						Public and archived projects are visible in search. Unlisted projects are published, but
						not visible in search or on user profiles. Private projects are only accessible by
						members of the project.

						<p>If approved by the moderators:</p>
						<ul class="visibility-info">
							<li>
								<CheckIcon
									v-if="visibility === 'approved' || visibility === 'archived'"
									class="good"
								/>
								<XIcon v-else class="bad" />
								{{ hasModifiedVisibility() ? 'Will be v' : 'V' }}isible in search
							</li>
							<li>
								<XIcon v-if="visibility === 'unlisted' || visibility === 'private'" class="bad" />
								<CheckIcon v-else class="good" />
								{{ hasModifiedVisibility() ? 'Will be v' : 'V' }}isible on profile
							</li>
							<li>
								<CheckIcon v-if="visibility !== 'private'" class="good" />
								<IssuesIcon
									v-else
									v-tooltip="{
										content:
											visibility === 'private'
												? 'Only members will be able to view the project.'
												: '',
									}"
									class="warn"
								/>
								{{ hasModifiedVisibility() ? 'Will be v' : 'V' }}isible via URL
							</li>
						</ul>
					</div>
				</label>
				<Multiselect
					id="project-visibility"
					v-model="visibility"
					class="small-multiselect"
					placeholder="Select one"
					:options="tags.approvedStatuses"
					:custom-label="(value) => formatProjectStatus(value)"
					:searchable="false"
					:close-on-select="true"
					:show-labels="false"
					:allow-empty="false"
					:disabled="!hasPermission"
				/>
			</div>
			<div class="button-group">
				<button
					type="button"
					class="iconified-button brand-button"
					:disabled="!hasChanges"
					@click="saveChanges()"
				>
					<SaveIcon aria-hidden="true" />
					Save changes
				</button>
			</div>
		</section>

		<section class="universal-card">
			<div class="label">
				<h3>
					<span class="label__title size-card-header">Delete project</span>
				</h3>
			</div>
			<p>
				Removes your project from Modrinth's servers and search. Clicking on this will delete your
				project, so be extra careful!
			</p>
			<button
				type="button"
				class="iconified-button danger-button"
				:disabled="!hasDeletePermission"
				@click="$refs.modal_confirm.show()"
			>
				<TrashIcon aria-hidden="true" />
				Delete project
			</button>
		</section>
	</div>
</template>

<script setup>
import {
	CheckIcon,
	IssuesIcon,
	SaveIcon,
	TrashIcon,
	TriangleAlertIcon,
	UploadIcon,
	XIcon,
} from '@modrinth/assets'
import { MIN_SUMMARY_CHARS } from '@modrinth/moderation'
import { Avatar, ConfirmModal, injectNotificationManager } from '@modrinth/ui'
import { formatProjectStatus, formatProjectType } from '@modrinth/utils'
import { Multiselect } from 'vue-multiselect'

import FileInput from '~/components/ui/FileInput.vue'
import { useFeatureFlags } from '~/composables/featureFlags.ts'

const { addNotification } = injectNotificationManager()

const flags = useFeatureFlags()

const props = defineProps({
	project: {
		type: Object,
		required: true,
		default: () => ({}),
	},
	projectV3: {
		type: Object,
		required: true,
		default: () => ({}),
	},
	currentMember: {
		type: Object,
		required: true,
		default: () => ({}),
	},
	patchProject: {
		type: Function,
		required: true,
		default: () => {},
	},
	patchIcon: {
		type: Function,
		required: true,
		default: () => {},
	},
	resetProject: {
		type: Function,
		required: true,
		default: () => {},
	},
})

const tags = useTags()
const router = useNativeRouter()

const name = ref(props.project.title)
const slug = ref(props.project.slug)
const summary = ref(props.project.description)
const icon = ref(null)
const previewImage = ref(null)
const clientSide = ref(props.project.client_side)
const serverSide = ref(props.project.server_side)
const deletedIcon = ref(false)
const visibility = ref(
	tags.value.approvedStatuses.includes(props.project.status)
		? props.project.status
		: props.project.requested_status,
)

const hasPermission = computed(() => {
	const EDIT_DETAILS = 1 << 2
	return (props.currentMember.permissions & EDIT_DETAILS) === EDIT_DETAILS
})

const hasDeletePermission = computed(() => {
	const DELETE_PROJECT = 1 << 7
	return (props.currentMember.permissions & DELETE_PROJECT) === DELETE_PROJECT
})

const summaryWarning = computed(() => {
	const text = summary.value?.trim() || ''
	const charCount = text.length

	if (charCount < MIN_SUMMARY_CHARS) {
		return `It's recommended to have a summary with at least ${MIN_SUMMARY_CHARS} characters. (${charCount}/${MIN_SUMMARY_CHARS})`
	}

	return null
})

const sideTypes = ['required', 'optional', 'unsupported']

const patchData = computed(() => {
	const data = {}

	if (name.value !== props.project.title) {
		data.title = name.value.trim()
	}
	if (slug.value !== props.project.slug) {
		data.slug = slug.value.trim()
	}
	if (summary.value !== props.project.description) {
		data.description = summary.value.trim()
	}
	if (clientSide.value !== props.project.client_side) {
		data.client_side = clientSide.value
	}
	if (serverSide.value !== props.project.server_side) {
		data.server_side = serverSide.value
	}
	if (tags.value.approvedStatuses.includes(props.project.status)) {
		if (visibility.value !== props.project.status) {
			data.status = visibility.value
		}
	} else if (visibility.value !== props.project.requested_status) {
		data.requested_status = visibility.value
	}

	return data
})

const hasChanges = computed(() => {
	return Object.keys(patchData.value).length > 0 || deletedIcon.value || icon.value
})

const hasModifiedVisibility = () => {
	const originalVisibility = tags.value.approvedStatuses.includes(props.project.status)
		? props.project.status
		: props.project.requested_status

	return originalVisibility !== visibility.value
}

const saveChanges = async () => {
	if (hasChanges.value) {
		await props.patchProject(patchData.value)
	}

	if (deletedIcon.value) {
		await deleteIcon()
		deletedIcon.value = false
	} else if (icon.value) {
		await props.patchIcon(icon.value)
		icon.value = null
	}
}

const showPreviewImage = (files) => {
	const reader = new FileReader()
	icon.value = files[0]
	deletedIcon.value = false
	reader.readAsDataURL(icon.value)
	reader.onload = (event) => {
		previewImage.value = event.target.result
	}
}

const deleteProject = async () => {
	await useBaseFetch(`project/${props.project.id}`, {
		method: 'DELETE',
	})
	await initUserProjects()
	await router.push('/dashboard/projects')
	addNotification({
		title: 'Project deleted',
		text: 'Your project has been deleted.',
		type: 'success',
	})
}

const markIconForDeletion = () => {
	deletedIcon.value = true
	icon.value = null
	previewImage.value = null
}

const deleteIcon = async () => {
	await useBaseFetch(`project/${props.project.id}/icon`, {
		method: 'DELETE',
	})
	await props.resetProject()
	addNotification({
		title: 'Project icon removed',
		text: "Your project's icon has been removed.",
		type: 'success',
	})
}
</script>
<style lang="scss" scoped>
.visibility-info {
	padding: 0;
	list-style: none;

	li {
		display: flex;
		align-items: center;
		gap: var(--spacing-card-xs);
	}
}

svg {
	&.good {
		color: var(--color-green);
	}

	&.bad {
		color: var(--color-red);
	}

	&.warn {
		color: var(--color-orange);
	}
}

.summary-input {
	min-height: 8rem;
	max-width: 24rem;
}

.small-multiselect {
	max-width: 15rem;
}

.button-group {
	justify-content: flex-start;
}
</style>
