<template>
	<!-- 纯数据组件：不渲染 UI，提供 Disk 悬浮信息 + 右键菜单动作 -->
	<div style="display:none"></div>
</template>

<script setup lang="ts">
/**
 * Disk 悬浮信息提供者 + 右键菜单（定位指示灯）
 * - 列表：GET  /UI/Rest/System/Storage/ViewsSummary  →  Drives[{Drives_ID, Name}]
 * - 详情：GET  /UI/Rest/System/Storage/Drives/:Drives_ID  →  悬浮 KV
 * - 定位：PATCH /UI/Rest/System/Storage/Drives/:Drives_ID  { IndicatorLED: 'Blinking' | 'Off' }
 *   说明：选择的是“磁盘名”（如 Disk0），真正 PATCH 用的是其 Drives_ID（如 HDDPlaneDisk0）
 */
import axios from 'axios';
import { ref, reactive, onMounted } from 'vue';
import { traduction } from '@/utils/language';

import { KV, MenuItem, CtxAction } from '../shared/types';
import { formatBytesIEC as formatBytes, fmt as fmtVal } from '../shared/format';

/* ============================== 常量 ============================== */
const VIEWS_SUMMARY = '/UI/Rest/System/Storage/ViewsSummary';
const DRIVE_DETAIL = (id: string) => `/UI/Rest/System/Storage/Drives/${id}`;
const DRIVE_PATCH = (id: string) => `/UI/Rest/System/Storage/Drives/${id}`;

const emit = defineEmits<{ (e: 'disk-list', names: string[]): void }>();

/* ============================== 缓存 ============================== */
/** Name → Drives_ID（供详情/patch 使用） */
const name2Id = reactive<Record<string, string>>({});
/** Name → 详情对象（含 IndicatorLED 等） */
const detailMap = reactive<Record<string, any>>({});
/** 当前存在的磁盘 Name 列表（右键/左键统一来源） */
const diskNames = ref<string[]>([]);

/* ============================== 拉取列表 / 详情 ============================== */
async function refresh() {
	try {
		const { data } = await axios.get(VIEWS_SUMMARY, { withCredentials: true });
		const list: Array<{ Drives_ID?: string; Name?: string }> = Array.isArray(data?.Drives)
			? data.Drives
			: [];

		Object.keys(name2Id).forEach((k) => {
			delete name2Id[k];
		});

		const names: string[] = [];
		for (const d of list) {
			const name = d?.Name?.trim();
			const id = d?.Drives_ID?.trim();
			if (!name || !id) {
				continue;
			}
			name2Id[name] = id;
			names.push(name);
		}
		diskNames.value = names;
		emit('disk-list', names);
	} catch (_err) {
		diskNames.value = [];
	}
}

async function ensureDetail(name: string) {
	if (!name || detailMap[name]) {
		return;
	}
	const id = name2Id[name];
	if (!id) {
		return;
	}
	try {
		const { data } = await axios.get(DRIVE_DETAIL(id), { withCredentials: true });
		detailMap[name] = {
			...data,
			_capacityStr: formatBytes(data?.CapacityBytes),
			_lifeLeft: fmtVal(data?.PredictedMediaLifeLeftPercent, '%'),
			_temp: fmtVal(data?.TemperatureCelsius, '°C'),
			_speedMax: fmtVal(data?.CapableSpeedGbs, 'Gbps'),
			_speedNeg: fmtVal(data?.NegotiatedSpeedGbs, 'Gbps'),
		};
	} catch (_err) {
		// ignore
	}
}

/* ============================== 悬浮卡片数据 ============================== */
async function buildPairs(name: string): Promise<KV[]> {
	await ensureDetail(name);
	const d = detailMap[name];
	if (!d) {
		return [];
	}
	const schema: Array<[string, string]> = [
		['COMMON_NAME', 'Name'],
		['FDM_INTERFACE_TYPE', 'Protocol'],
		['FDM_ALARM_VENDOR', 'Manufacturer'],
		['COMMON_SERIALNUMBER', 'SerialNumber'],
		['FDM_MEDIA_TYPE', 'MediaType'],
		['COMMON_CAPACITY', '_capacityStr'],
		['FDM_LOCATION_STATUS', 'IndicatorLED'],
		['COMMON_RESOURCE_OWNER', 'AssociatedResource'],

		['NET_HEALTH_STATUS', 'Health'],
		['FDM_ALARM_MODEL', 'Model'],
		['COMMON_FIXED_VERSION', 'Revision'],
		['FDM_TEMPERATURE', '_temp'],
		['FDM_SUPPORTED_RATE', '_speedMax'],
		['STORAGE_SPEED_NEGOTIATED', '_speedNeg'],
		['WEAR_RATE', '_lifeLeft'],
		['FDM_LOCATION', 'Position'],
	];
	return schema
		.map(([k, key]) => {
			const v = d?.[key];
			if (v === undefined || v === null || v === '') {
				return null;
			}
			return { k: traduction(k as any), v: String(v) };
		})
		.filter(Boolean) as KV[];
}

function getBasicText(name: string) {
	const d = detailMap[name];
	if (!d) {
		return name;
	}
	return [name, d?._capacityStr || '', d?._temp || ''].filter(Boolean).join(' | ') || name;
}

function getNames() {
	return diskNames.value.slice();
}

/* ============================== 定位指示灯（PATCH） ============================== */
async function setIndicatorLED(name: string, mode: 'Blinking' | 'Off'): Promise<boolean> {
	const id = name2Id[name];
	if (!id) {
		return false;
	}
	try {
		const { data } = await axios.patch(
			DRIVE_PATCH(id),
			{ IndicatorLED: mode },
			{ withCredentials: true },
		);
		if (data?.error) {
			return false;
		}
		if (detailMap[name]) {
			detailMap[name].IndicatorLED = mode;
		}
		return true;
	} catch (_err) {
		return false;
	}
}

/* ============================== 右键菜单 ============================== */
async function getContextMenu(): Promise<{ title: string; items: MenuItem[] }> {
	if (!diskNames.value.length) {
		await refresh();
	}

	const items: MenuItem[] = (diskNames.value || []).map((nm) => ({
		key: `disk.${nm}`,
		label: nm,
		children: [
			{
				key: `disk.${nm}.blink`,
				label: '定位灯 开启',
				action: { op: 'setIndicator', params: { name: nm, mode: 'Blinking' } },
			},
			{
				key: `disk.${nm}.off`,
				label: '定位灯 关闭',
				action: { op: 'setIndicator', params: { name: nm, mode: 'Off' } },
			},
		],
	}));

	items.push({
		key: 'disk.refresh',
		label: traduction('COMMON_REFRESH'),
		action: { op: 'refresh' },
	});

	return { title: '存储', items };
}

async function execContextAction(action: CtxAction): Promise<void> {
	const { op, params = {} } = action || {};
	switch (op) {
		case 'setIndicator':
			await setIndicatorLED((params as any).name, (params as any).mode);
			break;
		case 'refresh':
			await refresh();
			break;
		default:
			break;
	}
}

/* ============================== 对外暴露 ============================== */
defineExpose({
	buildPairs,
	getBasicText,
	getContextMenu,
	execContextAction,
	refresh,
	getNames,
});

onMounted(refresh);
</script>
