<template>
	<div
		class="rghtznwe"
		:class="{ draghover }"
		draggable="true"
		:title="title"
		@click="onClick"
		@contextmenu.stop="onContextmenu"
		@mouseover="onMouseover"
		@mouseout="onMouseout"
		@dragover.prevent.stop="onDragover"
		@dragenter.prevent="onDragenter"
		@dragleave="onDragleave"
		@drop.prevent.stop="onDrop"
		@dragstart="onDragstart"
		@dragend="onDragend"
	>
		<p class="name">
			<template v-if="hover"
				><i class="ph-folder-notch-open ph-bold ph-lg ph-fw ph-lg"></i
			></template>
			<template v-if="!hover"
				><i class="ph-folder-notch ph-bold ph-lg ph-fw ph-lg"></i
			></template>
			{{ folder.name }}
		</p>
		<p v-if="defaultStore.state.uploadFolder == folder.id" class="upload">
			{{ i18n.ts.uploadFolder }}
		</p>
		<button
			v-if="selectMode"
			class="checkbox _button"
			:class="{ checked: isSelected }"
			@click.prevent.stop="checkboxClicked"
		></button>
	</div>
</template>

<script lang="ts" setup>
import { computed, defineAsyncComponent, ref } from "vue";
import * as Misskey from "iceshrimp-sdk";
import * as os from "@/os";
import { i18n } from "@/i18n";
import { defaultStore } from "@/store";

const props = withDefaults(
	defineProps<{
		folder: Misskey.entities.DriveFolder;
		isSelected?: boolean;
		selectMode?: boolean;
	}>(),
	{
		isSelected: false,
		selectMode: false,
	},
);

const emit = defineEmits<{
	(ev: "chosen", v: Misskey.entities.DriveFolder): void;
	(ev: "move", v: Misskey.entities.DriveFolder): void;
	(ev: "upload", file: File, folder: Misskey.entities.DriveFolder);
	(ev: "removeFile", v: Misskey.entities.DriveFile["id"]): void;
	(ev: "removeFolder", v: Misskey.entities.DriveFolder["id"]): void;
	(ev: "dragstart"): void;
	(ev: "dragend"): void;
}>();

const hover = ref(false);
const draghover = ref(false);
const isDragging = ref(false);

const title = computed(() => props.folder.name);

function checkboxClicked() {
	emit("chosen", props.folder);
}

function onClick() {
	emit("move", props.folder);
}

function onMouseover() {
	hover.value = true;
}

function onMouseout() {
	hover.value = false;
}

function onDragover(ev: DragEvent) {
	if (!ev.dataTransfer) return;

	// 自分自身がドラッグされている場合
	if (isDragging.value) {
		// 自分自身にはドロップさせない
		ev.dataTransfer.dropEffect = "none";
		return;
	}

	const isFile = ev.dataTransfer.items[0].kind === "file";
	const isDriveFile = ev.dataTransfer.types[0] === _DATA_TRANSFER_DRIVE_FILE_;
	const isDriveFolder =
		ev.dataTransfer.types[0] === _DATA_TRANSFER_DRIVE_FOLDER_;

	if (isFile || isDriveFile || isDriveFolder) {
		ev.dataTransfer.dropEffect =
			ev.dataTransfer.effectAllowed === "all" ? "copy" : "move";
	} else {
		ev.dataTransfer.dropEffect = "none";
	}
}

function onDragenter() {
	if (!isDragging.value) draghover.value = true;
}

function onDragleave() {
	draghover.value = false;
}

function onDrop(ev: DragEvent) {
	draghover.value = false;

	if (!ev.dataTransfer) return;

	// ファイルだったら
	if (ev.dataTransfer.files.length > 0) {
		for (const file of Array.from(ev.dataTransfer.files)) {
			emit("upload", file, props.folder);
		}
		return;
	}

	//#region ドライブのファイル
	const driveFile = ev.dataTransfer.getData(_DATA_TRANSFER_DRIVE_FILE_);
	if (driveFile != null && driveFile !== "") {
		const file = JSON.parse(driveFile);
		emit("removeFile", file.id);
		os.api("drive/files/update", {
			fileId: file.id,
			folderId: props.folder.id,
		});
	}
	//#endregion

	//#region ドライブのフォルダ
	const driveFolder = ev.dataTransfer.getData(_DATA_TRANSFER_DRIVE_FOLDER_);
	if (driveFolder != null && driveFolder !== "") {
		const folder = JSON.parse(driveFolder);

		// 移動先が自分自身ならreject
		if (folder.id === props.folder.id) return;

		emit("removeFolder", folder.id);
		os.api("drive/folders/update", {
			folderId: folder.id,
			parentId: props.folder.id,
		})
			.then(() => {
				// noop
			})
			.catch((err) => {
				switch (err) {
					case "detected-circular-definition":
						os.alert({
							title: i18n.ts.unableToProcess,
							text: i18n.ts.circularReferenceFolder,
						});
						break;
					default:
						os.alert({
							type: "error",
							text: i18n.ts.somethingHappened,
						});
				}
			});
	}
	//#endregion
}

function onDragstart(ev: DragEvent) {
	if (!ev.dataTransfer) return;

	ev.dataTransfer.effectAllowed = "move";
	ev.dataTransfer.setData(
		_DATA_TRANSFER_DRIVE_FOLDER_,
		JSON.stringify(props.folder),
	);
	isDragging.value = true;

	// 親ブラウザに対して、ドラッグが開始されたフラグを立てる
	// (=あなたの子供が、ドラッグを開始しましたよ)
	emit("dragstart");
}

function onDragend() {
	isDragging.value = false;
	emit("dragend");
}

function go() {
	emit("move", props.folder.id);
}

function rename() {
	os.inputText({
		title: i18n.ts.renameFolder,
		placeholder: i18n.ts.inputNewFolderName,
		default: props.folder.name,
	}).then(({ canceled, result: name }) => {
		if (canceled) return;
		os.api("drive/folders/update", {
			folderId: props.folder.id,
			name: name,
		});
	});
}

function deleteFolder() {
	os.api("drive/folders/delete", {
		folderId: props.folder.id,
	})
		.then(() => {
			if (defaultStore.state.uploadFolder === props.folder.id) {
				defaultStore.set("uploadFolder", null);
			}
		})
		.catch((err) => {
			switch (err.id) {
				case "b0fc8a17-963c-405d-bfbc-859a487295e1":
					os.alert({
						type: "error",
						title: i18n.ts.unableToDelete,
						text: i18n.ts.hasChildFilesOrFolders,
					});
					break;
				default:
					os.alert({
						type: "error",
						text: i18n.ts.unableToDelete,
					});
			}
		});
}

function setAsUploadFolder() {
	defaultStore.set("uploadFolder", props.folder.id);
}

function onContextmenu(ev: MouseEvent) {
	os.contextMenu(
		[
			{
				text: i18n.ts.openInWindow,
				icon: "ph-copy ph-bold ph-lg",
				action: () => {
					os.popup(
						defineAsyncComponent(
							() => import("@/components/MkDriveWindow.vue"),
						),
						{
							initialFolder: props.folder,
						},
						{},
						"closed",
					);
				},
			},
			null,
			{
				text: i18n.ts.rename,
				icon: "ph-cursor-text ph-bold ph-lg",
				action: rename,
			},
			null,
			{
				text: i18n.ts.delete,
				icon: "ph-trash ph-bold ph-lg",
				danger: true,
				action: deleteFolder,
			},
		],
		ev,
	);
}
</script>

<style lang="scss" scoped>
.rghtznwe {
	position: relative;
	padding: 8px;
	height: 64px;
	background: var(--driveFolderBg);
	border-radius: 4px;

	&,
	* {
		cursor: pointer;
	}

	*:not(.checkbox) {
		pointer-events: none;
	}

	> .checkbox {
		position: absolute;
		bottom: 8px;
		right: 8px;
		width: 16px;
		height: 16px;
		background: #fff;
		border: solid 1px #000;

		&.checked {
			background: var(--accent);
		}
	}

	&.draghover {
		&:after {
			content: "";
			pointer-events: none;
			position: absolute;
			top: -4px;
			right: -4px;
			bottom: -4px;
			left: -4px;
			border: 2px dashed var(--focus);
			border-radius: 4px;
		}
	}

	> .name {
		margin: 0;
		font-size: 0.9em;
		color: var(--desktopDriveFolderFg);

		> i {
			margin-right: 4px;
			margin-left: 2px;
			text-align: left;
		}
	}

	> .upload {
		margin: 4px 4px;
		font-size: 0.8em;
		text-align: right;
		color: var(--desktopDriveFolderFg);
	}
}
</style>
