import { computed, nextTick, reactive, ref, watch } from 'vue';
import { useRoute } from 'vue-router';
import { ElMessage } from 'element-plus';
import { parseTime } from '@/utils/ruoyi';
import { getMonitorInfoTree } from '@/api/ems/base/baseMonitorInfo';
import { getRecordIotenvInstantReportData } from '@/api/ems/record/recordIotenvInstant';
import type { RecordIotenvInstantVO } from '@/api/ems/types';
import {
  buildMetricHintsByNode,
  normalizeIotCurveRecord,
  readMetricValue,
  resolveIotCurveMetrics,
  type IotCurveMetricDefinition,
  type IotCurveMetricHint,
  type NormalizedIotCurveRecord
} from './iotCurveShared';

export interface IotReportMetricStats {
  latest: number | null;
  avg: number | null;
  max: number | null;
  p75: number | null;
  p90: number | null;
}

export interface IotReportDeviceStat {
  monitorId: string;
  monitorName: string;
  latest: number;
  avg: number;
  max: number;
  count: number;
}

export interface IotReportScopeOption {
  key: string;
  label: string;
  deviceCount: number;
}

interface IotTreeLeafNode extends Record<string, unknown> {
  code?: string;
  label?: string;
  type?: unknown;
  __rootKey?: string;
}

interface IotReportSelection {
  compareScope: string;
  monitorId: string;
  monitorIds: string[];
  monitorName: string;
  selectionLabel: string;
  nodeId: string;
}

const createDefaultTimeRange = () => {
  const now = new Date();
  const start = new Date(now.getTime() - 2 * 60 * 60 * 1000);
  return [parseTime(start, '{y}-{m}-{d} {h}:{i}:{s}'), parseTime(now, '{y}-{m}-{d} {h}:{i}:{s}')];
};

const resolveNodeKey = (node: Record<string, unknown>) => {
  return String(node.id || node.code || node.label || Math.random());
};

const cloneTreeByRootKeys = (nodes: Array<Record<string, unknown>>, selectedKeys: string[]) => {
  return (nodes || []).filter((item) => selectedKeys.includes(resolveNodeKey(item)));
};

const getLeafNodes = (nodes: Array<Record<string, unknown>>, rootKey?: string): IotTreeLeafNode[] => {
  let result: IotTreeLeafNode[] = [];
  (nodes || []).forEach((item) => {
    const currentRootKey = rootKey || resolveNodeKey(item);
    if (Array.isArray(item.children) && item.children.length > 0) {
      result = result.concat(getLeafNodes(item.children as Array<Record<string, unknown>>, currentRootKey));
      return;
    }
    if (item.code) {
      result.push({
        ...item,
        __rootKey: currentRootKey
      });
    }
  });
  return result;
};

const buildDeviceDisplayMap = (nodes: Array<Record<string, unknown>>) => {
  return getLeafNodes(nodes).reduce((accumulator, item) => {
    const key = String(item.code || '');
    if (!key) {
      return accumulator;
    }
    accumulator[key] = {
      label: String(item.label || key),
      type: item.type
    };
    return accumulator;
  }, {} as Record<string, { label: string; type: unknown }>);
};

const findRootKeyByNodeId = (nodes: Array<Record<string, unknown>>, targetId: string, rootKey = ''): string => {
  for (const item of nodes || []) {
    const currentRootKey = rootKey || resolveNodeKey(item);
    if (String(item.id || '') === String(targetId || '')) {
      return currentRootKey;
    }
    if (Array.isArray(item.children) && item.children.length > 0) {
      const matched = findRootKeyByNodeId(item.children as Array<Record<string, unknown>>, targetId, currentRootKey);
      if (matched) {
        return matched;
      }
    }
  }
  return '';
};

const buildSelectionByLeafNodes = (leafNodes: IotTreeLeafNode[], selectionLabel: string, compareScope = ''): IotReportSelection => {
  const monitorIds = leafNodes.map((item) => String(item.code || '')).filter((item) => item);
  const firstNode = leafNodes[0];
  return {
    compareScope: compareScope || (monitorIds.length > 1 ? 'group' : 'single'),
    monitorId: monitorIds.length === 1 ? monitorIds[0] : '',
    monitorIds,
    monitorName: monitorIds.length === 1 ? String(firstNode?.label || selectionLabel) : selectionLabel,
    selectionLabel,
    nodeId: String(firstNode?.id || '')
  };
};

export const isValidNumber = (value: unknown) => value !== null && value !== undefined && !Number.isNaN(Number(value));

export const average = (values: number[]) => {
  if (!values.length) {
    return 0;
  }
  return values.reduce((sum, item) => sum + item, 0) / values.length;
};

export const percentile = (sortedValues: number[], ratio: number) => {
  if (!sortedValues.length) {
    return 0;
  }
  const index = Math.min(sortedValues.length - 1, Math.max(0, Math.ceil(sortedValues.length * ratio) - 1));
  return sortedValues[index];
};

export const getBands = (values: number[]) => {
  const sortedValues = [...values].sort((left, right) => left - right);
  return {
    low: percentile(sortedValues, 0.33),
    high: percentile(sortedValues, 0.66),
    avg: average(sortedValues),
    p75: percentile(sortedValues, 0.75),
    p90: percentile(sortedValues, 0.9)
  };
};

export const formatValue = (value: unknown) => {
  if (!isValidNumber(value)) {
    return '--';
  }
  return Number(value).toFixed(2);
};

export const formatPercent = (value: unknown) => {
  return `${(Number(value || 0) * 100).toFixed(1)}%`;
};

export const normalizePercent = (value: number | null, max: number | null) => {
  if (!isValidNumber(value) || !isValidNumber(max) || Number(max) <= 0) {
    return 0;
  }
  return Number((((value || 0) / (max || 1)) * 100).toFixed(2));
};

export const ceilNumber = (value: number) => Math.ceil(value * 10) / 10;

export const useIotReportWorkbench = () => {
  const route = useRoute();

  const loading = ref(false);
  const treeLoading = ref(false);
  const reportReady = ref(false);
  const monitorTreeOptions = ref<Array<Record<string, unknown>>>([]);
  const deviceDisplayMap = ref<Record<string, { label: string; type: unknown }>>({});
  const selectedScopeKeys = ref<string[]>([]);
  const currentTreeNodeId = ref('');
  const rawRecords = ref<NormalizedIotCurveRecord[]>([]);
  const daterangeRecordTime = ref<string[]>(createDefaultTimeRange());

  const queryForm = reactive({
    compareScope: 'single',
    monitorId: '',
    monitorIds: [] as string[],
    monitorName: '',
    selectionLabel: '当前分析范围',
    samplingInterval: 5,
    primaryMetricField: ''
  });

  const leafNodeMap = computed(() => {
    return getLeafNodes(monitorTreeOptions.value).reduce((accumulator, item) => {
      const key = String(item.code || '');
      if (key) {
        accumulator[key] = item;
      }
      return accumulator;
    }, {} as Record<string, IotTreeLeafNode>);
  });

  const selectedLeafNodes = computed(() => {
    const currentIds = queryForm.monitorIds.length ? queryForm.monitorIds : queryForm.monitorId ? [queryForm.monitorId] : [];
    return currentIds.map((item) => leafNodeMap.value[item]).filter(Boolean);
  });

  const metricHints = computed<IotCurveMetricHint[]>(() => {
    return selectedLeafNodes.value.flatMap((item) => buildMetricHintsByNode(item));
  });

  const metricConfigs = computed<IotCurveMetricDefinition[]>(() => {
    return resolveIotCurveMetrics(rawRecords.value, metricHints.value);
  });

  const primaryMetric = computed<IotCurveMetricDefinition | null>(() => {
    if (!metricConfigs.value.length) {
      return null;
    }
    const matched = metricConfigs.value.find((item) => item.key === queryForm.primaryMetricField);
    return matched || metricConfigs.value[0];
  });

  const availablePrimaryMetricOptions = computed(() => metricConfigs.value);

  const deviceCount = computed(() => {
    if (queryForm.monitorIds.length > 0) {
      return queryForm.monitorIds.length;
    }
    return queryForm.monitorId ? 1 : 0;
  });

  const hasMultiDevice = computed(() => {
    return queryForm.monitorIds.length > 1 || ['group', 'all'].includes(queryForm.compareScope);
  });

  const availableScopeOptions = computed<IotReportScopeOption[]>(() => {
    return (monitorTreeOptions.value || []).map((item) => ({
      key: resolveNodeKey(item),
      label: String(item.label || '未命名分组'),
      deviceCount: getLeafNodes([item]).length
    }));
  });

  const filteredMonitorTreeOptions = computed(() => {
    if (!selectedScopeKeys.value.length) {
      return monitorTreeOptions.value;
    }
    return cloneTreeByRootKeys(monitorTreeOptions.value, selectedScopeKeys.value);
  });

  const monitorTypeLabel = computed(() => {
    return metricConfigs.value.length ? metricConfigs.value.map((item) => item.label).join(' / ') : '待识别';
  });

  const selectionSummary = computed(() => {
    const summaryMap = {
      all: '多分组联合分析',
      group: '设备组分析',
      single: '单设备分析'
    };
    return summaryMap[queryForm.compareScope] || '分析中';
  });

  const energySelectionSummary = computed(() => {
    if (!selectedScopeKeys.value.length) {
      return '当前未限定分组，默认展示全部范围';
    }
    const labels = availableScopeOptions.value.filter((item) => selectedScopeKeys.value.includes(item.key)).map((item) => item.label);
    return `当前分组：${labels.join(' / ')}`;
  });

  const deviceSelectionSummary = computed(() => {
    return queryForm.selectionLabel ? `分析范围：${queryForm.selectionLabel}` : '分析范围待确认';
  });

  const analysisObjectValue = computed(() => {
    if (hasMultiDevice.value) {
      return `${deviceCount.value} 台设备`;
    }
    return queryForm.monitorName || queryForm.selectionLabel || '--';
  });

  const analysisObjectFoot = computed(() => {
    return hasMultiDevice.value ? '当前报表按设备组/联合范围聚合分析' : '当前报表按单设备时间轨迹分析';
  });

  const metricDescription = computed(() => {
    return metricConfigs.value.length ? metricConfigs.value.map((item) => item.label).join('、') : '等待识别有效指标';
  });

  const primaryMetricFoot = computed(() => {
    return primaryMetric.value ? `当前主看指标用于排名、筛选与小时均值分析` : '请选择有效主看指标';
  });

  const getMonitorDisplayName = (monitorId: string) => {
    const cachedItem = deviceDisplayMap.value[monitorId];
    return cachedItem?.label || monitorId || '--';
  };

  const getShortDisplayName = (monitorId: string) => {
    const displayName = getMonitorDisplayName(monitorId);
    return displayName.length <= 10 ? displayName : `${displayName.slice(0, 9)}...`;
  };

  const buildSeriesTimeAxis = () => {
    return Array.from(new Set(rawRecords.value.map((item) => item.__timeKey).filter((item) => item)));
  };

  const getMetricValues = (metric: IotCurveMetricDefinition, monitorId = '') => {
    return rawRecords.value
      .filter((item) => !monitorId || String(item.monitorId || item.monitorCode || '') === monitorId)
      .map((item) => readMetricValue(item, metric))
      .filter((item): item is number => item !== null);
  };

  const getMetricStats = (metric: IotCurveMetricDefinition, monitorId = ''): IotReportMetricStats => {
    const values = getMetricValues(metric, monitorId);
    if (!values.length) {
      return {
        latest: null,
        avg: null,
        max: null,
        p75: null,
        p90: null
      };
    }
    const sortedValues = [...values].sort((left, right) => left - right);
    return {
      latest: values[values.length - 1],
      avg: average(values),
      max: sortedValues[sortedValues.length - 1],
      p75: percentile(sortedValues, 0.75),
      p90: percentile(sortedValues, 0.9)
    };
  };

  const metricCards = computed(() => {
    return metricConfigs.value.slice(0, 4).map((metric) => {
      const stats = getMetricStats(metric);
      return {
        ...metric,
        latest: stats.latest,
        avg: stats.avg,
        max: stats.max
      };
    });
  });

  const deviceStats = computed<IotReportDeviceStat[]>(() => {
    if (!primaryMetric.value) {
      return [];
    }
    const deviceMap = {} as Record<string, number[]>;
    rawRecords.value.forEach((item) => {
      const monitorId = String(item.monitorId || item.monitorCode || '');
      const metricValue = readMetricValue(item, primaryMetric.value as IotCurveMetricDefinition);
      if (!monitorId || metricValue === null) {
        return;
      }
      if (!deviceMap[monitorId]) {
        deviceMap[monitorId] = [];
      }
      deviceMap[monitorId].push(metricValue);
    });

    return Object.keys(deviceMap)
      .map((monitorId) => {
        const values = deviceMap[monitorId];
        const sortedValues = [...values].sort((left, right) => left - right);
        return {
          monitorId,
          monitorName: getMonitorDisplayName(monitorId),
          latest: values[values.length - 1],
          avg: average(values),
          max: sortedValues[sortedValues.length - 1],
          count: values.length
        };
      })
      .sort((left, right) => right.avg - left.avg);
  });

  const coverageRatio = computed(() => {
    if (!rawRecords.value.length || !metricConfigs.value.length) {
      return 0;
    }
    const totalPoints = rawRecords.value.length * metricConfigs.value.length;
    const validPoints = metricConfigs.value.reduce((sum, metric) => sum + getMetricValues(metric).length, 0);
    return totalPoints ? validPoints / totalPoints : 0;
  });

  const loadMonitorTree = async () => {
    treeLoading.value = true;
    try {
      // 这里不再硬编码能源类型编号，直接读取当前项目可用树结构，后续新增/删减类型不需要改页面。
      const response = await getMonitorInfoTree({});
      monitorTreeOptions.value = response.data || [];
      deviceDisplayMap.value = buildDeviceDisplayMap(monitorTreeOptions.value);
    } finally {
      treeLoading.value = false;
    }
  };

  const buildSelectionByMonitorIds = (monitorIds: string[]) => {
    const leafNodes = monitorIds.map((item) => leafNodeMap.value[item]).filter(Boolean);
    if (!leafNodes.length) {
      return {
        compareScope: 'all',
        monitorId: '',
        monitorIds: [],
        monitorName: '',
        selectionLabel: '当前分析范围',
        nodeId: ''
      } as IotReportSelection;
    }
    const compareScope = leafNodes.length > 1 ? 'group' : 'single';
    const selectionLabel = leafNodes.length > 1 ? `选中设备组(${leafNodes.length}台)` : String(leafNodes[0].label || '当前设备');
    return buildSelectionByLeafNodes(leafNodes, selectionLabel, compareScope);
  };

  const applySelection = (selection: IotReportSelection, shouldQuery = true) => {
    queryForm.compareScope = selection.compareScope;
    queryForm.monitorId = selection.monitorId;
    queryForm.monitorIds = selection.monitorIds;
    queryForm.monitorName = selection.monitorName;
    queryForm.selectionLabel = selection.selectionLabel;
    currentTreeNodeId.value = selection.nodeId;
    if (shouldQuery) {
      void handleQuery();
    }
  };

  const applySelectionByScopeKeys = (shouldQuery = true) => {
    const selectedRoots = cloneTreeByRootKeys(monitorTreeOptions.value, selectedScopeKeys.value);
    if (!selectedRoots.length) {
      return;
    }
    const leafNodes = getLeafNodes(selectedRoots);
    const selectionLabel =
      selectedRoots.length === 1 ? `${String(selectedRoots[0].label || '当前分组')}设备组` : `${selectedRoots.map((item) => item.label).join(' / ')}联合分析`;
    const compareScope = selectedRoots.length > 1 ? 'all' : '';
    applySelection(buildSelectionByLeafNodes(leafNodes, selectionLabel, compareScope), shouldQuery);
  };

  const initQueryFromRoute = () => {
    const { query } = route;
    const selectionCacheKey = String(query.selectionKey || 'recordIotenvInstantDashboardSelection');
    const selectionCacheText = window.sessionStorage.getItem(selectionCacheKey);
    let selectionCache = {} as Record<string, unknown>;
    try {
      selectionCache = selectionCacheText ? JSON.parse(selectionCacheText) : {};
    } catch (error) {
      selectionCache = {};
    }

    const monitorIds = String(query.monitorIds || '')
      .split(',')
      .map((item) => item.trim())
      .filter((item) => item);

    queryForm.compareScope = String(query.compareScope || (monitorIds.length > 1 ? 'group' : 'single'));
    queryForm.monitorId = String(query.monitorId || '');
    queryForm.monitorIds = monitorIds;
    queryForm.monitorName = String(query.monitorName || query.monitorId || '');
    queryForm.selectionLabel = String(query.selectionLabel || selectionCache.selectionLabel || query.monitorName || '当前分析范围');
    queryForm.samplingInterval = Number(query.samplingInterval || 5);
    queryForm.primaryMetricField = String(query.primaryMetricField || '');

    const beginRecordTime = String(query.beginRecordTime || '');
    const endRecordTime = String(query.endRecordTime || '');
    if (beginRecordTime && endRecordTime) {
      daterangeRecordTime.value = [beginRecordTime, endRecordTime];
    }
  };

  const applyInitialSelection = () => {
    if (!monitorTreeOptions.value.length) {
      return;
    }
    const routeIds = queryForm.monitorIds.length ? queryForm.monitorIds : queryForm.monitorId ? [queryForm.monitorId] : [];
    if (routeIds.length) {
      const selection = buildSelectionByMonitorIds(routeIds);
      if (selection.monitorIds.length) {
        selectedScopeKeys.value = Array.from(new Set(routeIds.map((item) => leafNodeMap.value[item]?.__rootKey).filter(Boolean) as string[]));
        applySelection(selection, false);
        return;
      }
    }
    selectedScopeKeys.value = [resolveNodeKey(monitorTreeOptions.value[0])];
    applySelectionByScopeKeys(false);
  };

  const buildRequestQuery = () => {
    const query: Record<string, unknown> = {
      samplingInterval: queryForm.samplingInterval,
      params: {
        beginRecordTime: daterangeRecordTime.value[0],
        endRecordTime: daterangeRecordTime.value[1]
      }
    };
    if (queryForm.monitorIds.length > 1) {
      query.monitorIds = queryForm.monitorIds;
    } else {
      query.monitorId = queryForm.monitorIds[0] || queryForm.monitorId;
    }
    return query;
  };

  const handleQuery = async () => {
    if (!deviceCount.value) {
      ElMessage.warning('当前没有可分析的设备范围');
      return;
    }
    if (!daterangeRecordTime.value || daterangeRecordTime.value.length !== 2) {
      ElMessage.warning('请选择完整的记录时间范围');
      return;
    }

    loading.value = true;
    reportReady.value = false;
    try {
      const { data = [] } = await getRecordIotenvInstantReportData(buildRequestQuery());
      rawRecords.value = (data as RecordIotenvInstantVO[]).map((item) => normalizeIotCurveRecord(item));
      if (metricConfigs.value.length && !metricConfigs.value.some((item) => item.key === queryForm.primaryMetricField)) {
        queryForm.primaryMetricField = metricConfigs.value[0].key;
      }
      reportReady.value = rawRecords.value.length > 0 && metricConfigs.value.length > 0;
    } catch (error) {
      ElMessage.error('报表加载失败，请稍后重试');
    } finally {
      loading.value = false;
    }
  };

  const handleScopeChange = (value: string[]) => {
    if (!value || !value.length) {
      nextTick(() => {
        selectedScopeKeys.value = availableScopeOptions.value.length ? [availableScopeOptions.value[0].key] : [];
      });
      ElMessage.warning('至少保留一个分组用于分析');
      return;
    }
    applySelectionByScopeKeys();
  };

  const handleTreeNodeClick = (data: Record<string, unknown>) => {
    if (!data) {
      return;
    }
    const rootKey = findRootKeyByNodeId(monitorTreeOptions.value, String(data.id || ''));
    if (rootKey) {
      selectedScopeKeys.value = [rootKey];
    }
    if (Array.isArray(data.children) && data.children.length > 0) {
      applySelection(buildSelectionByLeafNodes(getLeafNodes([data]), `${String(data.label || '当前节点')}设备组`, 'group'));
      return;
    }
    const monitorId = String(data.code || '');
    applySelection(buildSelectionByMonitorIds([monitorId]));
  };

  watch(
    metricConfigs,
    (value) => {
      if (!value.length) {
        queryForm.primaryMetricField = '';
        return;
      }
      if (!value.some((item) => item.key === queryForm.primaryMetricField)) {
        queryForm.primaryMetricField = value[0].key;
      }
    },
    {
      immediate: true
    }
  );

  const initialize = async () => {
    initQueryFromRoute();
    await loadMonitorTree();
    applyInitialSelection();
    await handleQuery();
  };

  return {
    availablePrimaryMetricOptions,
    availableScopeOptions,
    analysisObjectFoot,
    analysisObjectValue,
    buildSeriesTimeAxis,
    coverageRatio,
    currentTreeNodeId,
    daterangeRecordTime,
    deviceCount,
    deviceDisplayMap,
    deviceSelectionSummary,
    deviceStats,
    energySelectionSummary,
    filteredMonitorTreeOptions,
    formatPercent,
    formatValue,
    getBands,
    getMetricStats,
    getMetricValues,
    getMonitorDisplayName,
    getShortDisplayName,
    handleQuery,
    handleScopeChange,
    handleTreeNodeClick,
    hasMultiDevice,
    initialize,
    loading,
    metricCards,
    metricConfigs,
    metricDescription,
    monitorTreeOptions,
    monitorTypeLabel,
    primaryMetric,
    primaryMetricFoot,
    queryForm,
    rawRecords,
    reportReady,
    selectedScopeKeys,
    selectionSummary,
    treeLoading,
    availableMetricHints: metricHints
  };
};
