<template>
<!-- sectionを利用しているのは、deck.vue側でcolumnに対してfirst-of-typeを効かせるため -->
<section v-hotkey="keymap" class="dnpfarvg _panel _narrow_"
	:class="{ paged: isMainColumn, naked, active, isStacked, draghover, dragging, dropready }"
	:style="{ '--deckColumnHeaderHeight': deckStore.reactiveState.columnHeaderHeight.value + 'px' }"
	@dragover.prevent.stop="onDragover"
	@dragleave="onDragleave"
	@drop.prevent.stop="onDrop"
>
	<header :class="{ indicated }"
		draggable="true"
		@click="goTop"
		@dragstart="onDragstart"
		@dragend="onDragend"
		@contextmenu.prevent.stop="onContextmenu"
	>
		<button v-if="isStacked && !isMainColumn" class="toggleActive _button" @click="toggleActive">
			<template v-if="active"><i class="fas fa-angle-up"></i></template>
			<template v-else><i class="fas fa-angle-down"></i></template>
		</button>
		<div class="action">
			<slot name="action"></slot>
		</div>
		<span class="header"><slot name="header"></slot></span>
		<button v-if="func" v-tooltip="func.title" class="menu _button" @click.stop="func.handler"><i :class="func.icon || 'fas fa-cog'"></i></button>
	</header>
	<div v-show="active" ref="body">
		<slot></slot>
	</div>
</section>
</template>

<script lang="ts">
export type DeckFunc = {
	title: string;
	handler: (payload: MouseEvent) => void;
	icon?: string;
};
</script>
<script lang="ts" setup>
import { onBeforeUnmount, onMounted, provide, watch } from 'vue';
import * as os from '@/os';
import { updateColumn, swapLeftColumn, swapRightColumn, swapUpColumn, swapDownColumn, stackLeftColumn, popRightColumn, removeColumn, swapColumn, Column } from './deck-store';
import { deckStore } from './deck-store';
import { i18n } from '@/i18n';

provide('shouldHeaderThin', true);
provide('shouldOmitHeaderTitle', true);

const props = withDefaults(defineProps<{
	column: Column;
	isStacked?: boolean;
	func?: DeckFunc | null;
	naked?: boolean;
	indicated?: boolean;
}>(), {
	isStacked: false,
	func: null,
	naked: false,
	indicated: false,
});

const emit = defineEmits<{
	(ev: 'parent-focus', direction: 'up' | 'down' | 'left' | 'right'): void;
	(ev: 'change-active-state', v: boolean): void;
}>();

let body = $ref<HTMLDivElement>();

let dragging = $ref(false);
watch($$(dragging), v => os.deckGlobalEvents.emit(v ? 'column.dragStart' : 'column.dragEnd'));

let draghover = $ref(false);
let dropready = $ref(false);

const isMainColumn = $computed(() => props.column.type === 'main');
const active = $computed(() => props.column.active !== false);
watch($$(active), v => emit('change-active-state', v));

const keymap = $computed(() => ({
	'shift+up': () => emit('parent-focus', 'up'),
	'shift+down': () => emit('parent-focus', 'down'),
	'shift+left': () => emit('parent-focus', 'left'),
	'shift+right': () => emit('parent-focus', 'right'),
}));

onMounted(() => {
	os.deckGlobalEvents.on('column.dragStart', onOtherDragStart);
	os.deckGlobalEvents.on('column.dragEnd', onOtherDragEnd);
});

onBeforeUnmount(() => {
	os.deckGlobalEvents.off('column.dragStart', onOtherDragStart);
	os.deckGlobalEvents.off('column.dragEnd', onOtherDragEnd);
});

function onOtherDragStart() {
	dropready = true;
}

function onOtherDragEnd() {
	dropready = false;
}

function toggleActive() {
	if (!props.isStacked) return;
	updateColumn(props.column.id, {
		active: !props.column.active
	});
}

function getMenu() {
	const items = [{
		icon: 'fas fa-pencil-alt',
		text: i18n.ts.edit,
		action: async () => {
			const { canceled, result } = await os.form(props.column.name, {
				name: {
					type: 'string',
					label: i18n.ts.name,
					default: props.column.name
				},
				width: {
					type: 'number',
					label: i18n.ts.width,
					default: props.column.width
				},
				flexible: {
					type: 'boolean',
					label: i18n.ts.flexible,
					default: props.column.flexible
				}
			});
			if (canceled) return;
			updateColumn(props.column.id, result);
		}
	}, null, {
		icon: 'fas fa-arrow-left',
		text: i18n.ts._deck.swapLeft,
		action: () => {
			swapLeftColumn(props.column.id);
		}
	}, {
		icon: 'fas fa-arrow-right',
		text: i18n.ts._deck.swapRight,
		action: () => {
			swapRightColumn(props.column.id);
		}
	}, props.isStacked ? {
		icon: 'fas fa-arrow-up',
		text: i18n.ts._deck.swapUp,
		action: () => {
			swapUpColumn(props.column.id);
		}
	} : undefined, props.isStacked ? {
		icon: 'fas fa-arrow-down',
		text: i18n.ts._deck.swapDown,
		action: () => {
			swapDownColumn(props.column.id);
		}
	} : undefined, null, {
		icon: 'fas fa-window-restore',
		text: i18n.ts._deck.stackLeft,
		action: () => {
			stackLeftColumn(props.column.id);
		}
	}, props.isStacked ? {
		icon: 'fas fa-window-maximize',
		text: i18n.ts._deck.popRight,
		action: () => {
			popRightColumn(props.column.id);
		}
	} : undefined, null, {
		icon: 'fas fa-trash-alt',
		text: i18n.ts.remove,
		danger: true,
		action: () => {
			removeColumn(props.column.id);
		}
	}];
	return items;
}

function onContextmenu(ev: MouseEvent) {
	os.contextMenu(getMenu(), ev);
}

function goTop() {
	body.scrollTo({
		top: 0,
		behavior: 'smooth'
	});
}

function onDragstart(ev) {
	ev.dataTransfer.effectAllowed = 'move';
	ev.dataTransfer.setData(_DATA_TRANSFER_DECK_COLUMN_, props.column.id);

	// Chromeのバグで、Dragstartハンドラ内ですぐにDOMを変更する(=リアクティブなプロパティを変更する)とDragが終了してしまう
	// SEE: https://stackoverflow.com/questions/19639969/html5-dragend-event-firing-immediately
	window.setTimeout(() => {
		dragging = true;
	}, 10);
}

function onDragend(ev) {
	dragging = false;
}

function onDragover(ev) {
	// 自分自身がドラッグされている場合
	if (dragging) {
		// 自分自身にはドロップさせない
		ev.dataTransfer.dropEffect = 'none';
	} else {
		const isDeckColumn = ev.dataTransfer.types[0] === _DATA_TRANSFER_DECK_COLUMN_;

		ev.dataTransfer.dropEffect = isDeckColumn ? 'move' : 'none';

		if (isDeckColumn) draghover = true;
	}
}

function onDragleave() {
	draghover = false;
}

function onDrop(ev) {
	draghover = false;
	os.deckGlobalEvents.emit('column.dragEnd');

	const id = ev.dataTransfer.getData(_DATA_TRANSFER_DECK_COLUMN_);
	if (id != null && id !== '') {
		swapColumn(props.column.id, id);
	}
}
</script>

<style lang="scss" scoped>
.dnpfarvg {
	--root-margin: 10px;

	height: 100%;
	overflow: hidden;
	contain: content;
	box-shadow: 0 0 8px 0 var(--shadow);

	&.draghover {
		box-shadow: 0 0 0 2px var(--focus);

		&:after {
			content: "";
			display: block;
			position: absolute;
			z-index: 1000;
			top: 0;
			left: 0;
			width: 100%;
			height: 100%;
			background: var(--focus);
		}
	}

	&.dragging {
		box-shadow: 0 0 0 2px var(--focus);
	}

	&.dropready {
		* {
			pointer-events: none;
		}
	}

	&:not(.active) {
		flex-basis: var(--deckColumnHeaderHeight);
		min-height: var(--deckColumnHeaderHeight);

		> header.indicated {
			box-shadow: 4px 0px var(--accent) inset;
		}
	}

	&.naked {
		background: var(--acrylicBg) !important;
		-webkit-backdrop-filter: var(--blur, blur(10px));
		backdrop-filter: var(--blur, blur(10px));

		> header {
			background: transparent;
			box-shadow: none;

			> button {
				color: var(--fg);
			}
		}
	}

	&.paged {
		background: var(--bg) !important;
	}

	> header {
		position: relative;
		display: flex;
		z-index: 2;
		line-height: var(--deckColumnHeaderHeight);
		height: var(--deckColumnHeaderHeight);
		padding: 0 16px;
		font-size: 0.9em;
		color: var(--panelHeaderFg);
		background: var(--panelHeaderBg);
		box-shadow: 0 1px 0 0 var(--panelHeaderDivider);
		cursor: pointer;

		&, * {
			user-select: none;
		}

		&.indicated {
			box-shadow: 0 3px 0 0 var(--accent);
		}

		> .header {
			display: inline-block;
			align-items: center;
			overflow: hidden;
			text-overflow: ellipsis;
			white-space: nowrap;
		}

		> span:only-of-type {
			width: 100%;
		}

		> .toggleActive,
		> .action > ::v-deep(*),
		> .menu {
			z-index: 1;
			width: var(--deckColumnHeaderHeight);
			line-height: var(--deckColumnHeaderHeight);
			font-size: 16px;
			color: var(--faceTextButton);

			&:hover {
				color: var(--faceTextButtonHover);
			}

			&:active {
				color: var(--faceTextButtonActive);
			}
		}

		> .toggleActive, > .action {
			margin-left: -16px;
		}

		> .action {
			z-index: 1;
		}

		> .action:empty {
			display: none;
		}

		> .menu {
			margin-left: auto;
			margin-right: -16px;
		}
	}

	> div {
		height: calc(100% - var(--deckColumnHeaderHeight));
		overflow-y: auto;
		overflow-x: hidden; // Safari does not supports clip
		overflow-x: clip;
		-webkit-overflow-scrolling: touch;
		box-sizing: border-box;
	}
}
</style>