<script setup lang="ts">
import { computed, ref, watch } from 'vue';
import VChart from 'vue-echarts';
import dayjs from 'dayjs';
import { LineChart } from 'echarts/charts';
import {
  AxisPointerComponent,
  DatasetComponent,
  DataZoomComponent,
  GridComponent,
  LegendComponent,
  MarkLineComponent,
  TooltipComponent,
} from 'echarts/components';
import { use } from 'echarts/core';
import { CanvasRenderer } from 'echarts/renderers';

import SvgIcon from '@/components/SvgIcon.vue';
import { useRequest } from '@/hooks/request';
import { useViewVisible } from '@/hooks/view-visible';
import { t } from '@/i18n';
import { getDevWorkHistoryData } from '@/api';
import { getEChartsColors, timeSorter } from '@/utils';
import { TimeRangePreset } from '@/constants';

import type { Dayjs } from 'dayjs';
import type { LineSeriesOption } from 'echarts/charts';
import type {
  DatasetComponentOption,
  DataZoomComponentOption,
  GridComponentOption,
  LegendComponentOption,
  TooltipComponentOption,
} from 'echarts/components';
import type { ComposeOption } from 'echarts/core';
import type { DevWorkHistoryDataItem, OptionItem, RangeValue } from '@/types';

use([
  CanvasRenderer,
  AxisPointerComponent,
  MarkLineComponent,
  LegendComponent,
  TooltipComponent,
  DatasetComponent,
  GridComponent,
  LineChart,
  DataZoomComponent,
]);

type EChartsOption = ComposeOption<
  | LegendComponentOption
  | TooltipComponentOption
  | DatasetComponentOption
  | GridComponentOption
  | LineSeriesOption
  | DataZoomComponentOption
>;

interface Props {
  devId: number;
  paramCodes: string[];
}

const props = defineProps<Props>();

const { visible, showView, hideView } = useViewVisible();
const { isLoading, handleRequest } = useRequest();
const timeRange = ref<RangeValue>([dayjs().add(-1, 'd'), dayjs()]);
const currTimeRangePreset = ref<TimeRangePreset>(TimeRangePreset.recent1Day);

const timeRangePresets = computed<OptionItem<TimeRangePreset>[]>(() => {
  return [
    { value: TimeRangePreset.recent1Day, label: t('common.recent1Day') },
    { value: TimeRangePreset.recent7Day, label: t('common.recent7Day') },
    { value: TimeRangePreset.recent30Day, label: t('common.recent30Day') },
    { value: TimeRangePreset.custom, label: t('common.custom') },
  ];
});

const disabledDate = (current: Dayjs) => {
  return current && current > dayjs().endOf('day');
};

const setTimeRange = () => {
  switch (currTimeRangePreset.value) {
    case TimeRangePreset.recent1Day:
      timeRange.value = [dayjs().add(-1, 'd'), dayjs()];
      break;
    case TimeRangePreset.recent7Day:
      timeRange.value = [dayjs().add(-7, 'd'), dayjs()];
      break;
    case TimeRangePreset.recent30Day:
      timeRange.value = [dayjs().add(-30, 'd'), dayjs()];
      break;
  }
};

const handleRangePresetChange = () => {
  setTimeRange();

  if (currTimeRangePreset.value !== TimeRangePreset.custom) {
    getParamHistoryData();
  }
};

const handleTimeRangeChange = () => {
  currTimeRangePreset.value = TimeRangePreset.custom;
  getParamHistoryData();
};

watch(visible, () => {
  if (visible.value) {
    getParamHistoryData();
  }
});

const historyData = ref<DevWorkHistoryDataItem[]>([]);

const paramLabel = computed<string>(() => {
  if (historyData.value.length) {
    const { deviceParamName, unit } = historyData.value[0];
    const unitText = unit ? `(${unit})` : '';
    return deviceParamName + unitText;
  }

  return '';
});

const option = computed<EChartsOption>(() => {
  const unitText = historyData.value[0]?.unit ?? '';
  const source = convertToEChartsDataset();
  const series = source[0].slice(1).map((name) => ({
    type: 'line',
    seriesLayoutBy: 'column',
    name,
    showSymbol: false,
  })) as LineSeriesOption;

  return {
    color: getEChartsColors(1),
    legend: {
      show: false,
    },
    tooltip: {
      show: true,
      trigger: 'axis',
      formatter(params) {
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        const tempParms = params as any[];
        const time = dayjs(tempParms[0].axisValue).format('MM-DD HH:mm');

        let tableHtml = '<table class="echarts-tooltip-electricity">';
        tableHtml += `<tr><th>${time}</th></tr>`;

        tempParms.forEach((param) => {
          tableHtml += `<tr><td>${param.marker}${param.seriesName}</td><td>${param.value[1] ?? '-'}${unitText}</td></tr>`;
        });

        tableHtml += '</table>';
        return tableHtml;
      },
    },
    dataset: {
      source,
    },
    xAxis: {
      type: 'category',
      axisLine: {
        lineStyle: {
          type: 'dashed',
          color: '#EBEBEB',
        },
      },
      axisLabel: {
        color: '#999',
        fontSize: 10,
        formatter(value) {
          return dayjs(value).format('MM-DD HH:mm');
        },
      },
      axisTick: {
        show: false,
      },
    },
    yAxis: {
      axisLabel: {
        color: '#999',
        fontSize: 10,
      },
      splitLine: {
        lineStyle: {
          type: 'dashed',
          color: '#EBEBEB',
        },
      },
    },
    series,
    grid: {
      top: 10,
      right: 30,
      bottom: 90,
      left: 30,
      containLabel: true,
    },
    dataZoom: [
      {
        type: 'inside',
        start: 0,
        end: 100,
        bottom: 35,
        handleStyle: {
          label: { show: false },
        },
        showDetail: false,
      },
      {
        start: 0,
        end: 100,
        bottom: 35,
        handleStyle: {
          label: { show: false },
        },
        showDetail: false,
      },
    ],
  };
});

const getParamHistoryData = () => {
  handleRequest(async () => {
    const [startTime, endTime] = timeRange.value;
    const data = await getDevWorkHistoryData({
      deviceIds: [props.devId],
      deviceParamCode: props.paramCodes,
      startTime: startTime.format('YYYY-MM-DD 00:00:00'),
      endTime: endTime.format('YYYY-MM-DD 23:59:59'),
    });

    if (data.length) {
      historyData.value = data[0].hisVOS;
    } else {
      historyData.value = [];
    }
  });
};

type EChartsDatasetItemValue = string | number | null;

const convertToEChartsDataset = () => {
  const times: string[] = [];
  const dataMap: Record<string, { time: string; value: string | number }[]> = {};

  historyData.value.forEach((item) => {
    const paramName = item.deviceParamName;
    dataMap[paramName] = [];

    item.value.forEach((val) => {
      if (!times.includes(val.time)) {
        times.push(val.time);
      }

      dataMap[paramName].push({
        time: val.time,
        value: val.value,
      });
    });
  });

  const source: EChartsDatasetItemValue[][] = [['time', ...Object.keys(dataMap)]];
  times.sort(timeSorter);

  times.forEach((time) => {
    const row: EChartsDatasetItemValue[] = [time];

    Object.values(dataMap).forEach((values) => {
      const found = values.find((v) => v.time === time);
      row.push(found ? found.value : null);
    });

    source.push(row);
  });

  return source;
};

const handleClose = () => {
  historyData.value = [];
  currTimeRangePreset.value = TimeRangePreset.recent1Day;
  setTimeRange();
};

defineExpose({
  showView,
  hideView,
});
</script>

<template>
  <AModal
    v-model:open="visible"
    wrap-class-name="dev-work-param-data-modal"
    :title="$t('deviceWorkStatus.viewData')"
    :width="920"
    :z-index="1001"
    centered
    :footer="null"
    :after-close="handleClose"
  >
    <ASpin class="center-loading" :spinning="isLoading" />
    <div class="param-data-select">
      <span class="param-data-label">{{ $t('common.selectTime') }}</span>
      <ASelect v-model:value="currTimeRangePreset" class="param-preset-picker" @change="handleRangePresetChange">
        <ASelectOption v-for="item in timeRangePresets" :key="item.value" :value="item.value">
          {{ item.label }}
        </ASelectOption>
      </ASelect>
      <ARangePicker
        class="param-date-picker"
        v-model:value="timeRange"
        :allow-clear="false"
        :separator="$t('common.to')"
        :disabled-date="disabledDate"
        @change="handleTimeRangeChange"
      >
        <template #suffixIcon>
          <SvgIcon name="calendar" color="#333" />
        </template>
      </ARangePicker>
    </div>
    <div class="param-name-unit">{{ paramLabel }}</div>
    <VChart class="param-data-chart" :option="option" />
  </AModal>
</template>

<style lang="scss">
.dev-work-param-data-modal {
  .ant-modal,
  .ant-modal > div,
  .ant-modal-content {
    height: 498px;
  }

  .ant-modal-content {
    display: flex;
    flex-direction: column;
    overflow: hidden;
  }

  .ant-modal-body {
    display: flex;
    flex-direction: column;
    height: calc(100% - 32px);
  }
}
</style>

<style lang="scss" scoped>
.param-data-select {
  margin-bottom: 16px;
}

.param-data-label {
  font-size: 14px;
  line-height: 24px;
  color: #333;
}

.param-preset-picker {
  width: 110px;
  margin-inline: 12px;
}

.param-date-picker {
  width: 256px;

  :deep(.ant-picker-range-separator) {
    padding-right: 16px;
  }
}

.param-name-unit {
  height: 17px;
  margin-left: 24px;
  font-size: 12px;
  line-height: 17px;
  color: #999;
}

.param-data-chart {
  height: 100%;
}
</style>
