<template>
	<div class="gantt-view">
		<div ref="ganttContainer" class="gantt-view__chart" />
	</div>
</template>

<script lang="ts" setup>
import { ref, onMounted, onUnmounted, watch } from 'vue';
import { gantt } from 'dhtmlx-gantt';
import 'dhtmlx-gantt/codebase/dhtmlxgantt.css';
import { useProjectStore } from '../../store/project';
import { useCool } from '/@/cool';

const emit = defineEmits<{
	(e: 'open-task', taskId: number): void;
}>();

const store = useProjectStore();
const { service } = useCool();
const ganttContainer = ref<HTMLElement>();

function initGantt() {
	if (!ganttContainer.value) return;

	// 中文 locale
	(gantt as any).locale = {
		date: {
			month_full: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'],
			month_short: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
			day_full: ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'],
			day_short: ['日', '一', '二', '三', '四', '五', '六'],
		},
		labels: {
			new_task: '新任务',
			dhx_cal_today_button: '今天',
			day_tab: '日',
			week_tab: '周',
			month_tab: '月',
			new_event: '新建事件',
			icon_save: '保存',
			icon_cancel: '取消',
			icon_details: '详情',
			icon_edit: '编辑',
			icon_delete: '删除',
			confirm_closing: '',
			confirm_deleting: '确定删除吗？',
			section_description: '描述',
			section_time: '时间',
			section_type: '类型',
			column_wbs: 'WBS',
			column_text: '任务名称',
			column_start_date: '开始时间',
			column_duration: '工期',
			column_add: '',
			link: '关联',
			confirm_link_deleting: '将被删除',
			link_start: '(开始)',
			link_end: '(结束)',
			type_task: '任务',
			type_project: '项目',
			type_milestone: '里程碑',
			minutes: '分钟',
			hours: '小时',
			days: '天',
			weeks: '周',
			months: '月',
			years: '年',
			message_ok: '确定',
			message_cancel: '取消',
		},
	};

	gantt.config.date_format = '%Y-%m-%d';
	gantt.config.min_column_width = 70;
	gantt.config.row_height = 36;
	gantt.config.drag_resize = true;
	gantt.config.drag_move = true;
	gantt.config.drag_links = true;
	gantt.config.auto_scheduling = false;
	gantt.config.open_tree_initially = true;
	gantt.config.fit_tasks = true;

	// 双行时间轴：上面显示"年-月"，下面显示"日 周几"
	gantt.config.scales = [
		{ unit: 'month', step: 1, format: '%Y年%m月' },
		{ unit: 'day', step: 1, format: '%d日 %D' },
	];

	gantt.config.columns = [
		{ name: 'text', label: '任务名称', width: 200, tree: true },
		{ name: 'start_date', label: '开始', align: 'center', width: 100 },
		{ name: 'end_date', label: '结束', align: 'center', width: 100 },
		{ name: 'assignee', label: '负责人', align: 'center', width: 70 },
	];

	gantt.attachEvent('onTaskDblClick', (id: string) => {
		if (id.startsWith('t_')) {
			const taskId = parseInt(id.replace('t_', ''));
			emit('open-task', taskId);
		}
		return false;
	});

	gantt.attachEvent('onAfterTaskDrag', (id: string) => {
		const task = gantt.getTask(id);
		const formatTaskDate = (date?: Date) => date ? gantt.templates.format_date(date) : '';
		// 使用 setTimeout 避免在 gantt 事件回调中同步触发 store 更新导致递归
		setTimeout(() => {
			store.ganttUpdate([
				{
					id,
					start_date: formatTaskDate(task.start_date),
					end_date: formatTaskDate(task.end_date),
					parent: task.parent,
				},
			]);
		}, 0);
	});

	gantt.attachEvent('onAfterLinkAdd', (id: any, link: any) => {
		const taskId = parseInt(String(link.target).replace('t_', ''));
		const dependsOnTaskId = parseInt(String(link.source).replace('t_', ''));
		if (taskId && dependsOnTaskId) {
			void service.project.task_dependency.add({
				taskId,
				dependsOnTaskId,
				type: parseInt(link.type) || 0
			});
		}
	});

	gantt.init(ganttContainer.value);
}

function renderData() {
	const { data, links } = store.ganttData;
	gantt.clearAll();
	if (data.length > 0) {
		// 没有日期的任务给默认日期（今天~明天），让用户可以在甘特图上看到并拖拽
		const today = new Date();
		const tomorrow = new Date(today);
		tomorrow.setDate(tomorrow.getDate() + 1);
		const todayStr = today.toISOString().slice(0, 10);
		const tomorrowStr = tomorrow.toISOString().slice(0, 10);

		const fixedData = data.map((d: any) => {
			const start = d.start_date || todayStr;
			let end = d.end_date || tomorrowStr;
			// dhtmlx-gantt 的 end_date 是"不包含"边界，start===end 时持续时间为0看不到
			// 同一天的任务至少显示为1天的条形
			if (end <= start) {
				const next = new Date(start);
				next.setDate(next.getDate() + 1);
				end = next.toISOString().slice(0, 10);
			}
			return { ...d, start_date: start, end_date: end };
		});
		gantt.parse({ data: fixedData, links });
	}
}

watch(() => store.ganttData, () => {
	renderData();
});

onMounted(() => {
	initGantt();
	renderData();
});

onUnmounted(() => {
	gantt.clearAll();
});
</script>

<style lang="scss" scoped>
.gantt-view {
	&__chart {
		width: 100%;
		height: calc(100vh - 260px);
	}
}
</style>
