<template>
	<!-- 部件侧边栏：搜索/分类/显示隐藏控制（按 showDetailsInSidebar 决定是否显示勾选） -->
	<aside class="sidebar" :class="{ collapsed: sidebarCollapsed }">
		<div class="sidebar-toggle" @click="onToggleSidebar?.()">
			{{ sidebarCollapsed ? ('◀ ' + tUI('SIDEBAR_EXPAND')) : ('▶ ' + tUI('SIDEBAR_COLLAPSE')) }}
		</div>

		<div v-show="!sidebarCollapsed" class="sidebar-content">
			<div class="side-title">
				<span>{{ tUI('SIDEBAR_TITLE_PARTS') }}</span>
				<!-- 顶部“全部显隐”按钮 -->
				<button class="btn-all" @click.stop="onToggleAll">
					{{ anyVisible ? tUI('SIDEBAR_HIDE_ALL') : tUI('SIDEBAR_SHOW_ALL') }}
				</button>
			</div>

			<div class="search">
				<input :value="searchKey" @input="e => onUpdateSearchKey?.((e.target as HTMLInputElement).value)"
					:placeholder="tUI('SIDEBAR_PLACEHOLDER_SEARCH')" />
			</div>

			<div class="cat-filter">
				<select id="categoryFilter" :value="currentFilter"
					@change="e => onUpdateCurrentFilter?.((e.target as HTMLSelectElement).value)">
					<option value="all">{{ tUI('SIDEBAR_FILTER_ALL') }}</option>
					<option v-for="cat in sortedCats" :key="cat" :value="cat">
						{{ tUI(cat) }}
					</option>
				</select>
			</div>

			<div class="tree">
				<section v-for="cat in sortedCats" :key="cat"
					v-show="(currentFilter === 'all' || currentFilter === cat) && matchCat(cat)" class="tree-group">
					<!-- 大类行：点击整行切换“该类是否可见”；当 showDetailsInSidebar=true 时显示大类勾选框 -->
					<header class="tree-head" :class="{ shown: isCatAnyVisible(cat) }"
						@click="toggleCategoryVisible(cat, !isCatAnyVisible(cat))">
						<!-- 折叠箭头：仅在显示明细时出现；阻止冒泡避免触发行点击 -->
						<span class="arrow" v-if="showDetailsInSidebar" @click.stop="onToggleCollapse?.(cat)">
							{{ collapsed[cat] ? '▸' : '▾' }}
						</span>

						<!-- 大类勾选框：仅在 showDetailsInSidebar=true 时显示 -->
						<input v-if="showDetailsInSidebar" type="checkbox" class="chk" :checked="isCatAllVisible(cat)"
							@click.stop
							@change="toggleCategoryVisible(cat, ($event.target as HTMLInputElement).checked)" />

						<span class="name">{{ tUI(cat) }}</span>
						<span class="count" v-if="showDetailsInSidebar">
							({{ categoryMap[cat].length }})
						</span>
					</header>

					<!-- 明细：只有在 showDetailsInSidebar=true 且该类未折叠时才渲染 -->
					<div class="tree-body" v-if="showDetailsInSidebar && !collapsed[cat]">
						<label v-for="name in categoryMap[cat]" :key="name" v-show="matchPart(name)"
							:class="['row', { 'has-info': infoMap[name] }]" :title="name">
							<!-- 明细勾选框：逐个控制部件 visible -->
							<input type="checkbox" class="chk" :checked="partMap[name]?.visible !== false" @click.stop
								@change="partMap[name] && (partMap[name].visible = ($event.target as HTMLInputElement).checked)" />

							<span class="label">{{ displayPartName(name) }}</span>
							<span class="dot" v-if="infoMap[name]" :title="tUI('SIDEBAR_HINT_HAS_INFO')"></span>
						</label>
					</div>
				</section>
			</div>
		</div>
	</aside>
</template>

<script setup lang="ts">
/**
 * 右侧部件树（已接入 tUI）
 * - showDetailsInSidebar = false：保持“无勾选框、仅大类点击控制 + 顶部批量按钮”的简洁模式
 * - showDetailsInSidebar = true ：显示大类勾选框与明细勾选框，可逐项控制 visible
 */
import { computed } from 'vue';
import { tUI } from './i18nExt';

const showDetailsInSidebar = false;

const props = defineProps<{
	// 折叠与显示
	sidebarCollapsed: boolean
	onToggleSidebar?: () => void

	// 搜索与筛选
	searchKey: string
	currentFilter: string
	sortedCats: string[]
	onUpdateSearchKey?: (v: string) => void
	onUpdateCurrentFilter?: (v: string) => void

	// 数据
	categoryMap: Record<string, string[]>
	partMap: Record<string, any>
	infoMap: Record<string, boolean>
	collapsed: Record<string, boolean>

	// 行为
	displayPartName: (name: string) => string
	onToggleCollapse?: (cat: string) => void

	// 是否显示明细
	showDetailsInSidebar?: boolean
}>();

/* -------- 工具：取某类下所有名称 -------- */
function namesOf(cat: string) {
	return props.categoryMap[cat] || [];
}

/* -------- 搜索匹配（本地实现） -------- */
function matchPart(name: string) {
	const k = props.searchKey.trim().toLowerCase();
	if (!k) {
		return true;
	}
	return name.toLowerCase().includes(k);
}

function matchCat(cat: string) {
	const k = props.searchKey.trim().toLowerCase();
	if (!k) {
		return true;
	}
	return namesOf(cat).some(n => matchPart(n));
}

/* -------- 全局批量显隐状态 -------- */
const allNames = computed(() => Object.values(props.categoryMap).flat());
const anyVisible = computed(() =>
	allNames.value.some(n => !!props.partMap[n]?.visible),
);

/** 批量显/隐所有部件 */
function toggleAllVisible(to: boolean) {
	allNames.value.forEach(n => {
		if (props.partMap[n]) {
			props.partMap[n].visible = to;
		}
	});
}

/** 顶部按钮：若当前有任何可见 => 全部隐藏；否则 => 全部显示 */
function onToggleAll() {
	toggleAllVisible(!anyVisible.value);
}

/* -------- 判定类可见性 -------- */
function isCatAnyVisible(cat: string) {
	const arr = namesOf(cat);
	return arr.length > 0 && arr.some(n => !!props.partMap[n]?.visible);
}
function isCatAllVisible(cat: string) {
	const arr = namesOf(cat);
	return arr.length > 0 && arr.every(n => !!props.partMap[n]?.visible);
}

/* -------- 点击大类：统一显/隐该类 -------- */
function toggleCategoryVisible(cat: string, checked: boolean) {
	namesOf(cat).forEach(n => {
		if (props.partMap[n]) {
			props.partMap[n].visible = checked;
		}
	});
}
</script>

<style scoped>
.sidebar {
	position: absolute;
	top: 60px;
	right: 12px;
	bottom: 12px;
	width: 280px;
	background: #fff;
	border: 1px solid #e5e5e5;
	border-radius: 10px;
	box-shadow: 0 6px 18px rgba(0, 0, 0, 0.08);
	z-index: 25;
	overflow: hidden;
	display: flex;
	flex-direction: column;
	transition: width 0.25s ease;
}

.sidebar.collapsed {
	width: 36px;
}

.sidebar-toggle {
	padding: 6px;
	font-size: 12px;
	text-align: center;
	background: #f5f5f5;
	border-bottom: 1px solid #eee;
	cursor: pointer;
	user-select: none;
}

.sidebar-content {
	flex: 1;
	display: flex;
	flex-direction: column;
	overflow: hidden;
}

.side-title {
	display: flex;
	align-items: center;
	justify-content: space-between;
	padding: 10px 12px;
	border-bottom: 1px solid #f0f0f0;
	font-weight: 600;
}

.btn-all {
	appearance: none;
	border: 1px solid #d9d9d9;
	background: #fff;
	border-radius: 999px;
	padding: 4px 10px;
	font-size: 12px;
	cursor: pointer;
}

.btn-all:hover {
	background: #e6f4ff;
	border-color: #91caff;
}

.search {
	padding: 10px 12px;
	border-bottom: 1px solid #f5f5f5;
}

.search input {
	width: 100%;
	height: 30px;
	border: 1px solid #e5e5e5;
	border-radius: 6px;
	padding: 0 10px;
}

.cat-filter {
	padding: 8px 12px;
}

.cat-filter select {
	width: 100%;
	height: 30px;
}

.tree {
	padding: 4px 8px 12px 8px;
	overflow: auto;
}

.tree-group {
	border-radius: 8px;
	border: 1px solid #f2f2f2;
	margin: 8px 0;
}

.tree-head {
	display: flex;
	align-items: center;
	gap: 8px;
	padding: 8px 10px;
	cursor: pointer;
	background: #fafafa;
	border-bottom: 1px solid #f3f3f3;
	transition:
		background-color 0.15s ease,
		border-color 0.15s ease,
		color 0.15s ease;
}

.tree-head.shown {
	background: #e6f4ff;
	border-color: #91caff;
}

.tree-head.shown .name {
	color: #1677ff;
	font-weight: 700;
}

.tree-head .name {
	flex: 1;
}

.tree-head .count {
	color: #888;
}

.tree-head .chk {
	margin-right: 6px;
}

.row .chk {
	margin-right: 8px;
}

.tree-body {
	padding: 6px 10px 10px 12px;
}

.row {
	display: flex;
	align-items: center;
	gap: 8px;
	padding: 4px 0;
}

.row.has-info .label {
	color: #1677ff;
	font-weight: 600;
}

.row .dot {
	width: 8px;
	height: 8px;
	border-radius: 50%;
	margin-left: 6px;
	background: #1677ff;
	display: inline-block;
}
</style>
