<template>
  <!-- 纯数据组件：不渲染 UI，提供 DIMM hover 信息 -->
  <div style="display:none"></div>
</template>

<script setup lang="ts">
/**
 * DIMM 悬浮信息提供者
 * - 负责内存条列表与（可选）详情的获取与 KV 组装
 */
import { ref, reactive, onMounted } from 'vue';
import { useI18n } from 'vue-i18n';
import { loading } from '@/utils/composition';
import * as service from '@/pages/System/Info/service/system.service';

import { KV } from '../shared/types';
import { firstNonEmpty, fmt } from '../shared/format';

const UI_REST_SYSTEM_MEMORY = '/UI/Rest/System/Memory';

const getMemoryApi =
  (service as any).getMemory ??
  (async () => ({ data: { List: [], MaxNumber: 0 } }));

const getOneMemoryApi =
  (service as any).getOneMemory ??
  (async (_url: string) => ({ data: {} }));

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

const { t } = useI18n();

const dimmSlots = ref<string[]>([]);
const detailMap = reactive<Record<string, Record<string, any>>>({});
const infoMap = reactive<Record<string, string>>({});
const urlMap = reactive<Record<string, string>>({});
const loaded = reactive<Record<string, boolean>>({});

async function initDimms() {
  loading?.(true);
  try {
    const { data } = await getMemoryApi();
    const list = data?.List || [];

    dimmSlots.value = list.map((i: any) => i?.General?.DeviceLocator).filter(Boolean);
    emit('dimm-slots', dimmSlots.value);

    list.forEach((i: any) => {
      const g = i?.General || {};
      const d = i?.Detail || {};

      const deviceLocator = firstNonEmpty(g.DeviceLocator, d.DeviceLocator);
      const position = firstNonEmpty(g.Position, d.Position, g.Location);
      const manufacturer = firstNonEmpty(g.Manufacturer, d.Manufacturer);
      const capacityMiB = fmt(firstNonEmpty(g.CapacityMiB, d.CapacityMiB), 'MB');
      const operating = fmt(
        firstNonEmpty(
          g.OperatingSpeedMHz,
          g.ConfiguredSpeedMTS,
          d.ConfiguredSpeedMTS,
          d.OperatingSpeedMHz,
        ),
        'MT/s',
      );
      const allowed = fmt(
        firstNonEmpty(g.AllowedSpeedsMHz, d.AllowedSpeedsMHz, d.MaxSpeedMTS),
        'MT/s',
      );
      const minVolt = fmt(
        firstNonEmpty(g.MinVoltageMillivolt, d.MinVoltageMillivolt, d.MinVoltage),
        'mV',
      );
      const dataWidth = fmt(
        firstNonEmpty(g.DataWidthBits, d.DataWidthBits, d.DataWidth),
        'bit',
      );
      const rankCount = fmt(firstNonEmpty(g.RankCount, d.RankCount), 'rank');
      const deviceType = firstNonEmpty(g.DeviceType, d.Type, g.Type);
      const partNumber = firstNonEmpty(g.PartNumber, d.PartNumber);
      const serialNumber = firstNonEmpty(g.SerialNumber, d.SerialNumber);
      const typeDetail = firstNonEmpty(g.TypeDetail, d.TypeDetail);
      const bomNumber = firstNonEmpty(g.BomNumber, d.BomNumber);

      infoMap[deviceLocator] = [deviceLocator, capacityMiB, manufacturer]
        .filter(Boolean)
        .join(' | ');
      detailMap[deviceLocator] = {
        deviceLocator,
        position,
        manufacturer,
        capacityMiB,
        operatingSpeedMHz: operating,
        allowedSpeedsMHz: allowed,
        deviceType,
        minVoltageMillivolt: minVolt,
        typeDetail,
        dataWidthBits: dataWidth,
        partNumber,
        rankCount,
        bomNumber,
        serialNumber,
      };

      if (position && deviceLocator) {
        urlMap[deviceLocator] = `${UI_REST_SYSTEM_MEMORY}/${position}${deviceLocator}`;
      }
    });
  } finally {
    loading?.(false);
  }
}

async function ensureDetail(loc: string) {
  if (loaded[loc]) {
    return;
  }
  const url = urlMap[loc];
  if (!url) {
    return;
  }
  try {
    const { data } = await getOneMemoryApi(url);
    const g = data?.General || {};
    const d = data?.Detail || {};

    const merged = {
      deviceLocator: firstNonEmpty(g.DeviceLocator, d.DeviceLocator),
      position: firstNonEmpty(g.Position, d.Position, g.Location),
      manufacturer: firstNonEmpty(g.Manufacturer, d.Manufacturer),
      capacityMiB: fmt(firstNonEmpty(g.CapacityMiB, d.CapacityMiB), 'MB'),
      operatingSpeedMHz: fmt(
        firstNonEmpty(
          g.OperatingSpeedMHz,
          g.ConfiguredSpeedMTS,
          d.ConfiguredSpeedMTS,
          d.OperatingSpeedMHz,
        ),
        'MT/s',
      ),
      allowedSpeedsMHz: fmt(
        firstNonEmpty(g.AllowedSpeedsMHz, d.AllowedSpeedsMHz, d.MaxSpeedMTS),
        'MT/s',
      ),
      deviceType: firstNonEmpty(g.DeviceType, d.Type, g.Type),
      minVoltageMillivolt: fmt(
        firstNonEmpty(g.MinVoltageMillivolt, d.MinVoltageMillivolt, d.MinVoltage),
        'mV',
      ),
      typeDetail: firstNonEmpty(g.TypeDetail, d.TypeDetail),
      dataWidthBits: fmt(
        firstNonEmpty(g.DataWidthBits, d.DataWidthBits, d.DataWidth),
        'bit',
      ),
      partNumber: firstNonEmpty(g.PartNumber, d.PartNumber),
      rankCount: fmt(firstNonEmpty(g.RankCount, d.RankCount), 'rank'),
      bomNumber: firstNonEmpty(g.BomNumber, d.BomNumber),
      serialNumber: firstNonEmpty(g.SerialNumber, d.SerialNumber),
    };
    detailMap[loc] = { ...detailMap[loc], ...merged };
    loaded[loc] = true;
  } catch {
    // ignore single DIMM detail error
  }
}

function getBasicText(name: string) {
  return infoMap[name] ?? name;
}

async function buildPairs(name: string): Promise<KV[]> {
  await ensureDetail(name);
  const info = detailMap[name];
  if (!info) {
    return [];
  }

  const schema: Array<[string, string]> = [
    ['COMMON_NAME', 'deviceLocator'],
    ['MEMORY_POSITION', 'position'],
    ['COMMON_MANUFACTURER', 'manufacturer'],
    ['COMMON_CAPACITY', 'capacityMiB'],
    ['MEMORY_CONFIGURED_SPEED_MTS', 'operatingSpeedMHz'],
    ['MEMORY_MAX_SPEED_MTS', 'allowedSpeedsMHz'],
    ['COMMON_TYPE', 'deviceType'],
    ['MEMORY_MIN_VOLTAGE_MILLIVOLT', 'minVoltageMillivolt'],
    ['MEMORY_TECHNOLOGY', 'typeDetail'],
    ['MEMORY_DATAWIDTH_BITS', 'dataWidthBits'],
    ['OTHER_PART_NUMBER', 'partNumber'],
    ['MEMORY_PANK', 'rankCount'],
    ['MEMORY_BOM_NUMBER', 'bomNumber'],
    ['COMMON_SERIALNUMBER', 'serialNumber'],
  ];

  return schema
    .map(([label, key]) => {
      const v = (info as any)[key];
      if (v === undefined || v === null || v === '') {
        return null;
      }
      return { k: t(label as any), v: String(v) };
    })
    .filter(Boolean) as KV[];
}

defineExpose({ buildPairs, getBasicText });
onMounted(initDimms);
</script>
